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
|
<!DOCTYPE html>
<script src="../../js/resources/js-test-pre.js"></script>
<script src="testutils.js"></script>
<body>
<script>
description('Tests that Custom Elements does not induce leaks');
var jsTestIsAsync = true;
if (!window.internals)
testFailed('this test requires window.internals');
function step1() {
debug('Test a custom element with minimal capturing');
withFrame(function (frame) {
// Create some upgrade candidates
frame.contentDocument.body.innerHTML = '<x-x><x-x></x-x></x-x>';
// Register a custom element
var proto = Object.create(frame.contentWindow.HTMLElement.prototype);
proto.createdCallback = function () {};
proto.enteredViewCallback = function () {};
proto.leftViewCallback = function () {};
proto.attributeChangedCallback = function () {};
var ctor = frame.contentDocument.register('x-x', {prototype: proto});
// Create some instances
frame.contentDocument.createElement('x-x');
frame.contentDocument.body.appendChild(new ctor());
frame.contentDocument.body.firstElementChild.innerHTML = '<x-x></x-x>';
// Watch to see that some objects die
observations = {
'frame': internals.observeGC(frame),
'window': internals.observeGC(frame.contentWindow),
'document': internals.observeGC(frame.contentDocument),
'proto': internals.observeGC(proto),
'ctor': internals.observeGC(ctor),
'callback': internals.observeGC(proto.attributeChangedCallback)
};
// Throw everything away
frame.remove();
// We check leaks in a separate closure.
checkLeaks(step2);
});
}
function step2() {
debug('Test callbacks which close over a bunch of objects');
withFrame(function (frame) {
// Register a custom element with a callback which closes over
// the prototype, constructor, document, window and frame.
var contentWindow = frame.contentWindow;
var contentDocument = frame.contentDocument;
var proto = Object.create(contentWindow.HTMLElement.prototype);
proto.attributeChangedCallback = function () {
var goodies = [proto, ctor, contentDocument, contentWindow, frame];
goodies.forEach(function (loot) { console.log(loot); });
};
var ctor = contentDocument.register('x-x', {prototype: proto});
// Create an instance; put it in the document
var elem = new ctor();
contentDocument.body.appendChild(elem);
// Watch to see that some objects die
observations = {
'frame': internals.observeGC(frame),
'window': internals.observeGC(contentWindow),
'document': internals.observeGC(contentDocument),
'proto': internals.observeGC(proto),
'ctor': internals.observeGC(ctor),
'callback': internals.observeGC(proto.attributeChangedCallback)
};
// Throw everything away
frame.remove();
checkLeaks(step3);
});
}
function step3() {
debug('Test that navigating a frame with custom elements does not leak');
withFrame(function (frame) {
// Register a custom element with a callback which closes over
// the prototype, constructor, document, window and frame.
var contentWindow = frame.contentWindow;
var contentDocument = frame.contentDocument;
var proto = Object.create(contentWindow.HTMLElement.prototype);
proto.attributeChangedCallback = function () {
var goodies = [proto, ctor, contentDocument, contentWindow, frame];
goodies.forEach(function (loot) { console.log(loot); });
};
var ctor = contentDocument.register('x-x', {prototype: proto});
// Create an instance; put it in the document *and* point to
// it from the window.
var elem = new ctor();
contentDocument.body.appendChild(elem);
contentWindow.thePrecious = elem;
// Watch to see that some objects die; we don't watch the
// window because Blink recycles the window
observations = {
'document': internals.observeGC(contentDocument),
'proto': internals.observeGC(proto),
'ctor': internals.observeGC(ctor),
'callback': internals.observeGC(proto.attributeChangedCallback)
};
// Throw everything away
frame.onload = checkLeaksAndFinishTest;
frame.src = 'resources/empty-document.html';
});
}
function checkLeaksAndFinishTest() {
checkLeaks(finishJSTest);
}
function checkLeaks(nextStep) {
setTimeout(function () {
gc();
// Check that everything that should have died, did die
for (var prop in observations)
shouldBeTrue('observations.' + prop + '.wasCollected');
observations = null;
nextStep();
}, 0);
}
step1();
var successfullyParsed = true;
</script>
<script src="../../js/resources/js-test-post.js"></script>
|