collect-gray.js (5755B)
1 // |reftest| skip-if(!xulRuntime.shell) 2 // Any copyright is dedicated to the Public Domain. 3 // http://creativecommons.org/licenses/publicdomain/ 4 5 //----------------------------------------------------------------------------- 6 var BUGNUMBER = 1337209; 7 var summary = 8 "Test gray marking"; 9 10 print(BUGNUMBER + ": " + summary); 11 12 if (typeof gczeal !== 'undefined') 13 gczeal(0); 14 15 function test() { 16 grayRoot().x = Object.create(null); 17 addMarkObservers([grayRoot(), grayRoot().x, this, Object.create(null)]); 18 gc(); 19 let marks = getMarks(); 20 assertEq(marks[0], 'gray', 'gray root'); 21 assertEq(marks[1], 'gray', 'object reachable from gray root'); 22 assertEq(marks[2], 'black', 'global'); 23 assertEq(marks[3], 'dead', 'dead object should have been collected'); 24 25 grayRoot().x = 7; // Overwrite the object 26 gc(); 27 marks = getMarks(); 28 assertEq(marks[0], 'gray', 'gray root'); 29 assertEq(marks[1], 'dead', 'object no longer reachable from gray root'); 30 assertEq(marks[2], 'black', 'global'); 31 assertEq(marks[3], 'dead', 'dead object should have been collected'); 32 33 var wm = new WeakMap(); 34 var global = newGlobal({newCompartment: true}); 35 36 var wrapper1 = global.eval("Object.create(null)"); 37 wrapper1.name = "wrapper1"; 38 var value1 = Object.create(null); 39 wm.set(wrapper1, value1); 40 41 var wrapper2 = global.eval("Object.create(null)"); 42 wrapper2.name = "wrapper2"; 43 var value2 = global.eval("Object.create(null)"); 44 wm.set(wrapper2, value2); 45 46 grayRoot().root1 = wrapper1; 47 grayRoot().root2 = wrapper2; 48 clearMarkObservers(); 49 addMarkObservers([wrapper1, value1, wrapper2, value2]); 50 wrapper1 = wrapper2 = null; 51 value1 = value2 = null; 52 gc(); 53 marks = getMarks(); 54 assertEq(marks[0], 'gray', 'gray key 1'); 55 assertEq(marks[1], 'gray', 'black map, gray key => gray value'); 56 assertEq(marks[2], 'gray', 'gray key 2'); 57 assertEq(marks[3], 'gray', 'black map, gray key => gray value'); 58 59 // Blacken one of the keys 60 wrapper1 = grayRoot().root1; 61 gc(); 62 marks = getMarks(); 63 assertEq(marks[0], 'black', 'black key 1'); 64 assertEq(marks[1], 'black', 'black map, black key => black value'); 65 assertEq(marks[2], 'gray', 'gray key 2'); 66 assertEq(marks[3], 'gray', 'black map, gray key => gray value'); 67 68 // Test edges from map&delegate => key and map&key => value. 69 // 70 // In general, when a&b => x, then if both a and b are black, then x must be 71 // black. If either is gray and the other is marked (gray or black), then x 72 // must be gray (unless otherwise reachable from black.) If neither a nor b is 73 // marked at all, then they will not keep x alive. 74 75 clearMarkObservers(); 76 77 // Black map, gray delegate => gray key 78 79 // wm is in a variable, so is black. 80 wm = new WeakMap(); 81 82 let key = Object.create(null); 83 // delegate unwraps key in the 'global' compartment 84 global.grayRoot().delegate = key; 85 86 // Create a value and map to it from a gray key, then make the value a gray 87 // root. 88 let value = Object.create(null); 89 wm.set(key, value); 90 grayRoot().value = value; 91 92 // We are interested in the mark bits of the map, key, and value, as well as 93 // the mark bits of the wrapped versions in the other compartment. Note that 94 // the other-compartment key is the known as the key's delegate with respect to 95 // the weakmap. 96 global.addMarkObservers([wm, key, value]); 97 addMarkObservers([wm, key, value]); 98 99 // Key is otherwise dead in main compartment. 100 key = null; 101 // Don't want value to be marked black. 102 value = null; 103 104 gc(); // Update mark bits. 105 let [ 106 other_map_mark, other_key_mark, other_value_mark, 107 map_mark, key_mark, value_mark 108 ] = getMarks(); 109 assertEq(other_map_mark, 'dead', 'nothing points to wm in other compartment'); 110 assertEq(other_key_mark, 'gray', 'delegate should be gray'); 111 assertEq(other_value_mark, 'dead', 'nothing points to value wrapper in other compartment'); 112 assertEq(map_mark, 'black', 'map in var => black'); 113 assertEq(key_mark, 'gray', 'black map, gray delegate => gray key'); 114 assertEq(value_mark, 'gray', 'black map, gray delegate/key => gray value'); 115 116 // Black map, black delegate => black key 117 118 // Blacken the delegate by pointing to it from the other global. 119 global.delegate = global.grayRoot().delegate; 120 121 gc(); 122 [ 123 other_map_mark, other_key_mark, other_value_mark, 124 map_mark, key_mark, value_mark 125 ] = getMarks(); 126 assertEq(other_map_mark, 'dead', 'nothing points to wm in other compartment'); 127 assertEq(other_key_mark, 'black', 'delegate held in global.delegate'); 128 assertEq(other_value_mark, 'dead', 'nothing points to value wrapper in other compartment'); 129 assertEq(map_mark, 'black', 'map in var => black'); 130 assertEq(key_mark, 'black', 'black map, black delegate => black key'); 131 assertEq(value_mark, 'black', 'black map, black key => black value'); 132 133 // Gray map, black delegate => gray key. Unfortunately, there's no way to test 134 // this, because a WeakMap key's delegate is its wrapper, and there is a strong 135 // edge from wrappers to wrappees. The jsapi-test in testGCGrayMarking, inside 136 // TestWeakMaps, *does* test this case. 137 138 grayRoot().map = wm; 139 wm = null; 140 141 gc(); 142 [ 143 other_map_mark, other_key_mark, other_value_mark, 144 map_mark, key_mark, value_mark 145 ] = getMarks(); 146 assertEq(other_map_mark, 'dead', 'nothing points to wm in other compartment'); 147 assertEq(other_key_mark, 'black', 'delegate held in global.delegate'); 148 assertEq(other_value_mark, 'dead', 'nothing points to value wrapper in other compartment'); 149 assertEq(map_mark, 'gray', 'map is a gray root'); 150 assertEq(key_mark, 'black', 'black delegate marks its key black'); 151 assertEq(value_mark, 'gray', 'gray map, black key => gray value'); 152 } 153 test(); 154 155 if (typeof reportCompare === "function") 156 reportCompare(true, true);