v8/test/inspector/debugger/set-script-source-debug-evaluate-closure.js
Simon Zünd 45026a66ef [liveedit] Replace ScopeObject instead of updating positions in-place
Currently, LiveEdit updates the source positions of unchanged SFIs
in-place (the SFI could have moved due to other functions changing).

This interfere with our plans to re-use ScopeInfo-based blocklists
for debug-evaluate. Entries in the global block list cache are keyed
by ScopeInfo's source position. Any closure that escaped a
debug-evaluate will point to the old ScopeInfo in its context chain
and the block lists should stay in-place in case the escaped closure
is called again.

Rather than updating ScopeInfos in-place, this CL updates the
ScopeInfo object wholesale for unchanged SFIs. This is safe todo
given that the old and new ScopeInfo are identical modulo source
positions.

Drive-by: Take the source position of the function token from the
`FunctionLiteral` rather than doing a more expensive position
translation.

Bug: chromium:1363561
Change-Id: I2b8476edd8d7dc4c618e53551aa5692a21d6fb32
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3932724
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83536}
2022-10-05 13:14:47 +00:00

65 lines
1.9 KiB
JavaScript

// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const {session, contextGroup, Protocol} =
InspectorTest.start('Check that setScriptSource doesn\'t affect debug-evaluate block listing');
const script = `
// INSERT NEWLINES HERE
function f() {
let a = 3; () => a; // context allocated.
return function g() {
let a = 42; // stack-allocated. Shadowing context-allocated from f.
return function h() {
// Give h a context.
let x = 5; () => x;
return function i() {
debugger;
};
};
};
}
(((f())())())();
`;
const updatedScript = script.replace('// INSERT NEWLINES HERE', '\n\n\n');
(async function test() {
await Protocol.Debugger.enable();
await Protocol.Runtime.enable();
const promise = Protocol.Debugger.oncePaused();
contextGroup.addScript(script);
const { params: { callFrames: [{ callFrameId, functionLocation: { scriptId } }] } } = await promise;
// Create a closure that returns `a` and stash it on the global.
await Protocol.Debugger.evaluateOnCallFrame({
callFrameId,
expression: `globalThis['foo'] = () => a;`
});
await Protocol.Debugger.resume();
// Expect a ReferenceError.
const { result: { result: result1 } } = await Protocol.Runtime.evaluate({
expression: 'globalThis.foo();'
});
InspectorTest.logMessage(result1);
// Move function 'h' but don't change it.
const { result: { status } } = await Protocol.Debugger.setScriptSource({
scriptId,
scriptSource: updatedScript,
});
InspectorTest.log(`Debugger.setScriptSource: ${status}`);
// Still expect a ReferenceError.
const { result: { result: result2 } } = await Protocol.Runtime.evaluate({
expression: 'globalThis.foo();'
});
InspectorTest.logMessage(result2);
InspectorTest.completeTest();
})();