diff options
Diffstat (limited to '')
-rw-r--r-- | js/src/tests/non262/extensions/collect-gray.js | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/js/src/tests/non262/extensions/collect-gray.js b/js/src/tests/non262/extensions/collect-gray.js new file mode 100644 index 0000000000..4beb9f094f --- /dev/null +++ b/js/src/tests/non262/extensions/collect-gray.js @@ -0,0 +1,153 @@ +// |reftest| skip-if(!xulRuntime.shell) +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1337209; +var summary = + "Test gray marking"; + +print(BUGNUMBER + ": " + summary); + +if (typeof gczeal !== 'undefined') + gczeal(0); + +grayRoot().x = Object.create(null); +addMarkObservers([grayRoot(), grayRoot().x, this, Object.create(null)]); +gc(); +let marks = getMarks(); +assertEq(marks[0], 'gray', 'gray root'); +assertEq(marks[1], 'gray', 'object reachable from gray root'); +assertEq(marks[2], 'black', 'global'); +assertEq(marks[3], 'dead', 'dead object should have been collected'); + +grayRoot().x = 7; // Overwrite the object +gc(); +marks = getMarks(); +assertEq(marks[0], 'gray', 'gray root'); +assertEq(marks[1], 'dead', 'object no longer reachable from gray root'); +assertEq(marks[2], 'black', 'global'); +assertEq(marks[3], 'dead', 'dead object should have been collected'); + +var wm = new WeakMap(); +var global = newGlobal({newCompartment: true}); + +var wrapper1 = global.eval("Object.create(null)"); +wrapper1.name = "wrapper1"; +var value1 = Object.create(null); +wm.set(wrapper1, value1); + +var wrapper2 = global.eval("Object.create(null)"); +wrapper2.name = "wrapper2"; +var value2 = global.eval("Object.create(null)"); +wm.set(wrapper2, value2); + +grayRoot().root1 = wrapper1; +grayRoot().root2 = wrapper2; +clearMarkObservers(); +addMarkObservers([wrapper1, value1, wrapper2, value2]); +wrapper1 = wrapper2 = null; +value1 = value2 = null; +gc(); +marks = getMarks(); +assertEq(marks[0], 'gray', 'gray key 1'); +assertEq(marks[1], 'gray', 'black map, gray key => gray value'); +assertEq(marks[2], 'gray', 'gray key 2'); +assertEq(marks[3], 'gray', 'black map, gray key => gray value'); + +// Blacken one of the keys +wrapper1 = grayRoot().root1; +gc(); +marks = getMarks(); +assertEq(marks[0], 'black', 'black key 1'); +assertEq(marks[1], 'black', 'black map, black key => black value'); +assertEq(marks[2], 'gray', 'gray key 2'); +assertEq(marks[3], 'gray', 'black map, gray key => gray value'); + +// Test edges from map&delegate => key and map&key => value. +// +// In general, when a&b => x, then if both a and b are black, then x must be +// black. If either is gray and the other is marked (gray or black), then x +// must be gray (unless otherwise reachable from black.) If neither a nor b is +// marked at all, then they will not keep x alive. + +clearMarkObservers(); + +// Black map, gray delegate => gray key + +// wm is in a variable, so is black. +wm = new WeakMap(); + +let key = Object.create(null); +// delegate unwraps key in the 'global' compartment +global.grayRoot().delegate = key; + +// Create a value and map to it from a gray key, then make the value a gray +// root. +let value = Object.create(null); +wm.set(key, value); +grayRoot().value = value; + +// We are interested in the mark bits of the map, key, and value, as well as +// the mark bits of the wrapped versions in the other compartment. Note that +// the other-compartment key is the known as the key's delegate with respect to +// the weakmap. +global.addMarkObservers([wm, key, value]); +addMarkObservers([wm, key, value]); + +// Key is otherwise dead in main compartment. +key = null; +// Don't want value to be marked black. +value = null; + +gc(); // Update mark bits. +let [ + other_map_mark, other_key_mark, other_value_mark, + map_mark, key_mark, value_mark +] = getMarks(); +assertEq(other_map_mark, 'dead', 'nothing points to wm in other compartment'); +assertEq(other_key_mark, 'gray', 'delegate should be gray'); +assertEq(other_value_mark, 'dead', 'nothing points to value wrapper in other compartment'); +assertEq(map_mark, 'black', 'map in var => black'); +assertEq(key_mark, 'gray', 'black map, gray delegate => gray key'); +assertEq(value_mark, 'gray', 'black map, gray delegate/key => gray value'); + +// Black map, black delegate => black key + +// Blacken the delegate by pointing to it from the other global. +global.delegate = global.grayRoot().delegate; + +gc(); +[ + other_map_mark, other_key_mark, other_value_mark, + map_mark, key_mark, value_mark +] = getMarks(); +assertEq(other_map_mark, 'dead', 'nothing points to wm in other compartment'); +assertEq(other_key_mark, 'black', 'delegate held in global.delegate'); +assertEq(other_value_mark, 'dead', 'nothing points to value wrapper in other compartment'); +assertEq(map_mark, 'black', 'map in var => black'); +assertEq(key_mark, 'black', 'black map, black delegate => black key'); +assertEq(value_mark, 'black', 'black map, black key => black value'); + +// Gray map, black delegate => gray key. Unfortunately, there's no way to test +// this, because a WeakMap key's delegate is its wrapper, and there is a strong +// edge from wrappers to wrappees. The jsapi-test in testGCGrayMarking, inside +// TestWeakMaps, *does* test this case. + +grayRoot().map = wm; +wm = null; + +gc(); +[ + other_map_mark, other_key_mark, other_value_mark, + map_mark, key_mark, value_mark +] = getMarks(); +assertEq(other_map_mark, 'dead', 'nothing points to wm in other compartment'); +assertEq(other_key_mark, 'black', 'delegate held in global.delegate'); +assertEq(other_value_mark, 'dead', 'nothing points to value wrapper in other compartment'); +assertEq(map_mark, 'gray', 'map is a gray root'); +assertEq(key_mark, 'black', 'black delegate marks its key black'); +assertEq(value_mark, 'gray', 'gray map, black key => gray value'); + +if (typeof reportCompare === "function") + reportCompare(true, true); |