зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1617210 - Fix issue with duplicated ObjectFronts in the scopes panel. r=jlast.
Since the thread actor caches the object actors it creates, if an object had multiple properties referencing the same object, we would create multiple fronts for the same object actor, which would confuse protocol.js. The fix consist in checking if a front already exists before creating a new one. A test is added for the debugger to ensure this works as expected and we don't regress. Differential Revision: https://phabricator.services.mozilla.com/D63907 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
14600c1dc3
Коммит
ab439621fd
|
@ -180,6 +180,7 @@ skip-if = (os == 'linux' && debug) || (os == 'linux' && asan) || ccov #Bug 1456
|
|||
[browser_dbg-old-breakpoint.js]
|
||||
[browser_dbg-idb-run-to-completion.js]
|
||||
[browser_dbg-inline-script-offset.js]
|
||||
[browser_dbg-scopes-duplicated.js]
|
||||
[browser_dbg-scopes-xrays.js]
|
||||
[browser_dbg-merge-scopes.js]
|
||||
[browser_dbg-message-run-to-completion.js]
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that properties with the same value objec be expanded. See Bug 1617210.
|
||||
|
||||
const httpServer = createTestHTTPServer();
|
||||
httpServer.registerContentType("html", "text/html");
|
||||
httpServer.registerContentType("js", "application/javascript");
|
||||
|
||||
httpServer.registerPathHandler(`/`, function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.write(`
|
||||
<html>
|
||||
<button class="pause">Click me</button>
|
||||
<script type="text/javascript" src="test.js"></script>
|
||||
</html>`);
|
||||
});
|
||||
|
||||
httpServer.registerPathHandler("/test.js", function(request, response) {
|
||||
response.setHeader("Content-Type", "application/javascript");
|
||||
response.write(`
|
||||
document.addEventListener("click", function onClick(e) {
|
||||
var hello = {hello: "world"};
|
||||
var x = {a: hello, b: hello, c: hello};
|
||||
debugger;
|
||||
});
|
||||
`);
|
||||
});
|
||||
const port = httpServer.identity.primaryPort;
|
||||
const TEST_URL = `http://localhost:${port}/`;
|
||||
|
||||
add_task(async function() {
|
||||
const dbg = await initDebuggerWithAbsoluteURL(TEST_URL);
|
||||
|
||||
const ready = Promise.all([
|
||||
waitForPaused(dbg),
|
||||
waitForLoadedSource(dbg, "test"),
|
||||
]);
|
||||
|
||||
SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
|
||||
content.document.querySelector("button.pause").click();
|
||||
});
|
||||
|
||||
await ready;
|
||||
|
||||
is(getLabel(dbg, 4), "e");
|
||||
is(getLabel(dbg, 5), "hello");
|
||||
is(getLabel(dbg, 6), "x");
|
||||
|
||||
info("Expand `x` node");
|
||||
await toggleScopeNode(dbg, 6);
|
||||
is(getLabel(dbg, 7), "a");
|
||||
is(getLabel(dbg, 8), "b");
|
||||
is(getLabel(dbg, 9), "c");
|
||||
|
||||
info("Expand `c`, `b` and `a` nodes");
|
||||
await toggleScopeNode(dbg, 9);
|
||||
await toggleScopeNode(dbg, 8);
|
||||
await toggleScopeNode(dbg, 7);
|
||||
|
||||
is(getLabel(dbg, 7), "a");
|
||||
is(getLabel(dbg, 8), "hello");
|
||||
is(getLabel(dbg, 9), "<prototype>");
|
||||
is(getLabel(dbg, 10), "b");
|
||||
is(getLabel(dbg, 11), "hello");
|
||||
is(getLabel(dbg, 12), "<prototype>");
|
||||
is(getLabel(dbg, 13), "c");
|
||||
is(getLabel(dbg, 14), "hello");
|
||||
is(getLabel(dbg, 15), "<prototype>");
|
||||
|
||||
info("Expand `e`");
|
||||
await toggleScopeNode(dbg, 4);
|
||||
|
||||
info("Expand the `target` node");
|
||||
let nodes = getAllLabels(dbg);
|
||||
const originalNodesCount = nodes.length;
|
||||
const targetNodeIndex = nodes.indexOf("target");
|
||||
ok(targetNodeIndex > -1, "Found the target node");
|
||||
await toggleScopeNode(dbg, targetNodeIndex);
|
||||
nodes = getAllLabels(dbg);
|
||||
ok(nodes.length > originalNodesCount, "the target node was expanded");
|
||||
ok(nodes.includes("classList"), "classList is displayed");
|
||||
});
|
||||
|
||||
function getAllLabels(dbg) {
|
||||
return Array.from(findAllElements(dbg, "scopeNodes")).map(el => el.innerText);
|
||||
}
|
||||
|
||||
function getLabel(dbg, index) {
|
||||
return findElement(dbg, "scopeNode", index).innerText;
|
||||
}
|
|
@ -1299,6 +1299,7 @@ const selectors = {
|
|||
},
|
||||
columnBreakpoints: ".column-breakpoint",
|
||||
scopes: ".scopes-list",
|
||||
scopeNodes: ".scopes-list .object-label",
|
||||
scopeNode: i => `.scopes-list .tree-node:nth-child(${i}) .object-label`,
|
||||
scopeValue: i =>
|
||||
`.scopes-list .tree-node:nth-child(${i}) .object-delimiter + *`,
|
||||
|
|
|
@ -433,6 +433,7 @@ function parsePacketAndCreateFronts(packet) {
|
|||
conn: {
|
||||
poolFor: () => {},
|
||||
addActorPool: () => {},
|
||||
getFrontByID: () => {},
|
||||
},
|
||||
manage: () => {},
|
||||
});
|
||||
|
|
|
@ -310,6 +310,7 @@ async function test_unsafe_grips(
|
|||
);
|
||||
}
|
||||
}
|
||||
await objClient.release();
|
||||
}
|
||||
|
||||
await threadFront.resume();
|
||||
|
|
|
@ -315,6 +315,14 @@ function getAdHocFrontOrPrimitiveGrip(packet, parentFront) {
|
|||
}
|
||||
|
||||
const { conn, targetFront } = parentFront;
|
||||
|
||||
// We may have already created a front for this object actor since some actor (e.g. the
|
||||
// thread actor) cache the object actors they create.
|
||||
const existingFront = conn.getFrontByID(packet.actor);
|
||||
if (existingFront) {
|
||||
return existingFront;
|
||||
}
|
||||
|
||||
const { type } = packet;
|
||||
|
||||
if (type === "longString") {
|
||||
|
|
Загрузка…
Ссылка в новой задаче