tor-browser

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

weak-marking-01.js (5903B)


      1 // These tests will be using object literals as keys, and we want some of them
      2 // to be dead after being inserted into a WeakMap. That means we must wrap
      3 // everything in functions because it seems like the toplevel script hangs onto
      4 // its object literals.
      5 
      6 gczeal(0);
      7 gcparam('minNurseryBytes', 1024 * 1024);
      8 gcparam('maxNurseryBytes', 1024 * 1024);
      9 
     10 function startIncrementalGC() {
     11  startgc(1, 'shrinking');
     12  while (gcstate() === "Prepare") {
     13    gcslice(1);
     14  }
     15 }
     16 
     17 function syncIncrementalGC() {
     18  startIncrementalGC();
     19  finishgc();
     20 }
     21 
     22 // All reachable keys should be found, and the rest should be swept.
     23 function basicSweeping() {
     24  gc();
     25 
     26  var wm1 = new WeakMap();
     27  wm1.set({'name': 'obj1'}, {'name': 'val1'});
     28  var hold = {'name': 'obj2'};
     29  wm1.set(hold, {'name': 'val2'});
     30  wm1.set({'name': 'obj3'}, {'name': 'val3'});
     31 
     32  syncIncrementalGC();
     33 
     34  assertEq(wm1.get(hold).name, 'val2');
     35  assertEq(nondeterministicGetWeakMapKeys(wm1).length, 1);
     36 }
     37 
     38 basicSweeping();
     39 
     40 // Keep values alive even when they are only referenced by (live) WeakMap values.
     41 function weakGraph() {
     42  gc();
     43 
     44  var wm1 = new WeakMap();
     45  var obj1 = {'name': 'obj1'};
     46  var obj2 = {'name': 'obj2'};
     47  var obj3 = {'name': 'obj3'};
     48  var obj4 = {'name': 'obj4'};
     49  var clear = {'name': ''}; // Make the interpreter forget about the last obj created
     50 
     51  wm1.set(obj2, obj3);
     52  wm1.set(obj3, obj1);
     53  wm1.set(obj4, obj1); // This edge will be cleared
     54  obj1 = obj3 = obj4 = undefined;
     55 
     56  syncIncrementalGC();
     57 
     58  assertEq(obj2.name, "obj2");
     59  assertEq(wm1.get(obj2).name, "obj3");
     60  assertEq(wm1.get(wm1.get(obj2)).name, "obj1");
     61  print(nondeterministicGetWeakMapKeys(wm1).map(o => o.name).join(","));
     62  assertEq(nondeterministicGetWeakMapKeys(wm1).length, 2);
     63 }
     64 
     65 weakGraph();
     66 
     67 // ...but the weakmap itself has to stay alive, too.
     68 function deadWeakMap() {
     69  gc();
     70 
     71  var wm1 = new WeakMap();
     72  var obj1 = makeFinalizeObserver();
     73  var obj2 = {'name': 'obj2'};
     74  var obj3 = {'name': 'obj3'};
     75  var obj4 = {'name': 'obj4'};
     76  var clear = {'name': ''}; // Make the interpreter forget about the last obj created
     77 
     78  wm1.set(obj2, obj3);
     79  wm1.set(obj3, obj1);
     80  wm1.set(obj4, obj1); // This edge will be cleared
     81  var initialCount = finalizeCount();
     82  obj1 = obj3 = obj4 = undefined;
     83  wm1 = undefined;
     84 
     85  syncIncrementalGC();
     86 
     87  assertEq(obj2.name, "obj2");
     88  assertEq(finalizeCount(), initialCount + 1);
     89 }
     90 
     91 deadWeakMap();
     92 
     93 // WeakMaps do not strongly reference their keys or values. (WeakMaps hold a
     94 // collection of (strong) references to *edges* from keys to values. If the
     95 // WeakMap is not live, then its edges are of course not live either. An edge
     96 // holds neither its key nor its value live; it just holds a strong ref from
     97 // the key to the value. So if the key is live, the value is live too, but the
     98 // edge itself has no references to anything.)
     99 function deadKeys() {
    100  gc();
    101 
    102  var wm1 = new WeakMap();
    103  var obj1 = makeFinalizeObserver();
    104  var obj2 = {'name': 'obj2'};
    105  var obj3 = makeFinalizeObserver();
    106  var clear = {}; // Make the interpreter forget about the last obj created
    107 
    108  wm1.set(obj1, obj1);
    109  wm1.set(obj3, obj2);
    110  obj1 = obj3 = undefined;
    111  var initialCount = finalizeCount();
    112 
    113  syncIncrementalGC();
    114 
    115  assertEq(finalizeCount(), initialCount + 2);
    116  assertEq(nondeterministicGetWeakMapKeys(wm1).length, 0);
    117 }
    118 
    119 deadKeys();
    120 
    121 // The weakKeys table has to grow if it encounters enough new unmarked weakmap
    122 // keys. Trigger this to happen during weakmap marking.
    123 //
    124 // There's some trickiness involved in getting it to test the right thing,
    125 // because if a key is marked before the weakmap, then it won't get entered
    126 // into the weakKeys table. This chains through multiple weakmap layers to
    127 // ensure that the objects can't get marked before the weakmaps.
    128 function weakKeysRealloc() {
    129  gc();
    130 
    131  var wm1 = new WeakMap;
    132  var wm2 = new WeakMap;
    133  var wm3 = new WeakMap;
    134  var obj1 = {'name': 'obj1'};
    135  var obj2 = {'name': 'obj2'};
    136  wm1.set(obj1, wm2);
    137  wm2.set(obj2, wm3);
    138  for (var i = 0; i < 10000; i++) {
    139    wm3.set(Object.create(null), wm2);
    140  }
    141  wm3.set(Object.create(null), makeFinalizeObserver());
    142 
    143  wm2 = undefined;
    144  wm3 = undefined;
    145  obj2 = undefined;
    146 
    147  var initialCount = finalizeCount();
    148  syncIncrementalGC();
    149  assertEq(finalizeCount(), initialCount + 1);
    150 }
    151 
    152 weakKeysRealloc();
    153 
    154 // The weakKeys table is populated during regular marking. When a key is later
    155 // deleted, both it and its delegate should be removed from weakKeys.
    156 // Otherwise, it will hold its value live if it gets marked, and our table
    157 // traversals will include non-keys, etc.
    158 function deletedKeys() {
    159  gc();
    160 
    161  var wm = new WeakMap;
    162  var g = newGlobal();
    163 
    164  for (var i = 0; i < 1000; i++)
    165    wm.set(g.Object.create(null), i);
    166 
    167  startIncrementalGC();
    168 
    169  for (var key of nondeterministicGetWeakMapKeys(wm)) {
    170    if (wm.get(key) % 2)
    171      wm.delete(key);
    172  }
    173 
    174  gc();
    175 }
    176 
    177 deletedKeys();
    178 
    179 // Test adding keys during incremental GC.
    180 function incrementalAdds() {
    181  gc();
    182 
    183  var initialCount = finalizeCount();
    184 
    185  var wm1 = new WeakMap;
    186  var wm2 = new WeakMap;
    187  var wm3 = new WeakMap;
    188  var obj1 = {'name': 'obj1'};
    189  var obj2 = {'name': 'obj2'};
    190  wm1.set(obj1, wm2);
    191  wm2.set(obj2, wm3);
    192  for (var i = 0; i < 10000; i++) {
    193    wm3.set(Object.create(null), wm2);
    194  }
    195  wm3.set(Object.create(null), makeFinalizeObserver());
    196  obj2 = undefined;
    197 
    198  var obj3 = [];
    199  startIncrementalGC();
    200  var M = 10;
    201  var N = 800;
    202  for (var j = 0; j < M; j++) {
    203    for (var i = 0; i < N; i++)
    204      wm3.set(Object.create(null), makeFinalizeObserver()); // Should be swept
    205    for (var i = 0; i < N; i++) {
    206      obj3.push({'name': 'obj3'});
    207      wm1.set(obj3[obj3.length - 1], makeFinalizeObserver()); // Should not be swept
    208    }
    209    gcslice();
    210  }
    211 
    212  wm2 = undefined;
    213  wm3 = undefined;
    214 
    215  gc();
    216  print("initialCount = " + initialCount);
    217  assertEq(finalizeCount(), initialCount + 1 + M * N);
    218 }
    219 
    220 incrementalAdds();