Commit aa101ca1 authored by Simon Zünd's avatar Simon Zünd Committed by V8 LUCI CQ

[debug] Fix scope for class member initializer

This CL removes the bailout when trying to collect the scope info
for the class member initializer function. While this might not have
worked previously, now we only need to tweak the scope search
slightly to fix this. Class member initializer functions never
have their own context but instead us the class context. That means
that most of the logic in debug-scopes.cc doesn't really matter and we
only need to initialize the ScopeIterator properly with the class
context and the member initializer JSFunction.

Note that this still does not fully fix bug 1350842. That is because
we still run into a DCHECk when paused at a `new class { ... }`
statement. We'll fix that in a separate CL.

R=bmeurer@chromium.org

Bug: chromium:1350842
Change-Id: Id128b10676a5aa8a77309735e755e485f2c14446
Fixed: chromium:1246889
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3825881
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82387}
parent 606e7022
......@@ -132,7 +132,13 @@ class ScopeChainRetriever {
}
bool RetrieveClosureScope(Scope* scope) {
if (break_scope_start_ == scope->start_position() &&
// The closure scope is the scope that matches exactly the function we
// paused in. There is one quirk though, member initializder functions have
// the same source position as their class scope, so when looking for the
// declaration scope of the member initializer, we need to skip the
// corresponding class scope and keep looking.
if (!scope->is_class_scope() &&
break_scope_start_ == scope->start_position() &&
break_scope_end_ == scope->end_position()) {
closure_scope_ = scope->AsDeclarationScope();
return true;
......@@ -194,16 +200,6 @@ void ScopeIterator::TryParseAndRetrieveScopes(ReparseStrategy strategy) {
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 (IsClassMembersInitializerFunction(shared_info->kind())) {
current_scope_ = closure_scope_ = nullptr;
context_ = Handle<Context>();
function_ = Handle<JSFunction>();
return;
}
bool ignore_nested_scopes = false;
if (shared_info->HasBreakInfo() && frame_inspector_ != nullptr) {
// The source position at return is always the end of the function,
......
......@@ -198,6 +198,55 @@ Running test: testScopesPaused
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 3
lineNumber : 15
scriptId : <scriptId>
}
name : <instance_members_initializer>
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
......@@ -383,6 +432,55 @@ Running test: testScopesPaused
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 3
lineNumber : 15
scriptId : <scriptId>
}
name : <instance_members_initializer>
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
......@@ -568,6 +666,55 @@ Running test: testScopesPaused
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 3
lineNumber : 15
scriptId : <scriptId>
}
name : <instance_members_initializer>
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
......@@ -826,6 +973,55 @@ Running test: testScopesPaused
scriptId : <scriptId>
}
scopeChain : [
[0] : {
endLocation : {
columnNumber : 3
lineNumber : 15
scriptId : <scriptId>
}
name : <instance_members_initializer>
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
......
Don't crash when evaluating `this` in class instance initializer
{
id : <messageId>
result : {
result : {
className : tmpName
description : tmpName
objectId : <objectId>
type : object
}
}
}
{
id : <messageId>
result : {
result : {
type : string
value : tmpName
}
}
}
// Copyright 2022 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 {contextGroup, Protocol} = InspectorTest.start('Don\'t crash when evaluating `this` in class instance initializer');
const script = `
(function foo() {
function identity(v) {
return v;
}
debugger;
class tmpName {
#thisWorks = this.constructor.name;
#thisFails = identity(this.constructor.name);
};
new tmpName;
})();
`;
(async () => {
Protocol.Debugger.enable();
contextGroup.addScript(script, 0, 0, 'test.js');
await Protocol.Debugger.oncePaused();
Protocol.Debugger.stepInto({});
await Protocol.Debugger.oncePaused();
Protocol.Debugger.stepInto({});
const { params: { callFrames } } = await Protocol.Debugger.oncePaused();
InspectorTest.logMessage(
await Protocol.Debugger.evaluateOnCallFrame({ callFrameId: callFrames[0].callFrameId, expression: "this" }));
InspectorTest.logMessage(
await Protocol.Debugger.evaluateOnCallFrame({ callFrameId: callFrames[0].callFrameId, expression: "this.constructor.name" }));
InspectorTest.completeTest();
})();
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