v8/test/mjsunit/debug-evaluate-shadowed-context.js
yangguo 089edbfa97 [debugger] fix debug-evaluate wrt shadowed context var.
Debug-evaluate used to resolve stack variables that shadow
context variables incorrectly, since the stack variable is
not visible in the context chain.

To fix this, we limit local variables accessible by debug-
evaluate to the ones directly referenced inside the function.
What is not referenced by the function itself, is considered
optimized out and not accessible by debug-evaluate.

To achieve this, we duplicate the entire context chain up to
the native context, and write back changes after debug-
evaluate. Changes to the original context chain will however
be overwritten. This already happens for catch and block
scopes though.

Also fix a crash caused by declaring variables inside debug-
evaluate.

R=mstarzinger@chromium.org
BUG=v8:4593
LOG=N

Review URL: https://codereview.chromium.org/1500933002

Cr-Commit-Position: refs/heads/master@{#32828}
2015-12-14 10:25:11 +00:00

83 lines
2.1 KiB
JavaScript

// Copyright 2015 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.
// Flags: --expose-debug-as debug --no-analyze-environment-liveness
// Test that debug-evaluate only resolves variables that are used by
// the function inside which we debug-evaluate. This is to avoid
// incorrect variable resolution when a context-allocated variable is
// shadowed by a stack-allocated variable.
Debug = debug.Debug
var exception = null;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
for (var i = 0; i < exec_state.frameCount() - 1; i++) {
var frame = exec_state.frame(i);
var value;
try {
value = frame.evaluate("x").value();
} catch (e) {
value = e.name;
}
print(frame.sourceLineText());
var expected = frame.sourceLineText().match(/\/\/ (.*$)/)[1];
assertEquals(String(expected), String(value));
}
assertEquals("[object global]",
String(exec_state.frame(0).evaluate("this").value()));
exec_state.frame(0).evaluate("y = 'Y'");
exec_state.frame(0).evaluate("a = 'A'");
assertThrows(() => exec_state.frame(0).evaluate("z"), ReferenceError);
} catch (e) {
exception = e;
print(e + e.stack);
}
}
Debug.setListener(listener);
var a = "a";
assertEquals("Y", (function() {
var x = 1; // context allocate x
(() => x);
var y = "y";
var z = "z";
(function() {
var x = 2; // stack allocate shadowing x
(function() {
y; // access y
debugger; // ReferenceError
})(); // 2
})(); // 1
return y;
})());
assertEquals("A", a);
a = "a";
assertEquals("Y", (function() {
var x = 1; // context allocate x
(() => x);
var y = "y";
var z = "z";
(function() {
var x = 2; // stack allocate shadowing x
(() => {
y;
a;
this; // context allocate receiver
debugger; // ReferenceError
})(); // 2
})(); // 1
return y;
})());
assertEquals("A", a);
Debug.setListener(null);
assertNull(exception);