summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/extensions/collect-gray.js
blob: 4beb9f094f22246353074c35153cbf325f5280c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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);