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;
......
......@@ -938,37 +938,44 @@ class BytecodeGenerator::OptionalChainNullLabelScope final {
namespace {
template <typename PropertyT>
struct Accessors : public ZoneObject {
Accessors() : getter(nullptr), setter(nullptr) {}
PropertyT* getter;
PropertyT* setter;
};
// A map from property names to getter/setter pairs allocated in the zone that
// also provides a way of accessing the pairs in the order they were first
// added so that the generated bytecode is always the same.
template <typename PropertyT>
class AccessorTable
: public base::TemplateHashMap<Literal, ObjectLiteral::Accessors,
: public base::TemplateHashMap<Literal, Accessors<PropertyT>,
bool (*)(void*, void*),
ZoneAllocationPolicy> {
public:
explicit AccessorTable(Zone* zone)
: base::TemplateHashMap<Literal, ObjectLiteral::Accessors,
: base::TemplateHashMap<Literal, Accessors<PropertyT>,
bool (*)(void*, void*), ZoneAllocationPolicy>(
Literal::Match, ZoneAllocationPolicy(zone)),
zone_(zone) {}
Iterator lookup(Literal* literal) {
Iterator it = find(literal, true, ZoneAllocationPolicy(zone_));
Accessors<PropertyT>* LookupOrInsert(Literal* key) {
auto it = this->find(key, true, ZoneAllocationPolicy(zone_));
if (it->second == nullptr) {
it->second = new (zone_) ObjectLiteral::Accessors();
ordered_accessors_.push_back({literal, it->second});
it->second = new (zone_) Accessors<PropertyT>();
ordered_accessors_.push_back({key, it->second});
}
return it;
return it->second;
}
const std::vector<std::pair<Literal*, ObjectLiteral::Accessors*>>&
const std::vector<std::pair<Literal*, Accessors<PropertyT>*>>&
ordered_accessors() {
return ordered_accessors_;
}
private:
std::vector<std::pair<Literal*, ObjectLiteral::Accessors*>>
ordered_accessors_;
std::vector<std::pair<Literal*, Accessors<PropertyT>*>> ordered_accessors_;
Zone* zone_;
};
......@@ -1998,41 +2005,6 @@ bool BytecodeGenerator::ShouldOptimizeAsOneShot() const {
info()->literal()->is_oneshot_iife();
}
void BytecodeGenerator::BuildPrivateClassMemberNameAssignment(
ClassLiteral::Property* property) {
DCHECK(property->is_private());
switch (property->kind()) {
case ClassLiteral::Property::FIELD: {
// Create the private name symbols for fields during class
// evaluation and store them on the context. These will be
// used as keys later during instance or static initialization.
RegisterAllocationScope private_name_register_scope(this);
Register private_name = register_allocator()->NewRegister();
VisitForRegisterValue(property->key(), private_name);
builder()
->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
.StoreAccumulatorInRegister(private_name)
.CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name);
DCHECK_NOT_NULL(property->private_name_var());
BuildVariableAssignment(property->private_name_var(), Token::INIT,
HoleCheckMode::kElided);
break;
}
case ClassLiteral::Property::METHOD: {
// Create the closures for private methods.
VisitForAccumulatorValue(property->value());
BuildVariableAssignment(property->private_name_var(), Token::INIT,
HoleCheckMode::kElided);
break;
}
case ClassLiteral::Property::GETTER:
case ClassLiteral::Property::SETTER: {
// TODO(joyee): Private accessors are not yet supported.
// Make them noops for now.
}
}
}
void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
size_t class_boilerplate_entry =
builder()->AllocateDeferredConstantPoolEntry();
......@@ -2041,6 +2013,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
VisitDeclarations(expr->scope()->declarations());
Register class_constructor = register_allocator()->NewRegister();
AccessorTable<ClassLiteral::Property> private_accessors(zone());
{
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewGrowableRegisterList();
......@@ -2098,7 +2071,44 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
}
if (property->is_private()) {
BuildPrivateClassMemberNameAssignment(property);
// Assign private class member's name variables.
switch (property->kind()) {
case ClassLiteral::Property::FIELD: {
// Create the private name symbols for fields during class
// evaluation and store them on the context. These will be
// used as keys later during instance or static initialization.
RegisterAllocationScope private_name_register_scope(this);
Register private_name = register_allocator()->NewRegister();
VisitForRegisterValue(property->key(), private_name);
builder()
->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
.StoreAccumulatorInRegister(private_name)
.CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name);
DCHECK_NOT_NULL(property->private_name_var());
BuildVariableAssignment(property->private_name_var(), Token::INIT,
HoleCheckMode::kElided);
break;
}
case ClassLiteral::Property::METHOD: {
// Create the closures for private methods.
VisitForAccumulatorValue(property->value());
BuildVariableAssignment(property->private_name_var(), Token::INIT,
HoleCheckMode::kElided);
break;
}
case ClassLiteral::Property::GETTER: {
Literal* key = property->key()->AsLiteral();
DCHECK_NULL(private_accessors.LookupOrInsert(key)->getter);
private_accessors.LookupOrInsert(key)->getter = property;
break;
}
case ClassLiteral::Property::SETTER: {
Literal* key = property->key()->AsLiteral();
DCHECK_NULL(private_accessors.LookupOrInsert(key)->setter);
private_accessors.LookupOrInsert(key)->setter = property;
break;
}
}
// The private fields are initialized in the initializer function and
// the private brand for the private methods are initialized in the
// constructor instead.
......@@ -2145,14 +2155,13 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
BuildVariableAssignment(expr->scope()->brand(), Token::INIT,
HoleCheckMode::kElided);
// Store the home object for any private methods or accessors that need
// Store the home object for any private methods that need
// them. We do this here once the prototype and brand symbol has
// been created.
// been created. Private accessors have their home object set later
// when they are defined.
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);
......@@ -2160,6 +2169,22 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
VisitSetHomeObject(func, prototype, property);
}
}
// Define accessors, using only a single call to the runtime for each pair
// of corresponding getters and setters.
for (auto accessors : private_accessors.ordered_accessors()) {
RegisterAllocationScope inner_register_scope(this);
RegisterList accessors_reg = register_allocator()->NewRegisterList(2);
ClassLiteral::Property* getter = accessors.second->getter;
ClassLiteral::Property* setter = accessors.second->setter;
VisitLiteralAccessor(prototype, getter, accessors_reg[0]);
VisitLiteralAccessor(prototype, setter, accessors_reg[1]);
builder()->CallRuntime(Runtime::kCreatePrivateAccessors, accessors_reg);
Variable* var = getter != nullptr ? getter->private_name_var()
: setter->private_name_var();
DCHECK_NOT_NULL(var);
BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided);
}
}
if (expr->instance_members_initializer_function() != nullptr) {
......@@ -2475,7 +2500,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
// Store computed values into the literal.
AccessorTable accessor_table(zone());
AccessorTable<ObjectLiteral::Property> accessor_table(zone());
for (; property_index < expr->properties()->length(); property_index++) {
ObjectLiteral::Property* property = expr->properties()->at(property_index);
if (property->is_computed_name()) break;
......@@ -2544,12 +2569,12 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
case ObjectLiteral::Property::GETTER:
if (property->emit_store()) {
accessor_table.lookup(key)->second->getter = property;
accessor_table.LookupOrInsert(key)->getter = property;
}
break;
case ObjectLiteral::Property::SETTER:
if (property->emit_store()) {
accessor_table.lookup(key)->second->setter = property;
accessor_table.LookupOrInsert(key)->setter = property;
}
break;
}
......@@ -2562,8 +2587,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
RegisterList args = register_allocator()->NewRegisterList(5);
builder()->MoveRegister(literal, args[0]);
VisitForRegisterValue(accessors.first, args[1]);
VisitObjectLiteralAccessor(literal, accessors.second->getter, args[2]);
VisitObjectLiteralAccessor(literal, accessors.second->setter, args[3]);
VisitLiteralAccessor(literal, accessors.second->getter, args[2]);
VisitLiteralAccessor(literal, accessors.second->setter, args[3]);
builder()
->LoadLiteral(Smi::FromInt(NONE))
.StoreAccumulatorInRegister(args[4])
......@@ -5793,8 +5818,9 @@ void BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) {
builder()->CreateCatchContext(exception, scope);
}
void BytecodeGenerator::VisitObjectLiteralAccessor(
Register home_object, ObjectLiteralProperty* property, Register value_out) {
void BytecodeGenerator::VisitLiteralAccessor(Register home_object,
LiteralProperty* property,
Register value_out) {
if (property == nullptr) {
builder()->LoadNull().StoreAccumulatorInRegister(value_out);
} else {
......
......@@ -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) \
......
......@@ -15,9 +15,9 @@ snippet: "
}
}
"
frame size: 7
frame size: 8
parameter count: 1
bytecode array length: 49
bytecode array length: 68
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
......@@ -36,6 +36,12 @@ bytecodes: [
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(CreateClosure), U8(4), U8(1), U8(2),
B(Star), R(6),
B(CreateClosure), U8(5), U8(2), U8(2),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
......@@ -46,6 +52,8 @@ constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......@@ -58,9 +66,9 @@ snippet: "
}
}
"
frame size: 7
frame size: 8
parameter count: 1
bytecode array length: 49
bytecode array length: 65
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
......@@ -79,6 +87,12 @@ bytecodes: [
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(CreateClosure), U8(4), U8(1), U8(2),
B(Star), R(6),
B(LdaNull),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
......@@ -89,6 +103,7 @@ constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["B"],
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......@@ -101,9 +116,9 @@ snippet: "
}
}
"
frame size: 7
frame size: 8
parameter count: 1
bytecode array length: 49
bytecode array length: 65
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
......@@ -122,6 +137,12 @@ bytecodes: [
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(LdaNull),
B(Star), R(6),
B(CreateClosure), U8(4), U8(1), U8(2),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
......@@ -132,6 +153,7 @@ constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......@@ -150,9 +172,9 @@ snippet: "
}
}
"
frame size: 9
frame size: 10
parameter count: 1
bytecode array length: 95
bytecode array length: 133
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
......@@ -171,23 +193,35 @@ bytecodes: [
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
B(StaCurrentContextSlot), U8(5),
B(CreateClosure), U8(4), U8(1), U8(2),
B(Star), R(8),
B(CreateClosure), U8(5), U8(2), U8(2),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(8), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(4),
B(Mov), R(3), R(0),
/* 38 E> */ B(CreateBlockContext), U8(4),
/* 38 E> */ B(CreateBlockContext), U8(6),
B(PushContext), R(4),
/* 118 E> */ B(CreateClosure), U8(6), U8(1), U8(2),
/* 118 E> */ B(CreateClosure), U8(8), U8(3), U8(2),
B(Star), R(5),
B(LdaConstant), U8(5),
B(LdaConstant), U8(7),
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(LdaConstant), U8(9),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
B(StaCurrentContextSlot), U8(5),
B(CreateClosure), U8(10), U8(4), U8(2),
B(Star), R(8),
B(CreateClosure), U8(11), U8(5), U8(2),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(8), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(4),
B(Mov), R(2), R(1),
B(LdaUndefined),
......@@ -198,10 +232,166 @@ constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"],
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"],
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
---
snippet: "
{
class A { foo() {} }
class C extends A {
get #a() { return super.foo; }
}
new C();
}
"
frame size: 10
parameter count: 1
bytecode array length: 119
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(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(CreateClosure), U8(8), U8(3), U8(2),
B(Star), R(8),
B(Ldar), R(6),
B(StaNamedProperty), R(8), U8(9), U8(0),
B(LdaNull),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(8), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(4),
B(Mov), R(2), R(1),
/* 122 S> */ B(Ldar), R(1),
/* 122 E> */ B(Construct), R(1), R(0), U8(0), U8(2),
B(LdaUndefined),
/* 133 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,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
SHARED_FUNCTION_INFO_TYPE,
SYMBOL_TYPE,
]
handlers: [
]
---
snippet: "
{
class A { foo(val) {} }
class C extends A {
set #a(val) { super.foo(val); }
}
new C();
}
"
frame size: 10
parameter count: 1
bytecode array length: 119
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),
/* 80 E> */ B(CreateClosure), U8(6), U8(2), 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(LdaNull),
B(Star), R(8),
B(CreateClosure), U8(8), U8(3), U8(2),
B(Star), R(9),
B(Ldar), R(6),
B(StaNamedProperty), R(9), U8(9), U8(0),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(8), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(4),
B(Mov), R(2), R(1),
/* 126 S> */ B(Ldar), R(1),
/* 126 E> */ B(Construct), R(1), R(0), U8(0), U8(2),
B(LdaUndefined),
/* 137 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,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
SHARED_FUNCTION_INFO_TYPE,
SYMBOL_TYPE,
]
handlers: [
]
......
......@@ -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