089edbfa97
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}
117 lines
2.6 KiB
JavaScript
117 lines
2.6 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
|
|
|
|
// Test that debug-evaluate can find the correct this value for an arrow
|
|
// function, if "this" is referenced within the arrow function scope.
|
|
|
|
Debug = debug.Debug
|
|
|
|
var break_count = 0;
|
|
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 this_value = frame.evaluate("this").value();
|
|
var expected = frame.sourceLineText().match(/\/\/ (.*$)/)[1];
|
|
print(expected, this_value, frame.sourceLineText());
|
|
assertEquals(String(expected), String(this_value));
|
|
}
|
|
break_count++;
|
|
} catch (e) {
|
|
exception = e;
|
|
print(e + e.stack);
|
|
}
|
|
}
|
|
|
|
// Context-allocated receiver.
|
|
function f() {
|
|
debugger; // foo
|
|
return () => {
|
|
debugger; // foo
|
|
with ({}) {
|
|
return () => {
|
|
debugger; // foo
|
|
try {
|
|
throw new Error();
|
|
} catch (e) {
|
|
return () => {
|
|
(() => this); // bind this.
|
|
debugger; // foo
|
|
return () => {
|
|
debugger; // undefined
|
|
return g.call("goo"); // undefined
|
|
}
|
|
};
|
|
}
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
// Stack-allocated receiver.
|
|
function g() {
|
|
debugger; // goo
|
|
return () => {
|
|
debugger; // undefined
|
|
with ({}) {
|
|
return () => {
|
|
debugger; // undefined
|
|
try {
|
|
throw new Error();
|
|
} catch (e) {
|
|
return () => {
|
|
debugger; // undefined
|
|
return f.call("foo"); // undefined
|
|
};
|
|
}
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
Debug.setListener(listener);
|
|
|
|
var h = f.call("foo");
|
|
for (var i = 0; i < 20; i++) h = h();
|
|
var h = g.call("goo");
|
|
for (var i = 0; i < 20; i++) h = h();
|
|
|
|
function x() {
|
|
(() => this); // bind this.
|
|
function y() {
|
|
(() => {
|
|
(() => this); // bind this.
|
|
debugger; // Y
|
|
})(); // Y
|
|
}
|
|
y.call("Y"); // X
|
|
}
|
|
x.call("X");
|
|
|
|
function u() {
|
|
(() => this);
|
|
function v() {
|
|
(() => {
|
|
debugger; // undefined
|
|
})(); // V
|
|
}
|
|
v.call("V"); // U
|
|
}
|
|
u.call("U");
|
|
|
|
(() => {
|
|
(() => this);
|
|
debugger; // [object global]
|
|
})();
|
|
|
|
Debug.setListener(null);
|
|
|
|
assertEquals(55, break_count);
|
|
assertNull(exception);
|