Commit 919ee633 authored by Joyee Cheung's avatar Joyee Cheung Committed by Commit Bot

[class] fix super access in private methods

This patch stores the home objects in private methods that
access super properties.

Bug: v8:8330
Change-Id: I2507fda0bd70183f02d162ec50a5be76c248f0ff
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1724900Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Cr-Commit-Position: refs/heads/master@{#63113}
parent 8eadbe5c
......@@ -2424,6 +2424,11 @@ class ClassLiteralProperty final : public LiteralProperty {
return private_or_computed_name_var_;
}
bool NeedsHomeObjectOnClassPrototype() const {
return is_private() && kind_ == METHOD &&
FunctionLiteral::NeedsHomeObject(value_);
}
private:
friend class AstNodeFactory;
......
......@@ -2124,6 +2124,22 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
.CallRuntime(Runtime::kCreatePrivateNameSymbol, brand);
BuildVariableAssignment(expr->scope()->brand(), Token::INIT,
HoleCheckMode::kElided);
// Store the home object for any private methods or accessors that need
// them. We do this here once the prototype and brand symbol has
// been created.
for (int i = 0; i < expr->properties()->length(); i++) {
RegisterAllocationScope register_scope(this);
ClassLiteral::Property* property = expr->properties()->at(i);
// TODO(joyee): do the same for private accessors when they are
// implemented.
if (property->NeedsHomeObjectOnClassPrototype()) {
Register func = register_allocator()->NewRegister();
BuildVariableLoad(property->private_name_var(), HoleCheckMode::kElided);
builder()->StoreAccumulatorInRegister(func);
VisitSetHomeObject(func, prototype, property);
}
}
}
if (expr->instance_members_initializer_function() != nullptr) {
......
#
# Autogenerated by generate-bytecode-expectations.
#
---
wrap: yes
private methods: yes
---
snippet: "
{
class A {
get #a() { return 1; }
set #a(val) { }
}
}
"
frame size: 7
parameter count: 1
bytecode array length: 49
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(1),
B(LdaConstant), U8(3),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
/* 101 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
]
handlers: [
]
---
snippet: "
{
class B {
get #b() { return 1; }
}
}
"
frame size: 7
parameter count: 1
bytecode array length: 49
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(1),
B(LdaConstant), U8(3),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
/* 81 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["B"],
]
handlers: [
]
---
snippet: "
{
class C {
set #c(val) { }
}
}
"
frame size: 7
parameter count: 1
bytecode array length: 49
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(1),
B(LdaConstant), U8(3),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
/* 74 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
]
handlers: [
]
---
snippet: "
{
class D {
get #d() { return 1; }
set #d(val) { }
}
class E extends D {
get #e() { return 2; }
set #e(val) { }
}
}
"
frame size: 9
parameter count: 1
bytecode array length: 95
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(4),
B(LdaTheHole),
B(Star), R(8),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(5),
B(LdaConstant), U8(1),
B(Star), R(6),
B(Mov), R(5), R(7),
B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
B(Star), R(6),
B(Mov), R(7), R(3),
B(LdaConstant), U8(3),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
B(StaCurrentContextSlot), U8(5),
B(PopContext), R(4),
B(Mov), R(3), R(0),
/* 38 E> */ B(CreateBlockContext), U8(4),
B(PushContext), R(4),
/* 118 E> */ B(CreateClosure), U8(6), U8(1), U8(2),
B(Star), R(5),
B(LdaConstant), U8(5),
B(Star), R(6),
B(Mov), R(5), R(7),
B(Mov), R(3), R(8),
B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
B(Star), R(6),
B(Mov), R(7), R(2),
B(LdaConstant), U8(7),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
B(StaCurrentContextSlot), U8(5),
B(PopContext), R(4),
B(Mov), R(2), R(1),
B(LdaUndefined),
/* 175 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"],
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"],
]
handlers: [
]
......@@ -158,3 +158,86 @@ constant pool: [
handlers: [
]
---
snippet: "
{
class A { foo() {} }
class C extends A {
#m() { return super.foo; }
fn() { return this.#m(); }
}
new C().fn();
}
"
frame size: 10
parameter count: 1
bytecode array length: 131
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(4),
B(LdaTheHole),
B(Star), R(8),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(5),
B(LdaConstant), U8(1),
B(Star), R(6),
B(CreateClosure), U8(3), U8(1), U8(2),
B(Star), R(9),
B(Mov), R(5), R(7),
B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(4),
B(Star), R(6),
B(Mov), R(7), R(3),
B(PopContext), R(4),
B(Mov), R(3), R(0),
/* 38 E> */ B(CreateBlockContext), U8(4),
B(PushContext), R(4),
/* 77 E> */ B(CreateClosure), U8(6), U8(2), U8(2),
B(Star), R(5),
B(LdaConstant), U8(5),
B(Star), R(6),
B(CreateClosure), U8(7), U8(3), U8(2),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(8), U8(4), U8(2),
B(Star), R(9),
B(Mov), R(5), R(7),
B(Mov), R(3), R(8),
B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(4),
B(Star), R(6),
B(Mov), R(7), R(2),
B(LdaConstant), U8(9),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
B(StaCurrentContextSlot), U8(5),
B(LdaCurrentContextSlot), U8(4),
B(Star), R(8),
B(Ldar), R(6),
B(StaNamedProperty), R(8), U8(10), U8(0),
B(PopContext), R(4),
B(Mov), R(2), R(1),
/* 149 S> */ B(Ldar), R(1),
/* 149 E> */ B(Construct), R(5), R(0), U8(0), U8(2),
B(Star), R(5),
/* 157 E> */ B(LdaNamedProperty), R(5), U8(11), U8(4),
B(Star), R(4),
/* 157 E> */ B(CallProperty0), R(4), R(5), U8(6),
B(LdaUndefined),
/* 165 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["fn"],
]
handlers: [
]
......@@ -2788,6 +2788,15 @@ TEST(PrivateMethods) {
"\n"
" const e = new E;\n"
" e.callE();\n"
"}\n",
"{\n"
" class A { foo() {} }\n"
" class C extends A {\n"
" #m() { return super.foo; }\n"
" fn() { return this.#m(); }\n"
" }\n"
" new C().fn();\n"
"}\n"};
CHECK(CompareTexts(BuildActual(printer, snippets),
......
......@@ -281,3 +281,17 @@
new D;
new E;
}
// Super access within private methods.
{
class A {
foo() { return 1; }
}
class C extends A {
#m() { return super.foo; }
fn() { return this.#m()(); }
}
assertEquals(1, new C().fn());
}
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