Commit 230dd86c authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[Class] Fix debug scope iteration for class fields

When trying to print the scope information for the class fields
initializer function, the debugger asks the parser to parse the class
literal as a function literal (to get the scope info) ... which
doesn't quite work.

Instead of adding support for parsing the class literal, we just short
cicruit this parsing step by just returning an empty context.

This works fine because initializer function doesn't have any
variables in it's local scope.

The one caveat is that the objects in the scope above this function
(like the global) are now missing. This trade off is possibly fine
for now, as adding parsing support for class literal to only produce
would be a lot of code for not enough use.

As a follow up to this change, the devtools UI needs to be updated to
handle this empty context cleanly. Currently, it doesn't show the
`this` object if no context exists even if the `this` object is
correctly passed to the UI from the backend.

Bug: v8:5367, v8:8122
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I52965f26241bbf6abdc988783aa0fc44bb36901f
Reviewed-on: https://chromium-review.googlesource.com/c/1274268
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarAleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56611}
parent fb233038
......@@ -98,6 +98,16 @@ void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
return;
}
// Class fields initializer functions don't have any scope
// information. We short circuit the parsing of the class literal
// and return an empty context here.
if (IsClassFieldsInitializerFunction(shared_info->kind())) {
current_scope_ = closure_scope_ = nullptr;
context_ = Handle<Context>();
function_ = Handle<JSFunction>();
return;
}
DCHECK_NE(IGNORE_NESTED_SCOPES, option);
bool ignore_nested_scopes = false;
if (shared_info->HasBreakInfo() && frame_inspector_ != nullptr) {
......
Test class fields scopes
Running test: testScopesPaused
[
[0] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 14
lineNumber : 2
scriptId : <scriptId>
}
functionName : foo
location : {
columnNumber : 4
lineNumber : 3
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 3
lineNumber : 5
scriptId : <scriptId>
}
name : foo
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 14
lineNumber : 2
scriptId : <scriptId>
}
type : local
}
[1] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : closure
}
[2] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
[1] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
functionName : run
location : {
columnNumber : 5
lineNumber : 13
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 3
lineNumber : 15
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 9
lineNumber : 11
scriptId : <scriptId>
}
type : block
}
[1] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : local
}
[2] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
[2] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
functionName :
location : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
scopeChain : [
[0] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
]
[
[0] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
functionName : <instance_fields_initializer>
location : {
columnNumber : 8
lineNumber : 12
scriptId : <scriptId>
}
scopeChain : [
]
this : {
className : X
description : X
objectId : <objectId>
type : object
}
url :
}
[1] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
functionName : X
location : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
name : X
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
type : local
}
[1] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : closure
}
[2] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : X
description : X
objectId : <objectId>
type : object
}
url :
}
[2] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
functionName : run
location : {
columnNumber : 2
lineNumber : 18
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : local
}
[1] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
[3] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
functionName :
location : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
scopeChain : [
[0] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
]
[
[0] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
functionName : <instance_fields_initializer>
location : {
columnNumber : 14
lineNumber : 13
scriptId : <scriptId>
}
scopeChain : [
]
this : {
className : X
description : X
objectId : <objectId>
type : object
}
url :
}
[1] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
functionName : X
location : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
name : X
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
type : local
}
[1] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : closure
}
[2] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : X
description : X
objectId : <objectId>
type : object
}
url :
}
[2] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
functionName : run
location : {
columnNumber : 2
lineNumber : 18
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : local
}
[1] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
[3] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
functionName :
location : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
scopeChain : [
[0] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
]
[
[0] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
functionName : <instance_fields_initializer>
location : {
columnNumber : 8
lineNumber : 14
scriptId : <scriptId>
}
scopeChain : [
]
this : {
className : X
description : X
objectId : <objectId>
type : object
}
url :
}
[1] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
functionName : X
location : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
name : X
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
type : local
}
[1] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : closure
}
[2] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : X
description : X
objectId : <objectId>
type : object
}
url :
}
[2] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
functionName : run
location : {
columnNumber : 2
lineNumber : 18
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : local
}
[1] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
[3] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
functionName :
location : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
scopeChain : [
[0] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
]
[
[0] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 14
lineNumber : 7
scriptId : <scriptId>
}
functionName : bar
location : {
columnNumber : 4
lineNumber : 8
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 3
lineNumber : 9
scriptId : <scriptId>
}
name : bar
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 14
lineNumber : 7
scriptId : <scriptId>
}
type : local
}
[1] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : closure
}
[2] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
[1] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
functionName : <instance_fields_initializer>
location : {
columnNumber : 8
lineNumber : 14
scriptId : <scriptId>
}
scopeChain : [
]
this : {
className : X
description : X
objectId : <objectId>
type : object
}
url :
}
[2] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
functionName : X
location : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
name : X
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 2
lineNumber : 11
scriptId : <scriptId>
}
type : local
}
[1] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : closure
}
[2] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : X
description : X
objectId : <objectId>
type : object
}
url :
}
[3] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
functionName : run
location : {
columnNumber : 2
lineNumber : 18
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 1
lineNumber : 19
scriptId : <scriptId>
}
name : run
object : {
className : Object
description : Object
objectId : <objectId>
type : object
}
startLocation : {
columnNumber : 12
lineNumber : 1
scriptId : <scriptId>
}
type : local
}
[1] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
[4] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
functionName :
location : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
scopeChain : [
[0] : {
object : {
className : global
description : global
objectId : <objectId>
type : object
}
type : global
}
]
this : {
className : global
description : global
objectId : <objectId>
type : object
}
url :
}
]
// Copyright 2016 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: --harmony-public-fields --harmony-static-fields
let { session, contextGroup, Protocol } = InspectorTest.start(
"Test class fields scopes"
);
contextGroup.addScript(`
function run() {
function foo() {
debugger;
return "foo";
}
function bar() {
return 3;
}
class X {
x = 1;
[foo()] = 2;
p = bar();
}
debugger;
new X;
}`);
InspectorTest.runAsyncTestSuite([
async function testScopesPaused() {
Protocol.Debugger.enable();
Protocol.Runtime.evaluate({ expression: "run()" });
let {
params: { callFrames: callFrames0 }
} = await Protocol.Debugger.oncePaused(); // inside foo()
InspectorTest.logMessage(callFrames0);
Protocol.Debugger.resume();
await Protocol.Debugger.oncePaused(); // at debugger;
Protocol.Debugger.stepOver(); // at debugger;
await Protocol.Debugger.oncePaused(); // at new X;
Protocol.Debugger.stepInto(); // step into initializer_function;
// at x = 1;
let {
params: { callFrames: callFrames1 }
} = await Protocol.Debugger.oncePaused();
InspectorTest.logMessage(callFrames1);
Protocol.Debugger.stepOver();
// at [foo()] = 2;
let {
params: { callFrames: callFrames2 }
} = await Protocol.Debugger.oncePaused();
InspectorTest.logMessage(callFrames2);
Protocol.Debugger.stepOver();
// at p = bar();
let {
params: { callFrames: callFrames3 }
} = await Protocol.Debugger.oncePaused();
InspectorTest.logMessage(callFrames3);
Protocol.Debugger.stepInto();
// inside bar();
let {
params: { callFrames: callFrames4 }
} = await Protocol.Debugger.oncePaused();
InspectorTest.logMessage(callFrames4);
Protocol.Debugger.resume();
Protocol.Debugger.disable();
}
]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment