tor-browser

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

compartment-revived-gc.js (3932B)


      1 // Test 'compartment revived' GCs, where we do an extra GC if there are
      2 // compartments which we expected to die but were kept alive.
      3 
      4 // A global used as the destination for transplants.
      5 let transplantTargetGlobal = newGlobal();
      6 
      7 function didCompartmentRevivedGC() {
      8  return performance.mozMemory.gc.lastStartReason === "COMPARTMENT_REVIVED";
      9 }
     10 
     11 function compartmentCount() {
     12  let r = performance.mozMemory.gc.compartmentCount;
     13  return r;
     14 }
     15 
     16 function startIncrementalGC() {
     17  startgc(1);
     18  while (gcstate() === "Prepare" || gcstate() == "MarkRoots") {
     19    gcslice(100, {dontStart: true});
     20  }
     21  assertEq(gcstate(), "Mark");
     22 }
     23 
     24 function finishIncrementalGC() {
     25  while (gcstate() !== "NotActive") {
     26    gcslice(100, {dontStart: true});
     27  }
     28  assertEq(gcstate(), "NotActive");
     29 }
     30 
     31 // Create a new compartment and global and return the global.
     32 function createCompartment() {
     33  return newGlobal({newCompartment: true});
     34 }
     35 
     36 // Create a transplantable object and create a wrapper to it from a new
     37 // compartment. Return a function to transplant the target object.
     38 function createTransplantableWrapperTarget(wrapperGlobal) {
     39  let {object: target, transplant} = transplantableObject();
     40  wrapperGlobal.wrapper = target;
     41  return transplant;
     42 }
     43 
     44 // Transplant an object to a new global by calling the transplant
     45 // function. This remaps all wrappers pointing to the target object,
     46 // potentially keeping dead compartments alive.
     47 function transplantTargetAndRemapWrappers(transplant) {
     48  transplant(transplantTargetGlobal);
     49 }
     50 
     51 // Test no compartment revived GC triggered in normal cases.
     52 function testNormal() {
     53  gc();
     54  assertEq(didCompartmentRevivedGC(), false);
     55 
     56  startIncrementalGC();
     57  finishIncrementalGC();
     58  assertEq(didCompartmentRevivedGC(), false);
     59 
     60  let initialCount = compartmentCount();
     61  createCompartment();
     62  startIncrementalGC();
     63  finishIncrementalGC();
     64  assertEq(compartmentCount(), initialCount);
     65 }
     66 
     67 // Test compartment revived GC is triggered by wrapper remapping.
     68 function testCompartmentRevived1() {
     69  let initialCount = compartmentCount();
     70  let compartment = createCompartment();
     71  let transplant = createTransplantableWrapperTarget(compartment);
     72  compartment = null;
     73 
     74  startIncrementalGC();
     75  transplantTargetAndRemapWrappers(transplant);
     76  finishIncrementalGC();
     77 
     78  assertEq(didCompartmentRevivedGC(), true);
     79  assertEq(compartmentCount(), initialCount);
     80 }
     81 
     82 // Test no compartment revived GC is triggered for compartments transitively
     83 // kept alive by black roots.
     84 function testCompartmentRevived2() {
     85  let initialCount = compartmentCount();
     86  let compartment = createCompartment();
     87  let transplant = createTransplantableWrapperTarget(compartment);
     88  let liveCompartment = createCompartment();
     89  liveCompartment.wrapper = compartment;
     90  compartment = null;
     91 
     92  startIncrementalGC();
     93  transplantTargetAndRemapWrappers(transplant);
     94  finishIncrementalGC();
     95 
     96  assertEq(didCompartmentRevivedGC(), false);
     97  assertEq(compartmentCount(), initialCount + 2);
     98 
     99  liveCompartment = null;
    100  gc();
    101 
    102  assertEq(compartmentCount(), initialCount);
    103 }
    104 
    105 // Test no compartment revived GC is triggered for compartments transitively
    106 // kept alive by gray roots.
    107 function testCompartmentRevived3() {
    108  let initialCount = compartmentCount();
    109  let compartment = createCompartment();
    110  let transplant = createTransplantableWrapperTarget(compartment);
    111  let liveCompartment = createCompartment();
    112  liveCompartment.wrapper = compartment;
    113  liveCompartment.eval('grayRoot()[0] = this');
    114  liveCompartment = null;
    115  gc();
    116 
    117  startIncrementalGC();
    118  transplantTargetAndRemapWrappers(transplant);
    119  finishIncrementalGC();
    120 
    121  assertEq(didCompartmentRevivedGC(), false);
    122  assertEq(compartmentCount(), initialCount + 2);
    123 
    124  // There's no easy way to clear gray roots for a compartment we don't have
    125  // any reference to.
    126 }
    127 
    128 gczeal(0);
    129 
    130 testNormal();
    131 testCompartmentRevived1();
    132 testCompartmentRevived2();
    133 testCompartmentRevived3();