tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

snapshots.js (13922B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 "use strict";
      5 
      6 const {
      7  immutableUpdate,
      8  assert,
      9 } = require("resource://devtools/shared/DevToolsUtils.js");
     10 const {
     11  actions,
     12  snapshotState: states,
     13  censusState,
     14  treeMapState,
     15  dominatorTreeState,
     16  viewState,
     17 } = require("resource://devtools/client/memory/constants.js");
     18 const DominatorTreeNode = require("resource://devtools/shared/heapsnapshot/DominatorTreeNode.js");
     19 
     20 const handlers = Object.create(null);
     21 
     22 handlers[actions.SNAPSHOT_ERROR] = function (snapshots, { id, error }) {
     23  return snapshots.map(snapshot => {
     24    return snapshot.id === id
     25      ? immutableUpdate(snapshot, { state: states.ERROR, error })
     26      : snapshot;
     27  });
     28 };
     29 
     30 handlers[actions.TAKE_SNAPSHOT_START] = function (snapshots, { snapshot }) {
     31  return [...snapshots, snapshot];
     32 };
     33 
     34 handlers[actions.TAKE_SNAPSHOT_END] = function (snapshots, { id, path }) {
     35  return snapshots.map(snapshot => {
     36    return snapshot.id === id
     37      ? immutableUpdate(snapshot, { state: states.SAVED, path })
     38      : snapshot;
     39  });
     40 };
     41 
     42 handlers[actions.IMPORT_SNAPSHOT_START] = handlers[actions.TAKE_SNAPSHOT_START];
     43 
     44 handlers[actions.READ_SNAPSHOT_START] = function (snapshots, { id }) {
     45  return snapshots.map(snapshot => {
     46    return snapshot.id === id
     47      ? immutableUpdate(snapshot, { state: states.READING })
     48      : snapshot;
     49  });
     50 };
     51 
     52 handlers[actions.READ_SNAPSHOT_END] = function (
     53  snapshots,
     54  { id, creationTime }
     55 ) {
     56  return snapshots.map(snapshot => {
     57    return snapshot.id === id
     58      ? immutableUpdate(snapshot, { state: states.READ, creationTime })
     59      : snapshot;
     60  });
     61 };
     62 
     63 handlers[actions.TAKE_CENSUS_START] = function (
     64  snapshots,
     65  { id, display, filter }
     66 ) {
     67  const census = {
     68    report: null,
     69    display,
     70    filter,
     71    state: censusState.SAVING,
     72  };
     73 
     74  return snapshots.map(snapshot => {
     75    return snapshot.id === id
     76      ? immutableUpdate(snapshot, { census })
     77      : snapshot;
     78  });
     79 };
     80 
     81 handlers[actions.TAKE_CENSUS_END] = function (
     82  snapshots,
     83  { id, report, parentMap, display, filter }
     84 ) {
     85  const census = {
     86    report,
     87    parentMap,
     88    expanded: new Set(),
     89    display,
     90    filter,
     91    state: censusState.SAVED,
     92  };
     93 
     94  return snapshots.map(snapshot => {
     95    return snapshot.id === id
     96      ? immutableUpdate(snapshot, { census })
     97      : snapshot;
     98  });
     99 };
    100 
    101 handlers[actions.TAKE_CENSUS_ERROR] = function (snapshots, { id, error }) {
    102  assert(error, "actions with TAKE_CENSUS_ERROR should have an error");
    103 
    104  return snapshots.map(snapshot => {
    105    if (snapshot.id !== id) {
    106      return snapshot;
    107    }
    108 
    109    const census = Object.freeze({
    110      state: censusState.ERROR,
    111      error,
    112    });
    113 
    114    return immutableUpdate(snapshot, { census });
    115  });
    116 };
    117 
    118 handlers[actions.TAKE_TREE_MAP_START] = function (snapshots, { id, display }) {
    119  const treeMap = {
    120    report: null,
    121    display,
    122    state: treeMapState.SAVING,
    123  };
    124 
    125  return snapshots.map(snapshot => {
    126    return snapshot.id === id
    127      ? immutableUpdate(snapshot, { treeMap })
    128      : snapshot;
    129  });
    130 };
    131 
    132 handlers[actions.TAKE_TREE_MAP_END] = function (snapshots, action) {
    133  const { id, report, display } = action;
    134  const treeMap = {
    135    report,
    136    display,
    137    state: treeMapState.SAVED,
    138  };
    139 
    140  return snapshots.map(snapshot => {
    141    return snapshot.id === id
    142      ? immutableUpdate(snapshot, { treeMap })
    143      : snapshot;
    144  });
    145 };
    146 
    147 handlers[actions.TAKE_TREE_MAP_ERROR] = function (snapshots, { id, error }) {
    148  assert(error, "actions with TAKE_TREE_MAP_ERROR should have an error");
    149 
    150  return snapshots.map(snapshot => {
    151    if (snapshot.id !== id) {
    152      return snapshot;
    153    }
    154 
    155    const treeMap = Object.freeze({
    156      state: treeMapState.ERROR,
    157      error,
    158    });
    159 
    160    return immutableUpdate(snapshot, { treeMap });
    161  });
    162 };
    163 
    164 handlers[actions.EXPAND_CENSUS_NODE] = function (snapshots, { id, node }) {
    165  return snapshots.map(snapshot => {
    166    if (snapshot.id !== id) {
    167      return snapshot;
    168    }
    169 
    170    assert(snapshot.census, "Should have a census");
    171    assert(snapshot.census.report, "Should have a census report");
    172    assert(snapshot.census.expanded, "Should have a census's expanded set");
    173 
    174    const expanded = new Set(snapshot.census.expanded);
    175    expanded.add(node.id);
    176    const census = immutableUpdate(snapshot.census, { expanded });
    177    return immutableUpdate(snapshot, { census });
    178  });
    179 };
    180 
    181 handlers[actions.COLLAPSE_CENSUS_NODE] = function (snapshots, { id, node }) {
    182  return snapshots.map(snapshot => {
    183    if (snapshot.id !== id) {
    184      return snapshot;
    185    }
    186 
    187    assert(snapshot.census, "Should have a census");
    188    assert(snapshot.census.report, "Should have a census report");
    189    assert(snapshot.census.expanded, "Should have a census's expanded set");
    190 
    191    const expanded = new Set(snapshot.census.expanded);
    192    expanded.delete(node.id);
    193    const census = immutableUpdate(snapshot.census, { expanded });
    194    return immutableUpdate(snapshot, { census });
    195  });
    196 };
    197 
    198 handlers[actions.FOCUS_CENSUS_NODE] = function (snapshots, { id, node }) {
    199  return snapshots.map(snapshot => {
    200    if (snapshot.id !== id) {
    201      return snapshot;
    202    }
    203 
    204    assert(snapshot.census, "Should have a census");
    205    const census = immutableUpdate(snapshot.census, { focused: node });
    206    return immutableUpdate(snapshot, { census });
    207  });
    208 };
    209 
    210 handlers[actions.SELECT_SNAPSHOT] = function (snapshots, { id }) {
    211  return snapshots.map(s => immutableUpdate(s, { selected: s.id === id }));
    212 };
    213 
    214 handlers[actions.DELETE_SNAPSHOTS_START] = function (snapshots, { ids }) {
    215  return snapshots.filter(s => !ids.includes(s.id));
    216 };
    217 
    218 handlers[actions.DELETE_SNAPSHOTS_END] = function (snapshots) {
    219  return snapshots;
    220 };
    221 
    222 handlers[actions.CHANGE_VIEW] = function (snapshots, { newViewState }) {
    223  return newViewState === viewState.DIFFING
    224    ? snapshots.map(s => immutableUpdate(s, { selected: false }))
    225    : snapshots;
    226 };
    227 
    228 handlers[actions.POP_VIEW] = function (snapshots, { previousView }) {
    229  return snapshots.map(s =>
    230    immutableUpdate(s, {
    231      selected: s.id === previousView.selected,
    232    })
    233  );
    234 };
    235 
    236 handlers[actions.COMPUTE_DOMINATOR_TREE_START] = function (snapshots, { id }) {
    237  const dominatorTree = Object.freeze({
    238    state: dominatorTreeState.COMPUTING,
    239    dominatorTreeId: undefined,
    240    root: undefined,
    241  });
    242 
    243  return snapshots.map(snapshot => {
    244    if (snapshot.id !== id) {
    245      return snapshot;
    246    }
    247 
    248    assert(!snapshot.dominatorTree, "Should not have a dominator tree model");
    249    return immutableUpdate(snapshot, { dominatorTree });
    250  });
    251 };
    252 
    253 handlers[actions.COMPUTE_DOMINATOR_TREE_END] = function (
    254  snapshots,
    255  { id, dominatorTreeId }
    256 ) {
    257  return snapshots.map(snapshot => {
    258    if (snapshot.id !== id) {
    259      return snapshot;
    260    }
    261 
    262    assert(snapshot.dominatorTree, "Should have a dominator tree model");
    263    assert(
    264      snapshot.dominatorTree.state == dominatorTreeState.COMPUTING,
    265      "Should be in the COMPUTING state"
    266    );
    267 
    268    const dominatorTree = immutableUpdate(snapshot.dominatorTree, {
    269      state: dominatorTreeState.COMPUTED,
    270      dominatorTreeId,
    271    });
    272    return immutableUpdate(snapshot, { dominatorTree });
    273  });
    274 };
    275 
    276 handlers[actions.FETCH_DOMINATOR_TREE_START] = function (
    277  snapshots,
    278  { id, display }
    279 ) {
    280  return snapshots.map(snapshot => {
    281    if (snapshot.id !== id) {
    282      return snapshot;
    283    }
    284 
    285    assert(snapshot.dominatorTree, "Should have a dominator tree model");
    286    assert(
    287      snapshot.dominatorTree.state !== dominatorTreeState.COMPUTING &&
    288        snapshot.dominatorTree.state !== dominatorTreeState.ERROR,
    289      "Should have already computed the dominator tree, found state = " +
    290        snapshot.dominatorTree.state
    291    );
    292 
    293    const dominatorTree = immutableUpdate(snapshot.dominatorTree, {
    294      state: dominatorTreeState.FETCHING,
    295      root: undefined,
    296      display,
    297    });
    298    return immutableUpdate(snapshot, { dominatorTree });
    299  });
    300 };
    301 
    302 handlers[actions.FETCH_DOMINATOR_TREE_END] = function (
    303  snapshots,
    304  { id, root }
    305 ) {
    306  return snapshots.map(snapshot => {
    307    if (snapshot.id !== id) {
    308      return snapshot;
    309    }
    310 
    311    assert(snapshot.dominatorTree, "Should have a dominator tree model");
    312    assert(
    313      snapshot.dominatorTree.state == dominatorTreeState.FETCHING,
    314      "Should be in the FETCHING state"
    315    );
    316 
    317    let focused;
    318    if (snapshot.dominatorTree.focused) {
    319      focused = (function findFocused(node) {
    320        if (node.nodeId === snapshot.dominatorTree.focused.nodeId) {
    321          return node;
    322        }
    323 
    324        if (node.children) {
    325          const length = node.children.length;
    326          for (let i = 0; i < length; i++) {
    327            const result = findFocused(node.children[i]);
    328            if (result) {
    329              return result;
    330            }
    331          }
    332        }
    333 
    334        return undefined;
    335      })(root);
    336    }
    337 
    338    const dominatorTree = immutableUpdate(snapshot.dominatorTree, {
    339      state: dominatorTreeState.LOADED,
    340      root,
    341      expanded: new Set(),
    342      focused,
    343    });
    344 
    345    return immutableUpdate(snapshot, { dominatorTree });
    346  });
    347 };
    348 
    349 handlers[actions.EXPAND_DOMINATOR_TREE_NODE] = function (
    350  snapshots,
    351  { id, node }
    352 ) {
    353  return snapshots.map(snapshot => {
    354    if (snapshot.id !== id) {
    355      return snapshot;
    356    }
    357 
    358    assert(snapshot.dominatorTree, "Should have a dominator tree");
    359    assert(
    360      snapshot.dominatorTree.expanded,
    361      "Should have the dominator tree's expanded set"
    362    );
    363 
    364    const expanded = new Set(snapshot.dominatorTree.expanded);
    365    expanded.add(node.nodeId);
    366    const dominatorTree = immutableUpdate(snapshot.dominatorTree, { expanded });
    367    return immutableUpdate(snapshot, { dominatorTree });
    368  });
    369 };
    370 
    371 handlers[actions.COLLAPSE_DOMINATOR_TREE_NODE] = function (
    372  snapshots,
    373  { id, node }
    374 ) {
    375  return snapshots.map(snapshot => {
    376    if (snapshot.id !== id) {
    377      return snapshot;
    378    }
    379 
    380    assert(snapshot.dominatorTree, "Should have a dominator tree");
    381    assert(
    382      snapshot.dominatorTree.expanded,
    383      "Should have the dominator tree's expanded set"
    384    );
    385 
    386    const expanded = new Set(snapshot.dominatorTree.expanded);
    387    expanded.delete(node.nodeId);
    388    const dominatorTree = immutableUpdate(snapshot.dominatorTree, { expanded });
    389    return immutableUpdate(snapshot, { dominatorTree });
    390  });
    391 };
    392 
    393 handlers[actions.FOCUS_DOMINATOR_TREE_NODE] = function (
    394  snapshots,
    395  { id, node }
    396 ) {
    397  return snapshots.map(snapshot => {
    398    if (snapshot.id !== id) {
    399      return snapshot;
    400    }
    401 
    402    assert(snapshot.dominatorTree, "Should have a dominator tree");
    403    const dominatorTree = immutableUpdate(snapshot.dominatorTree, {
    404      focused: node,
    405    });
    406    return immutableUpdate(snapshot, { dominatorTree });
    407  });
    408 };
    409 
    410 handlers[actions.FETCH_IMMEDIATELY_DOMINATED_START] = function (
    411  snapshots,
    412  { id }
    413 ) {
    414  return snapshots.map(snapshot => {
    415    if (snapshot.id !== id) {
    416      return snapshot;
    417    }
    418 
    419    assert(snapshot.dominatorTree, "Should have a dominator tree model");
    420    assert(
    421      snapshot.dominatorTree.state == dominatorTreeState.INCREMENTAL_FETCHING ||
    422        snapshot.dominatorTree.state == dominatorTreeState.LOADED,
    423      "The dominator tree should be loaded if we are going to " +
    424        "incrementally fetch children."
    425    );
    426 
    427    const activeFetchRequestCount = snapshot.dominatorTree
    428      .activeFetchRequestCount
    429      ? snapshot.dominatorTree.activeFetchRequestCount + 1
    430      : 1;
    431 
    432    const dominatorTree = immutableUpdate(snapshot.dominatorTree, {
    433      state: dominatorTreeState.INCREMENTAL_FETCHING,
    434      activeFetchRequestCount,
    435    });
    436 
    437    return immutableUpdate(snapshot, { dominatorTree });
    438  });
    439 };
    440 
    441 handlers[actions.FETCH_IMMEDIATELY_DOMINATED_END] = function (
    442  snapshots,
    443  { id, path, nodes, moreChildrenAvailable }
    444 ) {
    445  return snapshots.map(snapshot => {
    446    if (snapshot.id !== id) {
    447      return snapshot;
    448    }
    449 
    450    assert(snapshot.dominatorTree, "Should have a dominator tree model");
    451    assert(
    452      snapshot.dominatorTree.root,
    453      "Should have a dominator tree model root"
    454    );
    455    assert(
    456      snapshot.dominatorTree.state === dominatorTreeState.INCREMENTAL_FETCHING,
    457      "The dominator tree state should be INCREMENTAL_FETCHING"
    458    );
    459 
    460    const root = DominatorTreeNode.insert(
    461      snapshot.dominatorTree.root,
    462      path,
    463      nodes,
    464      moreChildrenAvailable
    465    );
    466 
    467    const focused = snapshot.dominatorTree.focused
    468      ? DominatorTreeNode.getNodeByIdAlongPath(
    469          snapshot.dominatorTree.focused.nodeId,
    470          root,
    471          path
    472        )
    473      : undefined;
    474 
    475    const activeFetchRequestCount =
    476      snapshot.dominatorTree.activeFetchRequestCount === 1
    477        ? undefined
    478        : snapshot.dominatorTree.activeFetchRequestCount - 1;
    479 
    480    // If there are still outstanding requests, we need to stay in the
    481    // INCREMENTAL_FETCHING state until they complete.
    482    const state = activeFetchRequestCount
    483      ? dominatorTreeState.INCREMENTAL_FETCHING
    484      : dominatorTreeState.LOADED;
    485 
    486    const dominatorTree = immutableUpdate(snapshot.dominatorTree, {
    487      state,
    488      root,
    489      focused,
    490      activeFetchRequestCount,
    491    });
    492 
    493    return immutableUpdate(snapshot, { dominatorTree });
    494  });
    495 };
    496 
    497 handlers[actions.DOMINATOR_TREE_ERROR] = function (snapshots, { id, error }) {
    498  assert(error, "actions with DOMINATOR_TREE_ERROR should have an error");
    499 
    500  return snapshots.map(snapshot => {
    501    if (snapshot.id !== id) {
    502      return snapshot;
    503    }
    504 
    505    const dominatorTree = Object.freeze({
    506      state: dominatorTreeState.ERROR,
    507      error,
    508    });
    509 
    510    return immutableUpdate(snapshot, { dominatorTree });
    511  });
    512 };
    513 
    514 module.exports = function (snapshots = [], action) {
    515  const handler = handlers[action.type];
    516  if (handler) {
    517    return handler(snapshots, action);
    518  }
    519  return snapshots;
    520 };