Commit 77d50cd8 authored by Joyee Cheung's avatar Joyee Cheung Committed by Commit Bot

[class] implement private accessor declarations

This patch implements the declaration of private accessors.
When iterating over the class properties, we track private
accessors associated with the same name in a ZoneHashMap.
Once we get to all the necessary components for a private name
(we know statically whether we should expect only a setter,
only a getter, or both), we emit a call to a runtime function
`CreatePrivateAccessors` that creates an AccessorPair, and
store the components in it. The AccessorPair is then associated
with the private name variable and stored in the context
for later retrieval when the private accessors are accessed.

Design doc: https://docs.google.com/document/d/10W4begYfs7lmldSqBoQBBt_BKamgT8igqxF9u50RGrI/edit

Bug: v8:8330
Change-Id: Ie6d3882507d143b1f645d7ae82b21b7358656e89
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1725670
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63284}
parent dd547367
......@@ -1369,12 +1369,6 @@ class ObjectLiteral final : public AggregateLiteral {
static_cast<int>(AggregateLiteral::kNeedsInitialAllocationSite) <
static_cast<int>(kFastElements));
struct Accessors: public ZoneObject {
Accessors() : getter(nullptr), setter(nullptr) {}
ObjectLiteralProperty* getter;
ObjectLiteralProperty* setter;
};
private:
friend class AstNodeFactory;
......
This diff is collapsed.
......@@ -299,7 +299,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitRestArgumentsArray(Variable* rest);
void VisitCallSuper(Call* call);
void BuildThrowPrivateMethodWriteError(const AstRawString* name);
void BuildPrivateClassMemberNameAssignment(ClassLiteral::Property* property);
void BuildClassLiteral(ClassLiteral* expr, Register name);
void VisitClassLiteral(ClassLiteral* expr, Register name);
void VisitNewTargetVariable(Variable* variable);
......@@ -311,9 +310,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitBlockDeclarationsAndStatements(Block* stmt);
void VisitSetHomeObject(Register value, Register home_object,
LiteralProperty* property);
void VisitObjectLiteralAccessor(Register home_object,
ObjectLiteralProperty* property,
Register value_out);
void VisitLiteralAccessor(Register home_object, LiteralProperty* property,
Register value_out);
void VisitForInAssignment(Expression* expr);
void VisitModuleNamespaceImports();
......
......@@ -1216,6 +1216,32 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyDescriptor) {
return *desc.ToPropertyDescriptorObject(isolate);
}
RUNTIME_FUNCTION(Runtime_LoadPrivateSetter) {
HandleScope scope(isolate);
DCHECK_EQ(args.length(), 1);
CONVERT_ARG_HANDLE_CHECKED(AccessorPair, pair, 0);
DCHECK(pair->setter().IsJSFunction());
return pair->setter();
}
RUNTIME_FUNCTION(Runtime_LoadPrivateGetter) {
HandleScope scope(isolate);
DCHECK_EQ(args.length(), 1);
CONVERT_ARG_HANDLE_CHECKED(AccessorPair, pair, 0);
DCHECK(pair->getter().IsJSFunction());
return pair->getter();
}
RUNTIME_FUNCTION(Runtime_CreatePrivateAccessors) {
HandleScope scope(isolate);
DCHECK_EQ(args.length(), 2);
DCHECK(args[0].IsNull() || args[0].IsJSFunction());
DCHECK(args[1].IsNull() || args[1].IsJSFunction());
Handle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
pair->SetComponents(args[0], args[1]);
return *pair;
}
RUNTIME_FUNCTION(Runtime_AddPrivateBrand) {
HandleScope scope(isolate);
DCHECK_EQ(args.length(), 2);
......
......@@ -107,9 +107,12 @@ bool Runtime::NeedsExactContext(FunctionId id) {
return false;
case Runtime::kAddPrivateField:
case Runtime::kAddPrivateBrand:
case Runtime::kCreatePrivateAccessors:
case Runtime::kCopyDataProperties:
case Runtime::kCreateDataProperty:
case Runtime::kCreatePrivateNameSymbol:
case Runtime::kLoadPrivateGetter:
case Runtime::kLoadPrivateSetter:
case Runtime::kReThrow:
case Runtime::kThrow:
case Runtime::kThrowApplyNonFunction:
......
......@@ -284,6 +284,7 @@ namespace internal {
F(CopyDataPropertiesWithExcludedProperties, -1 /* >= 1 */, 1) \
I(CreateDataProperty, 3, 1) \
I(CreateIterResultObject, 2, 1) \
F(CreatePrivateAccessors, 2, 1) \
F(DefineAccessorPropertyUnchecked, 5, 1) \
F(DefineDataPropertyInLiteral, 6, 1) \
F(DefineGetterPropertyUnchecked, 4, 1) \
......@@ -304,6 +305,8 @@ namespace internal {
F(JSReceiverGetPrototypeOf, 1, 1) \
F(JSReceiverSetPrototypeOfDontThrow, 2, 1) \
F(JSReceiverSetPrototypeOfThrow, 2, 1) \
F(LoadPrivateGetter, 1, 1) \
F(LoadPrivateSetter, 1, 1) \
F(NewObject, 2, 1) \
F(ObjectCreate, 2, 1) \
F(ObjectEntries, 1, 1) \
......
......@@ -2804,6 +2804,65 @@ TEST(PrivateMethods) {
i::FLAG_harmony_private_methods = old_methods_flag;
}
TEST(PrivateAccessors) {
bool old_methods_flag = i::FLAG_harmony_private_methods;
i::FLAG_harmony_private_methods = true;
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = {
"{\n"
" class A {\n"
" get #a() { return 1; }\n"
" set #a(val) { }\n"
" }\n"
"}\n",
"{\n"
" class B {\n"
" get #b() { return 1; }\n"
" }\n"
"}\n",
"{\n"
" class C {\n"
" set #c(val) { }\n"
" }\n"
"}\n",
"{\n"
" class D {\n"
" get #d() { return 1; }\n"
" set #d(val) { }\n"
" }\n"
"\n"
" class E extends D {\n"
" get #e() { return 2; }\n"
" set #e(val) { }\n"
" }\n"
"}\n",
"{\n"
" class A { foo() {} }\n"
" class C extends A {\n"
" get #a() { return super.foo; }\n"
" }\n"
" new C();\n"
"}\n",
"{\n"
" class A { foo(val) {} }\n"
" class C extends A {\n"
" set #a(val) { super.foo(val); }\n"
" }\n"
" new C();\n"
"}\n"};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("PrivateAccessors.golden")));
i::FLAG_harmony_private_methods = old_methods_flag;
}
TEST(StaticClassFields) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
......
......@@ -16,6 +16,26 @@
new C;
}
// Accessing super in private accessors.
{
class A { foo(val) {} }
class C extends A {
set #a(val) { super.foo(val); }
}
new C();
class D extends A {
get #a() { return super.foo; }
}
new D();
class E extends A {
set #a(val) { super.foo(val); }
get #a() { return super.foo; }
}
new E();
}
// Nested private accessors.
{
class C {
......
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