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();