[class] implement private method declarations
This patch implements the declarations of private methods, the access of private methods would be left to a future patch. When a private methods declaration is encountered, we now: - Create a brand symbol during class evaluation and store it in the context. - Create the closures for the private methods - Load the brand from the context and store it in the instance in the constructor. Design: https://docs.google.com/document/d/1T-Ql6HOIH2U_8YjWkwK2rTfywwb7b3Qe8d3jkz72KwA/edit# Bug: v8:8330 Change-Id: I2d695cbdc8a7367ddc7620d627b318f779d36150 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1568708 Commit-Queue: Joyee Cheung <joyee@igalia.com> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#61387}
This commit is contained in:
parent
db7f61d694
commit
b9191bd355
@ -201,6 +201,7 @@ class AstBigInt {
|
||||
F(bigint, "bigint") \
|
||||
F(boolean, "boolean") \
|
||||
F(computed, "<computed>") \
|
||||
F(dot_brand, ".brand") \
|
||||
F(constructor, "constructor") \
|
||||
F(default, "default") \
|
||||
F(done, "done") \
|
||||
|
@ -282,6 +282,17 @@ std::unique_ptr<char[]> FunctionLiteral::GetDebugName() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FunctionLiteral::requires_brand_initialization() const {
|
||||
Scope* outer = scope_->outer_scope();
|
||||
|
||||
// If there are no variables declared in the outer scope other than
|
||||
// the class name variable, the outer class scope may be elided when
|
||||
// the function is deserialized after preparsing.
|
||||
if (!outer->is_class_scope()) return false;
|
||||
|
||||
return outer->AsClassScope()->brand() != nullptr;
|
||||
}
|
||||
|
||||
ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
|
||||
Kind kind, bool is_computed_name)
|
||||
: LiteralProperty(key, value, is_computed_name),
|
||||
|
@ -2342,6 +2342,8 @@ class FunctionLiteral final : public Expression {
|
||||
return RequiresInstanceMembersInitializer::decode(bit_field_);
|
||||
}
|
||||
|
||||
bool requires_brand_initialization() const;
|
||||
|
||||
ProducedPreparseData* produced_preparse_data() const {
|
||||
return produced_preparse_data_;
|
||||
}
|
||||
@ -2435,12 +2437,10 @@ class ClassLiteralProperty final : public LiteralProperty {
|
||||
}
|
||||
|
||||
void set_private_name_var(Variable* var) {
|
||||
DCHECK_EQ(FIELD, kind());
|
||||
DCHECK(is_private());
|
||||
private_or_computed_name_var_ = var;
|
||||
}
|
||||
Variable* private_name_var() const {
|
||||
DCHECK_EQ(FIELD, kind());
|
||||
DCHECK(is_private());
|
||||
return private_or_computed_name_var_;
|
||||
}
|
||||
@ -2476,7 +2476,7 @@ class ClassLiteral final : public Expression {
|
||||
public:
|
||||
typedef ClassLiteralProperty Property;
|
||||
|
||||
Scope* scope() const { return scope_; }
|
||||
ClassScope* scope() const { return scope_; }
|
||||
Variable* class_variable() const { return class_variable_; }
|
||||
Expression* extends() const { return extends_; }
|
||||
FunctionLiteral* constructor() const { return constructor_; }
|
||||
@ -2508,7 +2508,7 @@ class ClassLiteral final : public Expression {
|
||||
private:
|
||||
friend class AstNodeFactory;
|
||||
|
||||
ClassLiteral(Scope* scope, Variable* class_variable, Expression* extends,
|
||||
ClassLiteral(ClassScope* scope, Variable* class_variable, Expression* extends,
|
||||
FunctionLiteral* constructor, ZonePtrList<Property>* properties,
|
||||
FunctionLiteral* static_fields_initializer,
|
||||
FunctionLiteral* instance_members_initializer_function,
|
||||
@ -2531,7 +2531,7 @@ class ClassLiteral final : public Expression {
|
||||
}
|
||||
|
||||
int end_position_;
|
||||
Scope* scope_;
|
||||
ClassScope* scope_;
|
||||
Variable* class_variable_;
|
||||
Expression* extends_;
|
||||
FunctionLiteral* constructor_;
|
||||
@ -3233,7 +3233,7 @@ class AstNodeFactory final {
|
||||
}
|
||||
|
||||
ClassLiteral* NewClassLiteral(
|
||||
Scope* scope, Variable* variable, Expression* extends,
|
||||
ClassScope* scope, Variable* variable, Expression* extends,
|
||||
FunctionLiteral* constructor,
|
||||
ZonePtrList<ClassLiteral::Property>* properties,
|
||||
FunctionLiteral* static_fields_initializer,
|
||||
|
@ -1054,12 +1054,17 @@ void AstPrinter::VisitClassLiteral(ClassLiteral* node) {
|
||||
if (node->extends() != nullptr) {
|
||||
PrintIndentedVisit("EXTENDS", node->extends());
|
||||
}
|
||||
Scope* outer = node->constructor()->scope()->outer_scope();
|
||||
if (outer->is_class_scope()) {
|
||||
Variable* brand = outer->AsClassScope()->brand();
|
||||
PrintLiteralWithModeIndented("BRAND", brand, brand->raw_name());
|
||||
}
|
||||
if (node->static_fields_initializer() != nullptr) {
|
||||
PrintIndentedVisit("STATIC FIELDS INITIALIZER",
|
||||
node->static_fields_initializer());
|
||||
}
|
||||
if (node->instance_members_initializer_function() != nullptr) {
|
||||
PrintIndentedVisit("INSTANCE ELEMENTS INITIALIZER",
|
||||
PrintIndentedVisit("INSTANCE MEMBERS INITIALIZER",
|
||||
node->instance_members_initializer_function());
|
||||
}
|
||||
PrintClassProperties(node->properties());
|
||||
@ -1067,7 +1072,7 @@ void AstPrinter::VisitClassLiteral(ClassLiteral* node) {
|
||||
|
||||
void AstPrinter::VisitInitializeClassMembersStatement(
|
||||
InitializeClassMembersStatement* node) {
|
||||
IndentedScope indent(this, "INITIALIZE CLASS ELEMENTS", node->position());
|
||||
IndentedScope indent(this, "INITIALIZE CLASS MEMBERS", node->position());
|
||||
PrintClassProperties(node->fields());
|
||||
}
|
||||
|
||||
|
@ -145,9 +145,16 @@ ClassScope::ClassScope(Zone* zone, Scope* outer_scope)
|
||||
set_language_mode(LanguageMode::kStrict);
|
||||
}
|
||||
|
||||
ClassScope::ClassScope(Zone* zone, Handle<ScopeInfo> scope_info)
|
||||
ClassScope::ClassScope(Zone* zone, AstValueFactory* ast_value_factory,
|
||||
Handle<ScopeInfo> scope_info)
|
||||
: Scope(zone, CLASS_SCOPE, scope_info) {
|
||||
set_language_mode(LanguageMode::kStrict);
|
||||
if (scope_info->HasClassBrand()) {
|
||||
Variable* brand =
|
||||
LookupInScopeInfo(ast_value_factory->dot_brand_string(), this);
|
||||
DCHECK_NOT_NULL(brand);
|
||||
EnsureRareData()->brand = brand;
|
||||
}
|
||||
}
|
||||
|
||||
Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info)
|
||||
@ -333,7 +340,8 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
|
||||
outer_scope = new (zone)
|
||||
DeclarationScope(zone, EVAL_SCOPE, handle(scope_info, isolate));
|
||||
} else if (scope_info->scope_type() == CLASS_SCOPE) {
|
||||
outer_scope = new (zone) ClassScope(zone, handle(scope_info, isolate));
|
||||
outer_scope = new (zone)
|
||||
ClassScope(zone, ast_value_factory, handle(scope_info, isolate));
|
||||
} else if (scope_info->scope_type() == BLOCK_SCOPE) {
|
||||
if (scope_info->is_declaration_scope()) {
|
||||
outer_scope = new (zone)
|
||||
@ -1710,6 +1718,11 @@ void Scope::Print(int n) {
|
||||
if (class_scope->rare_data_ != nullptr) {
|
||||
PrintMap(n1, "// private name vars:\n",
|
||||
&(class_scope->rare_data_->private_name_map), true, function);
|
||||
Variable* brand = class_scope->brand();
|
||||
if (brand != nullptr) {
|
||||
Indent(n1, "// brand var:\n");
|
||||
PrintVar(n1, brand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2512,5 +2525,21 @@ VariableProxy* ClassScope::ResolvePrivateNamesPartially() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Variable* ClassScope::DeclareBrandVariable(AstValueFactory* ast_value_factory,
|
||||
int class_token_pos) {
|
||||
DCHECK_IMPLIES(rare_data_ != nullptr, rare_data_->brand == nullptr);
|
||||
bool was_added;
|
||||
Variable* brand = Declare(zone(), ast_value_factory->dot_brand_string(),
|
||||
VariableMode::kConst, NORMAL_VARIABLE,
|
||||
InitializationFlag::kNeedsInitialization,
|
||||
MaybeAssignedFlag::kMaybeAssigned, &was_added);
|
||||
DCHECK(was_added);
|
||||
brand->ForceContextAllocation();
|
||||
brand->set_is_used();
|
||||
EnsureRareData()->brand = brand;
|
||||
brand->set_initializer_position(class_token_pos);
|
||||
return brand;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -1169,7 +1169,8 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
|
||||
public:
|
||||
ClassScope(Zone* zone, Scope* outer_scope);
|
||||
// Deserialization.
|
||||
ClassScope(Zone* zone, Handle<ScopeInfo> scope_info);
|
||||
ClassScope(Zone* zone, AstValueFactory* ast_value_factory,
|
||||
Handle<ScopeInfo> scope_info);
|
||||
|
||||
// Declare a private name in the private name map and add it to the
|
||||
// local variables of this scope.
|
||||
@ -1205,6 +1206,11 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
|
||||
// and the current tail.
|
||||
void MigrateUnresolvedPrivateNameTail(AstNodeFactory* ast_node_factory,
|
||||
UnresolvedList::Iterator tail);
|
||||
Variable* DeclareBrandVariable(AstValueFactory* ast_value_factory,
|
||||
int class_token_pos);
|
||||
Variable* brand() {
|
||||
return rare_data_ == nullptr ? nullptr : rare_data_->brand;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Scope;
|
||||
@ -1222,6 +1228,7 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
|
||||
explicit RareData(Zone* zone) : private_name_map(zone) {}
|
||||
UnresolvedList unresolved_private_names;
|
||||
VariableMap private_name_map;
|
||||
Variable* brand = nullptr;
|
||||
};
|
||||
|
||||
V8_INLINE RareData* EnsureRareData() {
|
||||
|
@ -147,6 +147,7 @@
|
||||
V(_, disjunction_string, "disjunction") \
|
||||
V(_, display_name_string, "displayName") \
|
||||
V(_, done_string, "done") \
|
||||
V(_, dot_brand_string, ".brand") \
|
||||
V(_, dot_catch_string, ".catch") \
|
||||
V(_, dot_default_string, ".default") \
|
||||
V(_, dot_for_string, ".for") \
|
||||
|
@ -1156,11 +1156,16 @@ void BytecodeGenerator::GenerateBytecodeBody() {
|
||||
builder()->StackCheck(info()->literal()->start_position());
|
||||
|
||||
// The derived constructor case is handled in VisitCallSuper.
|
||||
if (IsBaseConstructor(function_kind()) &&
|
||||
info()->literal()->requires_instance_members_initializer()) {
|
||||
if (IsBaseConstructor(function_kind())) {
|
||||
if (info()->literal()->requires_brand_initialization()) {
|
||||
BuildPrivateBrandInitialization(builder()->Receiver());
|
||||
}
|
||||
|
||||
if (info()->literal()->requires_instance_members_initializer()) {
|
||||
BuildInstanceMemberInitialization(Register::function_closure(),
|
||||
builder()->Receiver());
|
||||
}
|
||||
}
|
||||
|
||||
// Visit statements in the function body.
|
||||
VisitStatements(info()->literal()->body());
|
||||
@ -1929,6 +1934,39 @@ 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;
|
||||
}
|
||||
default:
|
||||
// TODO(joyee): Private accessors are not yet supported.
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
|
||||
size_t class_boilerplate_entry =
|
||||
builder()->AllocateDeferredConstantPoolEntry();
|
||||
@ -1993,19 +2031,15 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
|
||||
}
|
||||
}
|
||||
|
||||
if (property->kind() == ClassLiteral::Property::FIELD) {
|
||||
if (property->is_private()) {
|
||||
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);
|
||||
BuildPrivateClassMemberNameAssignment(property);
|
||||
// The private fields are initialized in the initializer function and
|
||||
// the private brand for the private methods are initialized in the
|
||||
// constructor instead.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property->kind() == ClassLiteral::Property::FIELD) {
|
||||
// We don't compute field's value here, but instead do it in the
|
||||
// initializer function.
|
||||
continue;
|
||||
@ -2029,6 +2063,23 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
|
||||
HoleCheckMode::kElided);
|
||||
}
|
||||
|
||||
// Create the class brand symbol and store it on the context
|
||||
// during class evaluation. This will be stored in the
|
||||
// receiver later in the constructor.
|
||||
if (expr->scope()->brand() != nullptr) {
|
||||
Register brand = register_allocator()->NewRegister();
|
||||
const AstRawString* class_name =
|
||||
expr->class_variable() != nullptr
|
||||
? expr->class_variable()->raw_name()
|
||||
: ast_string_constants()->empty_string();
|
||||
builder()
|
||||
->LoadLiteral(class_name)
|
||||
.StoreAccumulatorInRegister(brand)
|
||||
.CallRuntime(Runtime::kCreatePrivateNameSymbol, brand);
|
||||
BuildVariableAssignment(expr->scope()->brand(), Token::INIT,
|
||||
HoleCheckMode::kElided);
|
||||
}
|
||||
|
||||
if (expr->instance_members_initializer_function() != nullptr) {
|
||||
Register initializer =
|
||||
VisitForRegisterValue(expr->instance_members_initializer_function());
|
||||
@ -2110,6 +2161,10 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement(
|
||||
|
||||
for (int i = 0; i < stmt->fields()->length(); i++) {
|
||||
ClassLiteral::Property* property = stmt->fields()->at(i);
|
||||
// Private methods are not initialized in the
|
||||
// InitializeClassMembersStatement.
|
||||
DCHECK_IMPLIES(property->is_private(),
|
||||
property->kind() == ClassLiteral::Property::FIELD);
|
||||
|
||||
if (property->is_computed_name()) {
|
||||
DCHECK_EQ(property->kind(), ClassLiteral::Property::FIELD);
|
||||
@ -2120,8 +2175,7 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement(
|
||||
// variable at class definition time.
|
||||
BuildVariableLoad(var, HoleCheckMode::kElided);
|
||||
builder()->StoreAccumulatorInRegister(key);
|
||||
} else if (property->kind() == ClassLiteral::Property::FIELD &&
|
||||
property->is_private()) {
|
||||
} else if (property->is_private()) {
|
||||
Variable* private_name_var = property->private_name_var();
|
||||
DCHECK_NOT_NULL(private_name_var);
|
||||
BuildVariableLoad(private_name_var, HoleCheckMode::kElided);
|
||||
@ -2143,6 +2197,17 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement(
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeGenerator::BuildPrivateBrandInitialization(Register receiver) {
|
||||
RegisterList brand_args = register_allocator()->NewRegisterList(2);
|
||||
Variable* brand = info()->scope()->outer_scope()->AsClassScope()->brand();
|
||||
DCHECK_NOT_NULL(brand);
|
||||
BuildVariableLoad(brand, HoleCheckMode::kElided);
|
||||
builder()
|
||||
->StoreAccumulatorInRegister(brand_args[1])
|
||||
.MoveRegister(receiver, brand_args[0])
|
||||
.CallRuntime(Runtime::kAddPrivateBrand, brand_args);
|
||||
}
|
||||
|
||||
void BytecodeGenerator::BuildInstanceMemberInitialization(Register constructor,
|
||||
Register instance) {
|
||||
RegisterList args = register_allocator()->NewRegisterList(1);
|
||||
@ -4475,6 +4540,13 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
|
||||
BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kRequired);
|
||||
}
|
||||
|
||||
Register instance = register_allocator()->NewRegister();
|
||||
builder()->StoreAccumulatorInRegister(instance);
|
||||
|
||||
if (info()->literal()->requires_brand_initialization()) {
|
||||
BuildPrivateBrandInitialization(instance);
|
||||
}
|
||||
|
||||
// The derived constructor has the correct bit set always, so we
|
||||
// don't emit code to load and call the initializer if not
|
||||
// required.
|
||||
@ -4487,11 +4559,10 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
|
||||
// if required.
|
||||
if (info()->literal()->requires_instance_members_initializer() ||
|
||||
!IsDerivedConstructor(info()->literal()->kind())) {
|
||||
Register instance = register_allocator()->NewRegister();
|
||||
builder()->StoreAccumulatorInRegister(instance);
|
||||
BuildInstanceMemberInitialization(this_function, instance);
|
||||
builder()->LoadAccumulatorWithRegister(instance);
|
||||
}
|
||||
|
||||
builder()->LoadAccumulatorWithRegister(instance);
|
||||
}
|
||||
|
||||
void BytecodeGenerator::VisitCallNew(CallNew* expr) {
|
||||
|
@ -291,10 +291,12 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
|
||||
void VisitArgumentsObject(Variable* variable);
|
||||
void VisitRestArgumentsArray(Variable* rest);
|
||||
void VisitCallSuper(Call* call);
|
||||
void BuildPrivateClassMemberNameAssignment(ClassLiteral::Property* property);
|
||||
void BuildClassLiteral(ClassLiteral* expr, Register name);
|
||||
void VisitClassLiteral(ClassLiteral* expr, Register name);
|
||||
void VisitNewTargetVariable(Variable* variable);
|
||||
void VisitThisFunctionVariable(Variable* variable);
|
||||
void BuildPrivateBrandInitialization(Register receiver);
|
||||
void BuildInstanceMemberInitialization(Register constructor,
|
||||
Register instance);
|
||||
void BuildGeneratorObjectVariableInitialization();
|
||||
|
@ -2247,6 +2247,7 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { // NOLINT
|
||||
if (HasReceiver()) {
|
||||
os << "\n - receiver: " << ReceiverVariableField::decode(flags);
|
||||
}
|
||||
if (HasClassBrand()) os << "\n - has class brand";
|
||||
if (HasNewTarget()) os << "\n - needs new target";
|
||||
if (HasFunctionName()) {
|
||||
os << "\n - function name(" << FunctionVariableField::decode(flags)
|
||||
|
@ -526,6 +526,11 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
|
||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
||||
ClassLiteral::Property* property = expr->properties()->at(i);
|
||||
|
||||
// Private members are not processed using the class boilerplate.
|
||||
if (property->is_private()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClassBoilerplate::ValueKind value_kind;
|
||||
switch (property->kind()) {
|
||||
case ClassLiteral::Property::METHOD:
|
||||
|
@ -134,6 +134,9 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
|
||||
function_name_info = NONE;
|
||||
}
|
||||
|
||||
const bool has_brand = scope->is_class_scope()
|
||||
? scope->AsClassScope()->brand() != nullptr
|
||||
: false;
|
||||
const bool has_function_name = function_name_info != NONE;
|
||||
const bool has_position_info = NeedsPositionInfo(scope->scope_type());
|
||||
const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT;
|
||||
@ -181,6 +184,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
|
||||
LanguageModeField::encode(scope->language_mode()) |
|
||||
DeclarationScopeField::encode(scope->is_declaration_scope()) |
|
||||
ReceiverVariableField::encode(receiver_info) |
|
||||
HasClassBrandField::encode(has_brand) |
|
||||
HasNewTargetField::encode(has_new_target) |
|
||||
FunctionVariableField::encode(function_name_info) |
|
||||
HasInferredFunctionNameField::encode(has_inferred_function_name) |
|
||||
@ -354,9 +358,9 @@ Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
|
||||
ScopeTypeField::encode(WITH_SCOPE) | CallsSloppyEvalField::encode(false) |
|
||||
LanguageModeField::encode(LanguageMode::kSloppy) |
|
||||
DeclarationScopeField::encode(false) |
|
||||
ReceiverVariableField::encode(NONE) | HasNewTargetField::encode(false) |
|
||||
FunctionVariableField::encode(NONE) | IsAsmModuleField::encode(false) |
|
||||
HasSimpleParametersField::encode(true) |
|
||||
ReceiverVariableField::encode(NONE) | HasClassBrandField::encode(false) |
|
||||
HasNewTargetField::encode(false) | FunctionVariableField::encode(NONE) |
|
||||
IsAsmModuleField::encode(false) | HasSimpleParametersField::encode(true) |
|
||||
FunctionKindField::encode(kNormalFunction) |
|
||||
HasOuterScopeInfoField::encode(has_outer_scope_info) |
|
||||
IsDebugEvaluateScopeField::encode(false);
|
||||
@ -416,7 +420,7 @@ Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
|
||||
LanguageModeField::encode(LanguageMode::kSloppy) |
|
||||
DeclarationScopeField::encode(true) |
|
||||
ReceiverVariableField::encode(is_empty_function ? UNUSED : CONTEXT) |
|
||||
HasNewTargetField::encode(false) |
|
||||
HasClassBrandField::encode(false) | HasNewTargetField::encode(false) |
|
||||
FunctionVariableField::encode(is_empty_function ? UNUSED : NONE) |
|
||||
HasInferredFunctionNameField::encode(has_inferred_function_name) |
|
||||
IsAsmModuleField::encode(false) | HasSimpleParametersField::encode(true) |
|
||||
@ -536,6 +540,10 @@ bool ScopeInfo::HasAllocatedReceiver() const {
|
||||
return allocation == STACK || allocation == CONTEXT;
|
||||
}
|
||||
|
||||
bool ScopeInfo::HasClassBrand() const {
|
||||
return HasClassBrandField::decode(Flags());
|
||||
}
|
||||
|
||||
bool ScopeInfo::HasNewTarget() const {
|
||||
return HasNewTargetField::decode(Flags());
|
||||
}
|
||||
|
@ -69,6 +69,9 @@ class ScopeInfo : public FixedArray {
|
||||
// or context-allocated?
|
||||
bool HasAllocatedReceiver() const;
|
||||
|
||||
// Does this scope has class brand (for private methods)?
|
||||
bool HasClassBrand() const;
|
||||
|
||||
// Does this scope declare a "new.target" binding?
|
||||
bool HasNewTarget() const;
|
||||
|
||||
@ -228,8 +231,10 @@ class ScopeInfo : public FixedArray {
|
||||
class ReceiverVariableField
|
||||
: public BitField<VariableAllocationInfo, DeclarationScopeField::kNext,
|
||||
2> {};
|
||||
class HasNewTargetField
|
||||
class HasClassBrandField
|
||||
: public BitField<bool, ReceiverVariableField::kNext, 1> {};
|
||||
class HasNewTargetField
|
||||
: public BitField<bool, HasClassBrandField::kNext, 1> {};
|
||||
class FunctionVariableField
|
||||
: public BitField<VariableAllocationInfo, HasNewTargetField::kNext, 2> {};
|
||||
// TODO(cbruni): Combine with function variable field when only storing the
|
||||
|
@ -527,6 +527,7 @@ class ParserBase {
|
||||
has_static_computed_names(false),
|
||||
has_static_class_fields(false),
|
||||
has_instance_members(false),
|
||||
requires_brand(false),
|
||||
is_anonymous(false),
|
||||
static_fields_scope(nullptr),
|
||||
instance_members_scope(nullptr),
|
||||
@ -543,6 +544,7 @@ class ParserBase {
|
||||
bool has_static_computed_names;
|
||||
bool has_static_class_fields;
|
||||
bool has_instance_members;
|
||||
bool requires_brand;
|
||||
bool is_anonymous;
|
||||
DeclarationScope* static_fields_scope;
|
||||
DeclarationScope* instance_members_scope;
|
||||
@ -4249,19 +4251,32 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
|
||||
}
|
||||
is_constructor &= class_info.has_seen_constructor;
|
||||
|
||||
if (V8_UNLIKELY(property_kind == ClassLiteralProperty::FIELD)) {
|
||||
if (prop_info.is_computed_name) {
|
||||
DCHECK(!prop_info.is_private);
|
||||
class_info.computed_field_count++;
|
||||
bool is_field = property_kind == ClassLiteralProperty::FIELD;
|
||||
|
||||
if (V8_UNLIKELY(prop_info.is_private)) {
|
||||
DCHECK(!is_constructor);
|
||||
class_info.requires_brand |= !is_field;
|
||||
impl()->DeclarePrivateClassMember(class_scope, prop_info.name, property,
|
||||
property_kind, prop_info.is_static,
|
||||
&class_info);
|
||||
impl()->InferFunctionName();
|
||||
continue;
|
||||
}
|
||||
|
||||
impl()->DeclareClassField(class_scope, property, prop_info.name,
|
||||
prop_info.is_static, prop_info.is_computed_name,
|
||||
prop_info.is_private, &class_info);
|
||||
} else {
|
||||
impl()->DeclareClassProperty(class_scope, name, property, is_constructor,
|
||||
&class_info);
|
||||
if (V8_UNLIKELY(is_field)) {
|
||||
DCHECK(!prop_info.is_private);
|
||||
if (prop_info.is_computed_name) {
|
||||
class_info.computed_field_count++;
|
||||
}
|
||||
impl()->DeclarePublicClassField(class_scope, property,
|
||||
prop_info.is_static,
|
||||
prop_info.is_computed_name, &class_info);
|
||||
impl()->InferFunctionName();
|
||||
continue;
|
||||
}
|
||||
|
||||
impl()->DeclarePublicClassMethod(name, property, is_constructor,
|
||||
&class_info);
|
||||
impl()->InferFunctionName();
|
||||
}
|
||||
|
||||
@ -4278,6 +4293,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
|
||||
return impl()->FailureExpression();
|
||||
}
|
||||
|
||||
if (class_info.requires_brand) {
|
||||
class_scope->DeclareBrandVariable(ast_value_factory(), kNoSourcePosition);
|
||||
}
|
||||
|
||||
return impl()->RewriteClassLiteral(class_scope, name, &class_info,
|
||||
class_token_pos, end_pos);
|
||||
}
|
||||
|
@ -2800,18 +2800,16 @@ Variable* Parser::CreatePrivateNameVariable(ClassScope* scope,
|
||||
return proxy->var();
|
||||
}
|
||||
|
||||
void Parser::DeclareClassField(ClassScope* scope,
|
||||
void Parser::DeclarePublicClassField(ClassScope* scope,
|
||||
ClassLiteralProperty* property,
|
||||
const AstRawString* property_name,
|
||||
bool is_static, bool is_computed_name,
|
||||
bool is_private, ClassInfo* class_info) {
|
||||
ClassInfo* class_info) {
|
||||
if (is_static) {
|
||||
class_info->static_fields->Add(property, zone());
|
||||
} else {
|
||||
class_info->instance_fields->Add(property, zone());
|
||||
}
|
||||
|
||||
DCHECK_IMPLIES(is_computed_name, !is_private);
|
||||
if (is_computed_name) {
|
||||
// We create a synthetic variable name here so that scope
|
||||
// analysis doesn't dedupe the vars.
|
||||
@ -2820,9 +2818,32 @@ void Parser::DeclareClassField(ClassScope* scope,
|
||||
ast_value_factory(), class_info->computed_field_count));
|
||||
property->set_computed_name_var(computed_name_var);
|
||||
class_info->properties->Add(property, zone());
|
||||
} else if (is_private) {
|
||||
Variable* private_name_var =
|
||||
CreatePrivateNameVariable(scope, property_name);
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::DeclarePrivateClassMember(ClassScope* scope,
|
||||
const AstRawString* property_name,
|
||||
ClassLiteralProperty* property,
|
||||
ClassLiteralProperty::Kind kind,
|
||||
bool is_static, ClassInfo* class_info) {
|
||||
DCHECK_IMPLIES(kind == ClassLiteralProperty::Kind::METHOD,
|
||||
allow_harmony_private_methods());
|
||||
// TODO(joyee): We do not support private accessors yet (which allow
|
||||
// declaring the same private name twice). Make them noops.
|
||||
if (kind != ClassLiteralProperty::Kind::FIELD &&
|
||||
kind != ClassLiteralProperty::Kind::METHOD) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kind == ClassLiteralProperty::Kind::FIELD) {
|
||||
if (is_static) {
|
||||
class_info->static_fields->Add(property, zone());
|
||||
} else {
|
||||
class_info->instance_fields->Add(property, zone());
|
||||
}
|
||||
}
|
||||
|
||||
Variable* private_name_var = CreatePrivateNameVariable(scope, property_name);
|
||||
int pos = property->value()->position();
|
||||
if (pos == kNoSourcePosition) {
|
||||
pos = property->key()->position();
|
||||
@ -2831,16 +2852,15 @@ void Parser::DeclareClassField(ClassScope* scope,
|
||||
property->set_private_name_var(private_name_var);
|
||||
class_info->properties->Add(property, zone());
|
||||
}
|
||||
}
|
||||
|
||||
// This method declares a property of the given class. It updates the
|
||||
// following fields of class_info, as appropriate:
|
||||
// - constructor
|
||||
// - properties
|
||||
void Parser::DeclareClassProperty(ClassScope* scope,
|
||||
const AstRawString* class_name,
|
||||
void Parser::DeclarePublicClassMethod(const AstRawString* class_name,
|
||||
ClassLiteralProperty* property,
|
||||
bool is_constructor, ClassInfo* class_info) {
|
||||
bool is_constructor,
|
||||
ClassInfo* class_info) {
|
||||
if (is_constructor) {
|
||||
DCHECK(!class_info->constructor);
|
||||
class_info->constructor = property->value()->AsFunctionLiteral();
|
||||
@ -2861,9 +2881,9 @@ FunctionLiteral* Parser::CreateInitializerFunction(
|
||||
FunctionKind::kClassMembersInitializerFunction);
|
||||
// function() { .. class fields initializer .. }
|
||||
ScopedPtrList<Statement> statements(pointer_buffer());
|
||||
InitializeClassMembersStatement* static_fields =
|
||||
InitializeClassMembersStatement* stmt =
|
||||
factory()->NewInitializeClassMembersStatement(fields, kNoSourcePosition);
|
||||
statements.Add(static_fields);
|
||||
statements.Add(stmt);
|
||||
return factory()->NewFunctionLiteral(
|
||||
ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
|
||||
FunctionLiteral::kNoDuplicateParameters,
|
||||
|
@ -313,6 +313,19 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
||||
int class_token_pos, int end_pos);
|
||||
void DeclareClassVariable(const AstRawString* name, ClassInfo* class_info,
|
||||
int class_token_pos);
|
||||
void DeclareClassBrandVariable(ClassScope* scope, ClassInfo* class_info,
|
||||
int class_token_pos);
|
||||
void DeclarePrivateClassMember(ClassScope* scope,
|
||||
const AstRawString* property_name,
|
||||
ClassLiteralProperty* property,
|
||||
ClassLiteralProperty::Kind kind,
|
||||
bool is_static, ClassInfo* class_info);
|
||||
void DeclarePublicClassMethod(const AstRawString* class_name,
|
||||
ClassLiteralProperty* property,
|
||||
bool is_constructor, ClassInfo* class_info);
|
||||
void DeclarePublicClassField(ClassScope* scope,
|
||||
ClassLiteralProperty* property, bool is_static,
|
||||
bool is_computed_name, ClassInfo* class_info);
|
||||
void DeclareClassProperty(ClassScope* scope, const AstRawString* class_name,
|
||||
ClassLiteralProperty* property, bool is_constructor,
|
||||
ClassInfo* class_info);
|
||||
|
@ -1230,25 +1230,33 @@ class PreParser : public ParserBase<PreParser> {
|
||||
&was_added);
|
||||
}
|
||||
}
|
||||
V8_INLINE void DeclareClassProperty(ClassScope* scope,
|
||||
const PreParserIdentifier& class_name,
|
||||
V8_INLINE void DeclarePublicClassMethod(const PreParserIdentifier& class_name,
|
||||
const PreParserExpression& property,
|
||||
bool is_constructor,
|
||||
ClassInfo* class_info) {}
|
||||
|
||||
V8_INLINE void DeclareClassField(ClassScope* scope,
|
||||
V8_INLINE void DeclarePublicClassField(ClassScope* scope,
|
||||
const PreParserExpression& property,
|
||||
const PreParserIdentifier& property_name,
|
||||
bool is_static, bool is_computed_name,
|
||||
bool is_private, ClassInfo* class_info) {
|
||||
DCHECK_IMPLIES(is_computed_name, !is_private);
|
||||
ClassInfo* class_info) {
|
||||
if (is_computed_name) {
|
||||
bool was_added;
|
||||
DeclareVariableName(
|
||||
ClassFieldVariableName(ast_value_factory(),
|
||||
class_info->computed_field_count),
|
||||
VariableMode::kConst, scope, &was_added);
|
||||
} else if (is_private) {
|
||||
}
|
||||
}
|
||||
|
||||
V8_INLINE void DeclarePrivateClassMember(
|
||||
ClassScope* scope, const PreParserIdentifier& property_name,
|
||||
const PreParserExpression& property, ClassLiteralProperty::Kind kind,
|
||||
bool is_static, ClassInfo* class_info) {
|
||||
// TODO(joyee): We do not support private accessors yet (which allow
|
||||
// declaring the same private name twice). Make them noops.
|
||||
if (kind != ClassLiteralProperty::Kind::FIELD &&
|
||||
kind != ClassLiteralProperty::Kind::METHOD) {
|
||||
return;
|
||||
}
|
||||
bool was_added;
|
||||
DeclarePrivateVariableName(property_name.string_, scope, &was_added);
|
||||
if (!was_added) {
|
||||
@ -1257,7 +1265,6 @@ class PreParser : public ParserBase<PreParser> {
|
||||
property_name.string_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
V8_INLINE PreParserExpression
|
||||
RewriteClassLiteral(ClassScope* scope, const PreParserIdentifier& name,
|
||||
|
@ -1113,6 +1113,31 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyDescriptor) {
|
||||
return *desc.ToPropertyDescriptorObject(isolate);
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_AddPrivateBrand) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(args.length(), 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Symbol, brand, 1);
|
||||
DCHECK(brand->is_private_name());
|
||||
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(
|
||||
isolate, receiver, brand, LookupIterator::OWN);
|
||||
|
||||
if (it.IsFound()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kVarRedeclaration, brand));
|
||||
}
|
||||
|
||||
PropertyAttributes attributes =
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
// TODO(joyee): we could use this slot to store something useful. For now,
|
||||
// store the brand itself.
|
||||
CHECK(Object::AddDataProperty(&it, brand, attributes, Just(kDontThrow),
|
||||
StoreOrigin::kMaybeKeyed)
|
||||
.FromJust());
|
||||
return *receiver;
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_AddPrivateField) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
|
@ -106,6 +106,7 @@ bool Runtime::NeedsExactContext(FunctionId id) {
|
||||
// try-catch in async function.
|
||||
return false;
|
||||
case Runtime::kAddPrivateField:
|
||||
case Runtime::kAddPrivateBrand:
|
||||
case Runtime::kCopyDataProperties:
|
||||
case Runtime::kCreateDataProperty:
|
||||
case Runtime::kCreatePrivateNameSymbol:
|
||||
|
@ -282,6 +282,7 @@ namespace internal {
|
||||
#define FOR_EACH_INTRINSIC_OBJECT(F, I) \
|
||||
F(AddDictionaryProperty, 3, 1) \
|
||||
F(AddPrivateField, 3, 1) \
|
||||
F(AddPrivateBrand, 2, 1) \
|
||||
F(AllocateHeapNumber, 0, 1) \
|
||||
F(ClassOf, 1, 1) \
|
||||
F(CollectTypeProfile, 3, 1) \
|
||||
|
@ -0,0 +1,139 @@
|
||||
#
|
||||
# Autogenerated by generate-bytecode-expectations.
|
||||
#
|
||||
|
||||
---
|
||||
wrap: yes
|
||||
private methods: yes
|
||||
|
||||
---
|
||||
snippet: "
|
||||
{
|
||||
class A {
|
||||
#a() { return 1; }
|
||||
}
|
||||
|
||||
new A;
|
||||
}
|
||||
"
|
||||
frame size: 7
|
||||
parameter count: 1
|
||||
bytecode array length: 62
|
||||
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(CreateClosure), U8(3), U8(1), U8(2),
|
||||
B(StaCurrentContextSlot), U8(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(4),
|
||||
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),
|
||||
/* 78 S> */ B(Ldar), R(0),
|
||||
/* 78 E> */ B(Construct), R(0), R(0), U8(0), U8(0),
|
||||
B(LdaUndefined),
|
||||
/* 87 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
SCOPE_INFO_TYPE,
|
||||
FIXED_ARRAY_TYPE,
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
{
|
||||
class D {
|
||||
#d() {}
|
||||
}
|
||||
|
||||
class E extends D {
|
||||
#e() {}
|
||||
}
|
||||
|
||||
new D;
|
||||
new E;
|
||||
}
|
||||
"
|
||||
frame size: 9
|
||||
parameter count: 1
|
||||
bytecode array length: 121
|
||||
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(StaCurrentContextSlot), U8(4),
|
||||
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(4),
|
||||
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(5),
|
||||
B(PushContext), R(4),
|
||||
/* 83 E> */ B(CreateClosure), U8(7), U8(2), U8(2),
|
||||
B(Star), R(5),
|
||||
B(LdaConstant), U8(6),
|
||||
B(Star), R(6),
|
||||
B(CreateClosure), U8(8), U8(3), U8(2),
|
||||
B(StaCurrentContextSlot), U8(4),
|
||||
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(9),
|
||||
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),
|
||||
/* 106 S> */ B(Ldar), R(3),
|
||||
/* 106 E> */ B(Construct), R(3), R(0), U8(0), U8(0),
|
||||
/* 115 S> */ B(Ldar), R(2),
|
||||
/* 115 E> */ B(Construct), R(2), R(0), U8(0), U8(2),
|
||||
B(LdaUndefined),
|
||||
/* 124 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
SCOPE_INFO_TYPE,
|
||||
FIXED_ARRAY_TYPE,
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"],
|
||||
SCOPE_INFO_TYPE,
|
||||
FIXED_ARRAY_TYPE,
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"],
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
@ -2757,6 +2757,38 @@ TEST(PrivateClassFields) {
|
||||
LoadGolden("PrivateClassFields.golden")));
|
||||
}
|
||||
|
||||
TEST(PrivateMethods) {
|
||||
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"
|
||||
" #a() { return 1; }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" new A;\n"
|
||||
"}\n",
|
||||
|
||||
"{\n"
|
||||
" class D {\n"
|
||||
" #d() {}\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" class E extends D {\n"
|
||||
" #e() {}\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" new D;\n"
|
||||
" new E;\n"
|
||||
"}\n"};
|
||||
CHECK(CompareTexts(BuildActual(printer, snippets),
|
||||
LoadGolden("PrivateMethods.golden")));
|
||||
i::FLAG_harmony_private_methods = old_methods_flag;
|
||||
}
|
||||
|
||||
TEST(StaticClassFields) {
|
||||
InitializedIgnitionHandleScope scope;
|
||||
BytecodeExpectationsPrinter printer(CcTest::isolate());
|
||||
|
95
test/mjsunit/harmony/private-methods.js
Normal file
95
test/mjsunit/harmony/private-methods.js
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright 2019 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-private-methods
|
||||
|
||||
"use strict";
|
||||
|
||||
{
|
||||
class C {
|
||||
#a() {}
|
||||
}
|
||||
new C;
|
||||
}
|
||||
|
||||
{
|
||||
class C {
|
||||
#a() {
|
||||
class B {
|
||||
#a() { }
|
||||
}
|
||||
new B;
|
||||
}
|
||||
}
|
||||
new C;
|
||||
}
|
||||
|
||||
{
|
||||
class A {
|
||||
#a() {
|
||||
class C extends A {
|
||||
#c() { }
|
||||
}
|
||||
new C;
|
||||
}
|
||||
}
|
||||
|
||||
new A;
|
||||
}
|
||||
|
||||
{
|
||||
const C = class {
|
||||
#a() { }
|
||||
}
|
||||
new C;
|
||||
}
|
||||
|
||||
{
|
||||
const C = class {
|
||||
#a() {
|
||||
const B = class {
|
||||
#a() { }
|
||||
}
|
||||
new B;
|
||||
}
|
||||
}
|
||||
new C;
|
||||
}
|
||||
|
||||
{
|
||||
class A {
|
||||
constructor(arg) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
class C extends A {
|
||||
#x() { }
|
||||
|
||||
constructor(arg) {
|
||||
super(arg);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the brand twice on the same object.
|
||||
let c1 = new C({});
|
||||
assertThrows(() => new C(c1), TypeError);
|
||||
}
|
||||
|
||||
{
|
||||
// TODO(v8:9177): test extending a class expression that does not have
|
||||
// a private method.
|
||||
class D extends class {
|
||||
#c() {}
|
||||
} {
|
||||
#d() {}
|
||||
}
|
||||
|
||||
class E extends D {
|
||||
#e() {}
|
||||
}
|
||||
|
||||
new D;
|
||||
new E;
|
||||
}
|
@ -306,49 +306,49 @@ KNOWN_MAPS = {
|
||||
("read_only_space", 0x026e9): (98, "EnumCacheMap"),
|
||||
("read_only_space", 0x02789): (115, "ArrayBoilerplateDescriptionMap"),
|
||||
("read_only_space", 0x02ad9): (101, "InterceptorInfoMap"),
|
||||
("read_only_space", 0x05141): (89, "AccessCheckInfoMap"),
|
||||
("read_only_space", 0x05191): (90, "AccessorInfoMap"),
|
||||
("read_only_space", 0x051e1): (91, "AccessorPairMap"),
|
||||
("read_only_space", 0x05231): (92, "AliasedArgumentsEntryMap"),
|
||||
("read_only_space", 0x05281): (93, "AllocationMementoMap"),
|
||||
("read_only_space", 0x052d1): (94, "AsmWasmDataMap"),
|
||||
("read_only_space", 0x05321): (95, "AsyncGeneratorRequestMap"),
|
||||
("read_only_space", 0x05371): (96, "ClassPositionsMap"),
|
||||
("read_only_space", 0x053c1): (97, "DebugInfoMap"),
|
||||
("read_only_space", 0x05411): (99, "FunctionTemplateInfoMap"),
|
||||
("read_only_space", 0x05461): (100, "FunctionTemplateRareDataMap"),
|
||||
("read_only_space", 0x054b1): (102, "InterpreterDataMap"),
|
||||
("read_only_space", 0x05501): (103, "ModuleInfoEntryMap"),
|
||||
("read_only_space", 0x05551): (104, "ModuleMap"),
|
||||
("read_only_space", 0x055a1): (105, "ObjectTemplateInfoMap"),
|
||||
("read_only_space", 0x055f1): (106, "PromiseCapabilityMap"),
|
||||
("read_only_space", 0x05641): (107, "PromiseReactionMap"),
|
||||
("read_only_space", 0x05691): (108, "PrototypeInfoMap"),
|
||||
("read_only_space", 0x056e1): (109, "ScriptMap"),
|
||||
("read_only_space", 0x05731): (110, "SourcePositionTableWithFrameCacheMap"),
|
||||
("read_only_space", 0x05781): (111, "StackFrameInfoMap"),
|
||||
("read_only_space", 0x057d1): (112, "StackTraceFrameMap"),
|
||||
("read_only_space", 0x05821): (113, "Tuple2Map"),
|
||||
("read_only_space", 0x05871): (114, "Tuple3Map"),
|
||||
("read_only_space", 0x058c1): (116, "WasmCapiFunctionDataMap"),
|
||||
("read_only_space", 0x05911): (117, "WasmDebugInfoMap"),
|
||||
("read_only_space", 0x05961): (118, "WasmExceptionTagMap"),
|
||||
("read_only_space", 0x059b1): (119, "WasmExportedFunctionDataMap"),
|
||||
("read_only_space", 0x05a01): (120, "CallableTaskMap"),
|
||||
("read_only_space", 0x05a51): (121, "CallbackTaskMap"),
|
||||
("read_only_space", 0x05aa1): (122, "PromiseFulfillReactionJobTaskMap"),
|
||||
("read_only_space", 0x05af1): (123, "PromiseRejectReactionJobTaskMap"),
|
||||
("read_only_space", 0x05b41): (124, "PromiseResolveThenableJobTaskMap"),
|
||||
("read_only_space", 0x05b91): (125, "FinalizationGroupCleanupJobTaskMap"),
|
||||
("read_only_space", 0x05be1): (126, "AllocationSiteWithWeakNextMap"),
|
||||
("read_only_space", 0x05c31): (126, "AllocationSiteWithoutWeakNextMap"),
|
||||
("read_only_space", 0x05c81): (161, "LoadHandler1Map"),
|
||||
("read_only_space", 0x05cd1): (161, "LoadHandler2Map"),
|
||||
("read_only_space", 0x05d21): (161, "LoadHandler3Map"),
|
||||
("read_only_space", 0x05d71): (169, "StoreHandler0Map"),
|
||||
("read_only_space", 0x05dc1): (169, "StoreHandler1Map"),
|
||||
("read_only_space", 0x05e11): (169, "StoreHandler2Map"),
|
||||
("read_only_space", 0x05e61): (169, "StoreHandler3Map"),
|
||||
("read_only_space", 0x05159): (89, "AccessCheckInfoMap"),
|
||||
("read_only_space", 0x051a9): (90, "AccessorInfoMap"),
|
||||
("read_only_space", 0x051f9): (91, "AccessorPairMap"),
|
||||
("read_only_space", 0x05249): (92, "AliasedArgumentsEntryMap"),
|
||||
("read_only_space", 0x05299): (93, "AllocationMementoMap"),
|
||||
("read_only_space", 0x052e9): (94, "AsmWasmDataMap"),
|
||||
("read_only_space", 0x05339): (95, "AsyncGeneratorRequestMap"),
|
||||
("read_only_space", 0x05389): (96, "ClassPositionsMap"),
|
||||
("read_only_space", 0x053d9): (97, "DebugInfoMap"),
|
||||
("read_only_space", 0x05429): (99, "FunctionTemplateInfoMap"),
|
||||
("read_only_space", 0x05479): (100, "FunctionTemplateRareDataMap"),
|
||||
("read_only_space", 0x054c9): (102, "InterpreterDataMap"),
|
||||
("read_only_space", 0x05519): (103, "ModuleInfoEntryMap"),
|
||||
("read_only_space", 0x05569): (104, "ModuleMap"),
|
||||
("read_only_space", 0x055b9): (105, "ObjectTemplateInfoMap"),
|
||||
("read_only_space", 0x05609): (106, "PromiseCapabilityMap"),
|
||||
("read_only_space", 0x05659): (107, "PromiseReactionMap"),
|
||||
("read_only_space", 0x056a9): (108, "PrototypeInfoMap"),
|
||||
("read_only_space", 0x056f9): (109, "ScriptMap"),
|
||||
("read_only_space", 0x05749): (110, "SourcePositionTableWithFrameCacheMap"),
|
||||
("read_only_space", 0x05799): (111, "StackFrameInfoMap"),
|
||||
("read_only_space", 0x057e9): (112, "StackTraceFrameMap"),
|
||||
("read_only_space", 0x05839): (113, "Tuple2Map"),
|
||||
("read_only_space", 0x05889): (114, "Tuple3Map"),
|
||||
("read_only_space", 0x058d9): (116, "WasmCapiFunctionDataMap"),
|
||||
("read_only_space", 0x05929): (117, "WasmDebugInfoMap"),
|
||||
("read_only_space", 0x05979): (118, "WasmExceptionTagMap"),
|
||||
("read_only_space", 0x059c9): (119, "WasmExportedFunctionDataMap"),
|
||||
("read_only_space", 0x05a19): (120, "CallableTaskMap"),
|
||||
("read_only_space", 0x05a69): (121, "CallbackTaskMap"),
|
||||
("read_only_space", 0x05ab9): (122, "PromiseFulfillReactionJobTaskMap"),
|
||||
("read_only_space", 0x05b09): (123, "PromiseRejectReactionJobTaskMap"),
|
||||
("read_only_space", 0x05b59): (124, "PromiseResolveThenableJobTaskMap"),
|
||||
("read_only_space", 0x05ba9): (125, "FinalizationGroupCleanupJobTaskMap"),
|
||||
("read_only_space", 0x05bf9): (126, "AllocationSiteWithWeakNextMap"),
|
||||
("read_only_space", 0x05c49): (126, "AllocationSiteWithoutWeakNextMap"),
|
||||
("read_only_space", 0x05c99): (161, "LoadHandler1Map"),
|
||||
("read_only_space", 0x05ce9): (161, "LoadHandler2Map"),
|
||||
("read_only_space", 0x05d39): (161, "LoadHandler3Map"),
|
||||
("read_only_space", 0x05d89): (169, "StoreHandler0Map"),
|
||||
("read_only_space", 0x05dd9): (169, "StoreHandler1Map"),
|
||||
("read_only_space", 0x05e29): (169, "StoreHandler2Map"),
|
||||
("read_only_space", 0x05e79): (169, "StoreHandler3Map"),
|
||||
("map_space", 0x00141): (1057, "ExternalMap"),
|
||||
("map_space", 0x00191): (1073, "JSMessageObjectMap"),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user