Commit 1908872d authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[class] Make class field initializers breakable in the debugger

Add tests.

Bug: v8:5367
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I2a4215a87ba1dae98c4b25547494165f534b4a66
Reviewed-on: https://chromium-review.googlesource.com/1218046
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarAleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55974}
parent 5743beeb
......@@ -1859,6 +1859,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
DCHECK_NE(property->kind(), ClassLiteral::Property::PRIVATE_FIELD);
Register key = register_allocator()->GrowRegisterList(&args);
builder()->SetExpressionAsStatementPosition(property->key());
BuildLoadPropertyKey(property, key);
if (property->is_static()) {
// The static prototype property is read only. We handle the non
......@@ -1968,13 +1969,13 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
}
void BytecodeGenerator::VisitInitializeClassFieldsStatement(
InitializeClassFieldsStatement* expr) {
InitializeClassFieldsStatement* stmt) {
RegisterList args = register_allocator()->NewRegisterList(3);
Register constructor = args[0], key = args[1], value = args[2];
builder()->MoveRegister(builder()->Receiver(), constructor);
for (int i = 0; i < expr->fields()->length(); i++) {
ClassLiteral::Property* property = expr->fields()->at(i);
for (int i = 0; i < stmt->fields()->length(); i++) {
ClassLiteral::Property* property = stmt->fields()->at(i);
if (property->is_computed_name()) {
DCHECK_EQ(property->kind(), ClassLiteral::Property::PUBLIC_FIELD);
......@@ -1993,6 +1994,7 @@ void BytecodeGenerator::VisitInitializeClassFieldsStatement(
BuildLoadPropertyKey(property, key);
}
builder()->SetExpressionAsStatementPosition(property->value());
VisitForRegisterValue(property->value(), value);
VisitSetHomeObject(value, constructor, property);
......
......@@ -3252,7 +3252,7 @@ FunctionLiteral* Parser::CreateInitializerFunction(
ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kAnonymousExpression,
FunctionLiteral::kShouldEagerCompile, scope->start_position(), true,
FunctionLiteral::kShouldEagerCompile, scope->start_position(), false,
GetNextFunctionLiteralId());
}
......
......@@ -631,5 +631,14 @@ RUNTIME_FUNCTION(Runtime_ReportMessage) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetInitializerFunction) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, constructor, 0);
Handle<Symbol> key = isolate->factory()->class_fields_symbol();
Handle<Object> initializer = JSReceiver::GetDataProperty(constructor, key);
return *initializer;
}
} // namespace internal
} // namespace v8
......@@ -471,6 +471,7 @@ namespace internal {
F(FreezeWasmLazyCompilation, 1, 1) \
F(GetCallable, 0, 1) \
F(GetDeoptCount, 1, 1) \
F(GetInitializerFunction, 1, 1) \
F(GetOptimizationStatus, -1, 1) \
F(GetUndetectable, 0, 1) \
F(GetWasmExceptionId, 2, 1) \
......
......@@ -103,12 +103,12 @@ bytecodes: [
B(Star), R(3),
B(LdaConstant), U8(3),
B(Star), R(4),
B(LdaImmutableCurrentContextSlot), U8(4),
/* 75 E> */ B(ToName), R(7),
/* 75 S> */ B(LdaImmutableCurrentContextSlot), U8(4),
B(ToName), R(7),
B(CreateClosure), U8(5), U8(1), U8(2),
B(Star), R(8),
B(LdaImmutableCurrentContextSlot), U8(5),
/* 106 E> */ B(ToName), R(9),
/* 106 S> */ B(LdaImmutableCurrentContextSlot), U8(5),
B(ToName), R(9),
B(LdaConstant), U8(6),
B(TestEqualStrict), R(9), U8(2),
B(Mov), R(3), R(5),
......
......@@ -37,7 +37,7 @@ bytecodes: [
B(Star), R(5),
B(LdaConstant), U8(1),
B(Star), R(6),
B(LdaConstant), U8(3),
/* 60 S> */ B(LdaConstant), U8(3),
B(StaCurrentContextSlot), U8(4),
B(Star), R(9),
B(Mov), R(5), R(7),
......@@ -59,7 +59,7 @@ bytecodes: [
B(Star), R(5),
B(LdaConstant), U8(7),
B(Star), R(6),
B(LdaConstant), U8(3),
/* 99 S> */ B(LdaConstant), U8(3),
B(StaCurrentContextSlot), U8(4),
B(Star), R(9),
B(Mov), R(5), R(7),
......@@ -145,7 +145,7 @@ bytecodes: [
B(Star), R(7),
B(LdaConstant), U8(1),
B(Star), R(8),
B(LdaConstant), U8(5),
/* 77 S> */ B(LdaConstant), U8(5),
B(StaCurrentContextSlot), U8(4),
B(Star), R(11),
B(Mov), R(7), R(9),
......@@ -175,7 +175,7 @@ bytecodes: [
B(Star), R(7),
B(LdaConstant), U8(9),
B(Star), R(8),
B(LdaConstant), U8(5),
/* 133 S> */ B(LdaConstant), U8(5),
B(StaCurrentContextSlot), U8(4),
B(Star), R(11),
B(CreateClosure), U8(13), U8(7), U8(2),
......@@ -198,7 +198,7 @@ bytecodes: [
B(Star), R(7),
B(LdaConstant), U8(16),
B(Star), R(8),
B(LdaConstant), U8(5),
/* 256 S> */ B(LdaConstant), U8(5),
B(StaCurrentContextSlot), U8(4),
B(Star), R(11),
B(Mov), R(7), R(9),
......
......@@ -44,10 +44,10 @@ bytecodes: [
B(Star), R(5),
B(LdaConstant), U8(1),
B(Star), R(6),
B(LdaConstant), U8(3),
/* 60 S> */ B(LdaConstant), U8(3),
B(StaCurrentContextSlot), U8(4),
B(Star), R(9),
B(LdaConstant), U8(4),
/* 92 S> */ B(LdaConstant), U8(4),
B(Star), R(10),
B(LdaConstant), U8(5),
B(TestEqualStrict), R(10), U8(1),
......@@ -79,10 +79,10 @@ bytecodes: [
B(Star), R(5),
B(LdaConstant), U8(10),
B(Star), R(6),
B(LdaConstant), U8(3),
/* 131 S> */ B(LdaConstant), U8(3),
B(StaCurrentContextSlot), U8(4),
B(Star), R(9),
B(LdaConstant), U8(4),
/* 176 S> */ B(LdaConstant), U8(4),
B(Star), R(10),
B(LdaConstant), U8(5),
B(TestEqualStrict), R(10), U8(1),
......@@ -188,10 +188,10 @@ bytecodes: [
B(Star), R(7),
B(LdaConstant), U8(1),
B(Star), R(8),
B(LdaConstant), U8(5),
/* 77 S> */ B(LdaConstant), U8(5),
B(StaCurrentContextSlot), U8(4),
B(Star), R(11),
B(LdaConstant), U8(6),
/* 109 S> */ B(LdaConstant), U8(6),
B(Star), R(12),
B(LdaConstant), U8(7),
B(TestEqualStrict), R(12), U8(2),
......@@ -231,10 +231,10 @@ bytecodes: [
B(Star), R(7),
B(LdaConstant), U8(12),
B(Star), R(8),
B(LdaConstant), U8(5),
/* 165 S> */ B(LdaConstant), U8(5),
B(StaCurrentContextSlot), U8(4),
B(Star), R(11),
B(LdaConstant), U8(6),
/* 210 S> */ B(LdaConstant), U8(6),
B(Star), R(12),
B(LdaConstant), U8(7),
B(TestEqualStrict), R(12), U8(2),
......@@ -267,10 +267,10 @@ bytecodes: [
B(Star), R(7),
B(LdaConstant), U8(20),
B(Star), R(8),
B(LdaConstant), U8(5),
/* 333 S> */ B(LdaConstant), U8(5),
B(StaCurrentContextSlot), U8(4),
B(Star), R(11),
B(LdaConstant), U8(6),
/* 378 S> */ B(LdaConstant), U8(6),
B(Star), R(12),
B(LdaConstant), U8(7),
B(TestEqualStrict), R(12), U8(2),
......
// Copyright 2018 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 --allow-natives-syntax
Debug = debug.Debug
Debug.setListener(function() {});
class Y {
x = 1;
y = 2;
z = 3;
}
var initializer = %GetInitializerFunction(Y);
var b1, b2, b3;
// class Y {
// x = [B0]1;
// y = [B1]2;
// z = [B2]3;
// }
b1 = Debug.setBreakPoint(initializer, 0, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
b2 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") > 0);
Debug.clearBreakPoint(b2);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") === -1);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B0]3") > 0);
Debug.clearBreakPoint(b3);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B0]3") === -1);
b1 = Debug.setBreakPoint(initializer, 0, 0);
b2 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B1]2;") > 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
Debug.clearBreakPoint(b2);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B1]2;") === -1);
b1 = Debug.setBreakPoint(initializer, 0, 0);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") > 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
Debug.clearBreakPoint(b3);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") === -1);
b2 = Debug.setBreakPoint(initializer, 1, 0);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") > 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") > 0);
Debug.clearBreakPoint(b2);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") === -1);
Debug.clearBreakPoint(b3);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") === -1);
function foo() {}
var bar = "bar";
class X {
[foo()] = 1;
[bar] = 2;
baz = foo();
}
// The computed properties are evaluated during class construction,
// not as part of the initializer function. As a consequence of which,
// they aren't breakable here in the initializer function, but
// instead, are part of the enclosing function.
//
// class X {
// [foo()] = [B0]1;
// [bar] = [B1]2;
// [baz] = [B2]foo();
// }
initializer = %GetInitializerFunction(X);
b1 = Debug.setBreakPoint(initializer, 0, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === -1);
b2 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B0]2;") > 0);
Debug.clearBreakPoint(b2);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B0]2;") === -1);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B0]foo()") > 0);
Debug.clearBreakPoint(b3);
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B0]foo()") === -1);
b1 = Debug.setBreakPoint(initializer, 0, 0);
b2 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B1]2;") > 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === -1);
Debug.clearBreakPoint(b2);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B1]2;") === -1);
b1 = Debug.setBreakPoint(initializer, 0, 0);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B1]foo()") > 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === -1);
Debug.clearBreakPoint(b3);
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B1]foo()") === -1);
b2 = Debug.setBreakPoint(initializer, 1, 0);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B0]2;") > 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B1]foo()") > 0);
Debug.clearBreakPoint(b2);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B0]2;") === -1);
Debug.clearBreakPoint(b3);
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B1]foo()") === -1);
function t() {
class X {
[foo()] = 1;
}
}
b1 = Debug.setBreakPoint(t, 0, 0);
assertTrue(Debug.showBreakPoints(t).indexOf("[[B0]foo()] = 1;")> 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("[[B0]foo()] = 1;") === -1);
Checks Debugger.getPossibleBreakpoints for class fields
// Copyright 2017 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.
let x = |R|class {}
|_|x = |R|class {
x = |_|1;
y = |_|2|R|;
}
|_|x = |R|class {
x = |C|foo();
y = |_|2;
z = |C|bar()|R|;
}
|_|x = class {
x = |C|foo();
y = |_|2;
z = |C|bar()|R|;
constructor() {
this.|_|x;
|R|}
}
|_|x = class {
x = |C|foo();
y = |_|2;
constructor() {
this.|_|x;
|R|}
z = |C|bar()|R|;
}
|_|x = class {
x = |C|foo();
y = |_|2;
constructor() {
this.|_|x;
|R|}
z = |C|bar()|R|;
}
|_|x = |R|class {
x = |_|1;
foo() {|R|}
y = |_|2|R|;
}
|_|x = |R|class {
x = (function() {
|C|foo();
|R|})|C|();
y = (() => {
|C|bar();
|R|})|C|()|R|;
}
|_|x = |R|class {
x = |_|function() {
|C|foo();
|R|}|R|;
}
|_|x = |R|class {
x = |_|async function() {
|_|await |C|foo();
|R|}|R|;
}
|_|x = |R|class {
x = |_|() => {
|C|foo();
|R|};
y = |_|() => |C|bar()|R|;
}
|_|x = |R|class {
x = |_|async () => {
|_|await |C|foo();
|R|};
y = |_|async () => |_|await |C|bar()|R|;
}
|_|x = |R|class {
[|_|x] = |_|1;
[|C|foo()] = |_|2|R|;
}
|_|x = |R|class {
[|_|x] = |_|[...this]|R|;
}
|_|x = |R|class {
x;
[|C|foo()]|R|;
}
|_|x = |R|class {
x = |_|function*|_|() {
|_|yield 1;
|R|}|R|;
}
|_|x = |R|class {
static x = |_|1;
static y = |_|2|R|;
}
|_|x = |R|class {
static x = |C|foo();
static y = |_|2;
static z = |C|bar()|R|;
}
|_|x = class {
static x = |C|foo();
static y = |_|2;
static z = |C|bar()|R|;
constructor() {
this.|_|x;
|R|}
}
|_|x = class {
static x = |C|foo();
static y = |_|2;
constructor() {
this.|_|x;
|R|}
static z = |C|bar()|R|;
}
|_|x = |R|class {
static x = |_|1;
static foo() {|R|}
bar() {|R|}
static y = |_|2|R|;
}
|_|x = |R|class {
static x = (function() {
|C|foo();
|R|})|C|();
static y = (() => {
|C|bar();
|R|})|C|()|R|;
}
|_|x = |R|class {
static x = |_|function() {
|C|foo();
|R|}|R|;
}
|_|x = |R|class {
static x = |_|async function() {
|_|await |C|foo();
|R|}|R|;
}
|_|x = |R|class {
static x = |_|() => {
|C|foo();
|R|};
static y = |_|() => |C|bar()|R|;
}
|_|x = |R|class {
static x = |_|async () => {
|_|await |C|foo();
|R|};
static y = |_|async () => |_|await |C|bar()|R|;
}
|_|x = |R|class {
static [|_|x] = |_|1;
static [|C|foo()] = |_|2|R|;
}
|_|x = |R|class {
static [|_|x] = |_|[...this]|R|;
}
|_|x = |R|class {
static x;
static [|C|foo()]|R|;
}
|_|x = |R|class {
static x = |_|function*|_|() {
|_|yield 1;
|R|}|R|;
}
|_|x = |R|class {
static x = |_|1;
y = |_|2;
static [|_|z] = |_|3;
[|_|p] = |_|4;
static [|C|foo()] = |_|5|R|;
[|C|bar()] = |_|6|R|;
}
|R|
// Copyright 2018 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(
"Checks Debugger.getPossibleBreakpoints for class fields"
);
(async function() {
session.setupScriptMap();
await Protocol.Debugger.enable();
const source = utils.read(
"test/inspector/debugger/resources/break-locations-class-fields.js"
);
contextGroup.addScript(source);
const {
params: { scriptId }
} = await Protocol.Debugger.onceScriptParsed();
const {
result: { locations }
} = await Protocol.Debugger.getPossibleBreakpoints({
start: {
lineNumber: 0,
columnNumber: 0,
scriptId
}
});
session.logBreakLocations(locations);
InspectorTest.completeTest();
})();
// Copyright 2017 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.
let x = class {}
x = class {
x = 1;
y = 2;
}
x = class {
x = foo();
y = 2;
z = bar();
}
x = class {
x = foo();
y = 2;
z = bar();
constructor() {
this.x;
}
}
x = class {
x = foo();
y = 2;
constructor() {
this.x;
}
z = bar();
}
x = class {
x = foo();
y = 2;
constructor() {
this.x;
}
z = bar();
}
x = class {
x = 1;
foo() {}
y = 2;
}
x = class {
x = (function() {
foo();
})();
y = (() => {
bar();
})();
}
x = class {
x = function() {
foo();
};
}
x = class {
x = async function() {
await foo();
};
}
x = class {
x = () => {
foo();
};
y = () => bar();
}
x = class {
x = async () => {
await foo();
};
y = async () => await bar();
}
x = class {
[x] = 1;
[foo()] = 2;
}
x = class {
[x] = [...this];
}
x = class {
x;
[foo()];
}
x = class {
x = function*() {
yield 1;
};
}
x = class {
static x = 1;
static y = 2;
}
x = class {
static x = foo();
static y = 2;
static z = bar();
}
x = class {
static x = foo();
static y = 2;
static z = bar();
constructor() {
this.x;
}
}
x = class {
static x = foo();
static y = 2;
constructor() {
this.x;
}
static z = bar();
}
x = class {
static x = 1;
static foo() {}
bar() {}
static y = 2;
}
x = class {
static x = (function() {
foo();
})();
static y = (() => {
bar();
})();
}
x = class {
static x = function() {
foo();
};
}
x = class {
static x = async function() {
await foo();
};
}
x = class {
static x = () => {
foo();
};
static y = () => bar();
}
x = class {
static x = async () => {
await foo();
};
static y = async () => await bar();
}
x = class {
static [x] = 1;
static [foo()] = 2;
}
x = class {
static [x] = [...this];
}
x = class {
static x;
static [foo()];
}
x = class {
static x = function*() {
yield 1;
};
}
x = class {
static x = 1;
y = 2;
static [z] = 3;
[p] = 4;
static [foo()] = 5;
[bar()] = 6;
}
// Copyright 2018 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
class X {
[foo()] = 1;
}
*%(basename)s:8: ReferenceError: foo is not defined
[foo()] = 1;
^
ReferenceError: foo is not defined
at *%(basename)s:8:4
\ No newline at end of file
// Copyright 2018 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
//
// TODO(gsathya): Remove 'Function' from stack trace.
class X {
static x = foo();
}
*%(basename)s:10: ReferenceError: foo is not defined
static x = foo();
^
ReferenceError: foo is not defined
at Function.<static_fields_initializer> (*%(basename)s:10:14)
at *%(basename)s:1:1
\ No newline at end of file
// Copyright 2018 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
class X {
x = foo();
}
new X;
*%(basename)s:8: ReferenceError: foo is not defined
x = foo();
^
ReferenceError: foo is not defined
at X.<instance_fields_initializer> (*%(basename)s:8:7)
at new X (*%(basename)s:7:1)
at *%(basename)s:11:1
\ No newline at end of file
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