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
|
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test the ObjectCommand
add_task(async function testObjectRelease() {
const tab = await addTab("data:text/html;charset=utf-8,Test page<script>var foo = { bar: 42 };</script>");
const commands = await CommandsFactory.forTab(tab);
await commands.targetCommand.startListening();
const { objectCommand } = commands;
const evaluationResponse = await commands.scriptCommand.execute(
"window.foo"
);
// Execute a second time so that the WebConsoleActor set this._lastConsoleInputEvaluation to another value
// and so we prevent freeing `window.foo`
await commands.scriptCommand.execute("");
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
is(content.wrappedJSObject.foo.bar, 42);
const weakRef = Cu.getWeakReference(content.wrappedJSObject.foo);
// Hold off the weak reference on SpecialPowsers so that it can be accessed in the next SpecialPowers.spawn
SpecialPowers.weakRef = weakRef;
// Nullify this variable so that it should be freed
// unless the DevTools inspection still hold it in memory
content.wrappedJSObject.foo = null;
Cu.forceGC();
Cu.forceCC();
ok(SpecialPowers.weakRef.get(), "The 'foo' object can't be freed because of DevTools keeping a reference on it");
});
info("Release the server side actors which are keeping the object in memory");
const objectFront = evaluationResponse.result;
await commands.objectCommand.releaseObjects([objectFront]);
ok(objectFront.isDestroyed(), "The passed object front has been destroyed");
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
await ContentTaskUtils.waitForCondition(() => {
Cu.forceGC();
Cu.forceCC();
return !SpecialPowers.weakRef.get();
}, "Wait for JS object to be freed", 500);
ok(!SpecialPowers.weakRef.get(), "The 'foo' object has been freed");
});
await commands.destroy();
BrowserTestUtils.removeTab(tab);
});
add_task(async function testMultiTargetObjectRelease() {
// This test fails with EFT disabled
if (!isEveryFrameTargetEnabled()) {
return;
}
const tab = await addTab(`data:text/html;charset=utf-8,Test page<iframe src="data:text/html,bar">/iframe>`);
const commands = await CommandsFactory.forTab(tab);
await commands.targetCommand.startListening();
const [,iframeTarget] = commands.targetCommand.getAllTargets(commands.targetCommand.ALL_TYPES);
is(iframeTarget.url, "data:text/html,bar");
const { objectCommand } = commands;
const evaluationResponse1 = await commands.scriptCommand.execute(
"window"
);
const evaluationResponse2 = await commands.scriptCommand.execute(
"window", {
selectedTargetFront: iframeTarget,
}
);
const object1 = evaluationResponse1.result;
const object2 = evaluationResponse2.result;
isnot(object1, object2, "The two window object fronts are different");
isnot(object1.targetFront, object2.targetFront, "The two window object fronts relates to two distinct targets");
is(object2.targetFront, iframeTarget, "The second object relates to the iframe target");
await commands.objectCommand.releaseObjects([object1, object2]);
ok(object1.isDestroyed(), "The first object front is destroyed");
ok(object2.isDestroyed(), "The second object front is destroyed");
await commands.destroy();
BrowserTestUtils.removeTab(tab);
});
add_task(async function testWorkerObjectRelease() {
const workerUrl = `data:text/javascript,const foo = {}`;
const tab = await addTab(`data:text/html;charset=utf-8,Test page<script>const worker = new Worker("${workerUrl}")</script>`);
const commands = await CommandsFactory.forTab(tab);
commands.targetCommand.listenForWorkers = true;
await commands.targetCommand.startListening();
const [,workerTarget] = commands.targetCommand.getAllTargets(commands.targetCommand.ALL_TYPES);
is(workerTarget.url, workerUrl);
const { objectCommand } = commands;
const evaluationResponse = await commands.scriptCommand.execute(
"foo", {
selectedTargetFront: workerTarget,
}
);
const object = evaluationResponse.result;
is(object.targetFront, workerTarget, "The 'foo' object relates to the worker target");
await commands.objectCommand.releaseObjects([object]);
ok(object.isDestroyed(), "The object front is destroyed");
await commands.destroy();
BrowserTestUtils.removeTab(tab);
});
|