Commit 44ee4a9f authored by Shu-yu Guo's avatar Shu-yu Guo Committed by Commit Bot

[class] Implement class static blocks

Stage 3 proposal: https://github.com/tc39/proposal-class-static-block

Bug: v8:11375
Change-Id: I579adab4679cce0190b9d8bd814a7cd297ebfa15
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2699449Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72847}
parent 93ea0a22
...@@ -40,8 +40,8 @@ void AstFunctionLiteralIdReindexer::VisitClassLiteral(ClassLiteral* expr) { ...@@ -40,8 +40,8 @@ void AstFunctionLiteralIdReindexer::VisitClassLiteral(ClassLiteral* expr) {
Visit(expr->extends()); Visit(expr->extends());
} }
Visit(expr->constructor()); Visit(expr->constructor());
if (expr->static_fields_initializer() != nullptr) { if (expr->static_initializer() != nullptr) {
Visit(expr->static_fields_initializer()); Visit(expr->static_initializer());
} }
if (expr->instance_members_initializer_function() != nullptr) { if (expr->instance_members_initializer_function() != nullptr) {
Visit(expr->instance_members_initializer_function()); Visit(expr->instance_members_initializer_function());
......
...@@ -469,8 +469,8 @@ void AstTraversalVisitor<Subclass>::VisitClassLiteral(ClassLiteral* expr) { ...@@ -469,8 +469,8 @@ void AstTraversalVisitor<Subclass>::VisitClassLiteral(ClassLiteral* expr) {
RECURSE_EXPRESSION(Visit(expr->extends())); RECURSE_EXPRESSION(Visit(expr->extends()));
} }
RECURSE_EXPRESSION(Visit(expr->constructor())); RECURSE_EXPRESSION(Visit(expr->constructor()));
if (expr->static_fields_initializer() != nullptr) { if (expr->static_initializer() != nullptr) {
RECURSE_EXPRESSION(Visit(expr->static_fields_initializer())); RECURSE_EXPRESSION(Visit(expr->static_initializer()));
} }
if (expr->instance_members_initializer_function() != nullptr) { if (expr->instance_members_initializer_function() != nullptr) {
RECURSE_EXPRESSION(Visit(expr->instance_members_initializer_function())); RECURSE_EXPRESSION(Visit(expr->instance_members_initializer_function()));
...@@ -505,6 +505,29 @@ void AstTraversalVisitor<Subclass>::VisitInitializeClassMembersStatement( ...@@ -505,6 +505,29 @@ void AstTraversalVisitor<Subclass>::VisitInitializeClassMembersStatement(
} }
} }
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitInitializeClassStaticElementsStatement(
InitializeClassStaticElementsStatement* stmt) {
PROCESS_NODE(stmt);
ZonePtrList<ClassLiteral::StaticElement>* elements = stmt->elements();
for (int i = 0; i < elements->length(); ++i) {
ClassLiteral::StaticElement* element = elements->at(i);
switch (element->kind()) {
case ClassLiteral::StaticElement::PROPERTY: {
ClassLiteral::Property* prop = element->property();
if (!prop->key()->IsLiteral()) {
RECURSE(Visit(prop->key()));
}
RECURSE(Visit(prop->value()));
break;
}
case ClassLiteral::StaticElement::STATIC_BLOCK:
RECURSE(Visit(element->static_block()));
break;
}
}
}
template <class Subclass> template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitSpread(Spread* expr) { void AstTraversalVisitor<Subclass>::VisitSpread(Spread* expr) {
PROCESS_EXPRESSION(expr); PROCESS_EXPRESSION(expr);
......
...@@ -68,7 +68,8 @@ namespace internal { ...@@ -68,7 +68,8 @@ namespace internal {
V(TryCatchStatement) \ V(TryCatchStatement) \
V(TryFinallyStatement) \ V(TryFinallyStatement) \
V(DebuggerStatement) \ V(DebuggerStatement) \
V(InitializeClassMembersStatement) V(InitializeClassMembersStatement) \
V(InitializeClassStaticElementsStatement)
#define LITERAL_NODE_LIST(V) \ #define LITERAL_NODE_LIST(V) \
V(RegExpLiteral) \ V(RegExpLiteral) \
...@@ -2366,6 +2367,40 @@ class ClassLiteralProperty final : public LiteralProperty { ...@@ -2366,6 +2367,40 @@ class ClassLiteralProperty final : public LiteralProperty {
Variable* private_or_computed_name_var_; Variable* private_or_computed_name_var_;
}; };
class ClassLiteralStaticElement final : public ZoneObject {
public:
enum Kind : uint8_t { PROPERTY, STATIC_BLOCK };
Kind kind() const { return kind_; }
ClassLiteralProperty* property() const {
DCHECK(kind() == PROPERTY);
return property_;
}
Block* static_block() const {
DCHECK(kind() == STATIC_BLOCK);
return static_block_;
}
private:
friend class AstNodeFactory;
friend Zone;
explicit ClassLiteralStaticElement(ClassLiteralProperty* property)
: kind_(PROPERTY), property_(property) {}
explicit ClassLiteralStaticElement(Block* static_block)
: kind_(STATIC_BLOCK), static_block_(static_block) {}
Kind kind_;
union {
ClassLiteralProperty* property_;
Block* static_block_;
};
};
class InitializeClassMembersStatement final : public Statement { class InitializeClassMembersStatement final : public Statement {
public: public:
using Property = ClassLiteralProperty; using Property = ClassLiteralProperty;
...@@ -2382,9 +2417,28 @@ class InitializeClassMembersStatement final : public Statement { ...@@ -2382,9 +2417,28 @@ class InitializeClassMembersStatement final : public Statement {
ZonePtrList<Property>* fields_; ZonePtrList<Property>* fields_;
}; };
class InitializeClassStaticElementsStatement final : public Statement {
public:
using StaticElement = ClassLiteralStaticElement;
ZonePtrList<StaticElement>* elements() const { return elements_; }
private:
friend class AstNodeFactory;
friend Zone;
InitializeClassStaticElementsStatement(ZonePtrList<StaticElement>* elements,
int pos)
: Statement(pos, kInitializeClassStaticElementsStatement),
elements_(elements) {}
ZonePtrList<StaticElement>* elements_;
};
class ClassLiteral final : public Expression { class ClassLiteral final : public Expression {
public: public:
using Property = ClassLiteralProperty; using Property = ClassLiteralProperty;
using StaticElement = ClassLiteralStaticElement;
ClassScope* scope() const { return scope_; } ClassScope* scope() const { return scope_; }
Expression* extends() const { return extends_; } Expression* extends() const { return extends_; }
...@@ -2410,9 +2464,7 @@ class ClassLiteral final : public Expression { ...@@ -2410,9 +2464,7 @@ class ClassLiteral final : public Expression {
return is_anonymous_expression(); return is_anonymous_expression();
} }
FunctionLiteral* static_fields_initializer() const { FunctionLiteral* static_initializer() const { return static_initializer_; }
return static_fields_initializer_;
}
FunctionLiteral* instance_members_initializer_function() const { FunctionLiteral* instance_members_initializer_function() const {
return instance_members_initializer_function_; return instance_members_initializer_function_;
...@@ -2430,7 +2482,7 @@ class ClassLiteral final : public Expression { ...@@ -2430,7 +2482,7 @@ class ClassLiteral final : public Expression {
FunctionLiteral* constructor, FunctionLiteral* constructor,
ZonePtrList<Property>* public_members, ZonePtrList<Property>* public_members,
ZonePtrList<Property>* private_members, ZonePtrList<Property>* private_members,
FunctionLiteral* static_fields_initializer, FunctionLiteral* static_initializer,
FunctionLiteral* instance_members_initializer_function, FunctionLiteral* instance_members_initializer_function,
int start_position, int end_position, int start_position, int end_position,
bool has_name_static_property, bool has_static_computed_names, bool has_name_static_property, bool has_static_computed_names,
...@@ -2443,7 +2495,7 @@ class ClassLiteral final : public Expression { ...@@ -2443,7 +2495,7 @@ class ClassLiteral final : public Expression {
constructor_(constructor), constructor_(constructor),
public_members_(public_members), public_members_(public_members),
private_members_(private_members), private_members_(private_members),
static_fields_initializer_(static_fields_initializer), static_initializer_(static_initializer),
instance_members_initializer_function_( instance_members_initializer_function_(
instance_members_initializer_function), instance_members_initializer_function),
home_object_(home_object), home_object_(home_object),
...@@ -2460,7 +2512,7 @@ class ClassLiteral final : public Expression { ...@@ -2460,7 +2512,7 @@ class ClassLiteral final : public Expression {
FunctionLiteral* constructor_; FunctionLiteral* constructor_;
ZonePtrList<Property>* public_members_; ZonePtrList<Property>* public_members_;
ZonePtrList<Property>* private_members_; ZonePtrList<Property>* private_members_;
FunctionLiteral* static_fields_initializer_; FunctionLiteral* static_initializer_;
FunctionLiteral* instance_members_initializer_function_; FunctionLiteral* instance_members_initializer_function_;
using HasNameStaticProperty = Expression::NextBitField<bool, 1>; using HasNameStaticProperty = Expression::NextBitField<bool, 1>;
using HasStaticComputedNames = HasNameStaticProperty::Next<bool, 1>; using HasStaticComputedNames = HasNameStaticProperty::Next<bool, 1>;
...@@ -3174,11 +3226,21 @@ class AstNodeFactory final { ...@@ -3174,11 +3226,21 @@ class AstNodeFactory final {
is_computed_name, is_private); is_computed_name, is_private);
} }
ClassLiteral::StaticElement* NewClassLiteralStaticElement(
ClassLiteral::Property* property) {
return zone_->New<ClassLiteral::StaticElement>(property);
}
ClassLiteral::StaticElement* NewClassLiteralStaticElement(
Block* static_block) {
return zone_->New<ClassLiteral::StaticElement>(static_block);
}
ClassLiteral* NewClassLiteral( ClassLiteral* NewClassLiteral(
ClassScope* scope, Expression* extends, FunctionLiteral* constructor, ClassScope* scope, Expression* extends, FunctionLiteral* constructor,
ZonePtrList<ClassLiteral::Property>* public_members, ZonePtrList<ClassLiteral::Property>* public_members,
ZonePtrList<ClassLiteral::Property>* private_members, ZonePtrList<ClassLiteral::Property>* private_members,
FunctionLiteral* static_fields_initializer, FunctionLiteral* static_initializer,
FunctionLiteral* instance_members_initializer_function, FunctionLiteral* instance_members_initializer_function,
int start_position, int end_position, bool has_name_static_property, int start_position, int end_position, bool has_name_static_property,
bool has_static_computed_names, bool is_anonymous, bool has_static_computed_names, bool is_anonymous,
...@@ -3186,7 +3248,7 @@ class AstNodeFactory final { ...@@ -3186,7 +3248,7 @@ class AstNodeFactory final {
Variable* static_home_object) { Variable* static_home_object) {
return zone_->New<ClassLiteral>( return zone_->New<ClassLiteral>(
scope, extends, constructor, public_members, private_members, scope, extends, constructor, public_members, private_members,
static_fields_initializer, instance_members_initializer_function, static_initializer, instance_members_initializer_function,
start_position, end_position, has_name_static_property, start_position, end_position, has_name_static_property,
has_static_computed_names, is_anonymous, has_private_methods, has_static_computed_names, is_anonymous, has_private_methods,
home_object, static_home_object); home_object, static_home_object);
...@@ -3242,6 +3304,12 @@ class AstNodeFactory final { ...@@ -3242,6 +3304,12 @@ class AstNodeFactory final {
return zone_->New<InitializeClassMembersStatement>(args, pos); return zone_->New<InitializeClassMembersStatement>(args, pos);
} }
InitializeClassStaticElementsStatement*
NewInitializeClassStaticElementsStatement(
ZonePtrList<ClassLiteral::StaticElement>* args, int pos) {
return zone_->New<InitializeClassStaticElementsStatement>(args, pos);
}
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
private: private:
......
...@@ -235,6 +235,18 @@ void CallPrinter::VisitInitializeClassMembersStatement( ...@@ -235,6 +235,18 @@ void CallPrinter::VisitInitializeClassMembersStatement(
} }
} }
void CallPrinter::VisitInitializeClassStaticElementsStatement(
InitializeClassStaticElementsStatement* node) {
for (int i = 0; i < node->elements()->length(); i++) {
ClassLiteral::StaticElement* element = node->elements()->at(i);
if (element->kind() == ClassLiteral::StaticElement::PROPERTY) {
Find(element->property()->value());
} else {
Find(element->static_block());
}
}
}
void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {} void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {}
...@@ -1086,9 +1098,8 @@ void AstPrinter::VisitClassLiteral(ClassLiteral* node) { ...@@ -1086,9 +1098,8 @@ void AstPrinter::VisitClassLiteral(ClassLiteral* node) {
PrintLiteralWithModeIndented("BRAND", brand, brand->raw_name()); PrintLiteralWithModeIndented("BRAND", brand, brand->raw_name());
} }
} }
if (node->static_fields_initializer() != nullptr) { if (node->static_initializer() != nullptr) {
PrintIndentedVisit("STATIC FIELDS INITIALIZER", PrintIndentedVisit("STATIC INITIALIZER", node->static_initializer());
node->static_fields_initializer());
} }
if (node->instance_members_initializer_function() != nullptr) { if (node->instance_members_initializer_function() != nullptr) {
PrintIndentedVisit("INSTANCE MEMBERS INITIALIZER", PrintIndentedVisit("INSTANCE MEMBERS INITIALIZER",
...@@ -1104,10 +1115,14 @@ void AstPrinter::VisitInitializeClassMembersStatement( ...@@ -1104,10 +1115,14 @@ void AstPrinter::VisitInitializeClassMembersStatement(
PrintClassProperties(node->fields()); PrintClassProperties(node->fields());
} }
void AstPrinter::PrintClassProperties( void AstPrinter::VisitInitializeClassStaticElementsStatement(
const ZonePtrList<ClassLiteral::Property>* properties) { InitializeClassStaticElementsStatement* node) {
for (int i = 0; i < properties->length(); i++) { IndentedScope indent(this, "INITIALIZE CLASS STATIC ELEMENTS",
ClassLiteral::Property* property = properties->at(i); node->position());
PrintClassStaticElements(node->elements());
}
void AstPrinter::PrintClassProperty(ClassLiteral::Property* property) {
const char* prop_kind = nullptr; const char* prop_kind = nullptr;
switch (property->kind()) { switch (property->kind()) {
case ClassLiteral::Property::METHOD: case ClassLiteral::Property::METHOD:
...@@ -1127,11 +1142,31 @@ void AstPrinter::PrintClassProperties( ...@@ -1127,11 +1142,31 @@ void AstPrinter::PrintClassProperties(
SNPrintF(buf, "PROPERTY%s%s - %s", property->is_static() ? " - STATIC" : "", SNPrintF(buf, "PROPERTY%s%s - %s", property->is_static() ? " - STATIC" : "",
property->is_private() ? " - PRIVATE" : " - PUBLIC", prop_kind); property->is_private() ? " - PRIVATE" : " - PUBLIC", prop_kind);
IndentedScope prop(this, buf.begin()); IndentedScope prop(this, buf.begin());
PrintIndentedVisit("KEY", properties->at(i)->key()); PrintIndentedVisit("KEY", property->key());
PrintIndentedVisit("VALUE", properties->at(i)->value()); PrintIndentedVisit("VALUE", property->value());
}
void AstPrinter::PrintClassProperties(
const ZonePtrList<ClassLiteral::Property>* properties) {
for (int i = 0; i < properties->length(); i++) {
PrintClassProperty(properties->at(i));
} }
} }
void AstPrinter::PrintClassStaticElements(
const ZonePtrList<ClassLiteral::StaticElement>* static_elements) {
for (int i = 0; i < static_elements->length(); i++) {
ClassLiteral::StaticElement* element = static_elements->at(i);
switch (element->kind()) {
case ClassLiteral::StaticElement::PROPERTY:
PrintClassProperty(element->property());
break;
case ClassLiteral::StaticElement::STATIC_BLOCK:
PrintIndentedVisit("STATIC BLOCK", element->static_block());
break;
}
}
}
void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {
IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position()); IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position());
......
...@@ -133,8 +133,11 @@ class AstPrinter final : public AstVisitor<AstPrinter> { ...@@ -133,8 +133,11 @@ class AstPrinter final : public AstVisitor<AstPrinter> {
const char* prefix = ""); const char* prefix = "");
void PrintObjectProperties( void PrintObjectProperties(
const ZonePtrList<ObjectLiteral::Property>* properties); const ZonePtrList<ObjectLiteral::Property>* properties);
void PrintClassProperty(ClassLiteral::Property* property);
void PrintClassProperties( void PrintClassProperties(
const ZonePtrList<ClassLiteral::Property>* properties); const ZonePtrList<ClassLiteral::Property>* properties);
void PrintClassStaticElements(
const ZonePtrList<ClassLiteral::StaticElement>* static_elements);
void inc_indent() { indent_++; } void inc_indent() { indent_++; }
void dec_indent() { indent_--; } void dec_indent() { indent_--; }
......
...@@ -27,8 +27,9 @@ namespace internal { ...@@ -27,8 +27,9 @@ namespace internal {
T(ApplyNonFunction, \ T(ApplyNonFunction, \
"Function.prototype.apply was called on %, which is a % and not a " \ "Function.prototype.apply was called on %, which is a % and not a " \
"function") \ "function") \
T(ArgumentsDisallowedInInitializer, \ T(ArgumentsDisallowedInInitializerAndStaticBlock, \
"'arguments' is not allowed in class field initializer") \ "'arguments' is not allowed in class field initializer or static " \
"initialization block") \
T(ArrayBufferTooShort, \ T(ArrayBufferTooShort, \
"Derived ArrayBuffer constructor created a buffer which was too small") \ "Derived ArrayBuffer constructor created a buffer which was too small") \
T(ArrayBufferSpeciesThis, \ T(ArrayBufferSpeciesThis, \
......
...@@ -249,7 +249,8 @@ DEFINE_IMPLICATION(harmony_weak_refs_with_cleanup_some, harmony_weak_refs) ...@@ -249,7 +249,8 @@ DEFINE_IMPLICATION(harmony_weak_refs_with_cleanup_some, harmony_weak_refs)
V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \ V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \
V(harmony_weak_refs_with_cleanup_some, \ V(harmony_weak_refs_with_cleanup_some, \
"harmony weak references with FinalizationRegistry.prototype.cleanupSome") \ "harmony weak references with FinalizationRegistry.prototype.cleanupSome") \
V(harmony_import_assertions, "harmony import assertions") V(harmony_import_assertions, "harmony import assertions") \
V(harmony_class_static_blocks, "harmony static initializer blocks")
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
#define HARMONY_INPROGRESS(V) \ #define HARMONY_INPROGRESS(V) \
......
...@@ -4317,6 +4317,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_top_level_await) ...@@ -4317,6 +4317,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_top_level_await)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_logical_assignment) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_logical_assignment)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_assertions) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_assertions)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_private_brand_checks) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_private_brand_checks)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_class_static_blocks)
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_intl_displaynames_date_types) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_intl_displaynames_date_types)
......
...@@ -2441,7 +2441,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { ...@@ -2441,7 +2441,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
.LoadAccumulatorWithRegister(class_constructor); .LoadAccumulatorWithRegister(class_constructor);
} }
if (expr->static_fields_initializer() != nullptr) { if (expr->static_initializer() != nullptr) {
// TODO(gsathya): This can be optimized away to be a part of the // TODO(gsathya): This can be optimized away to be a part of the
// class boilerplate in the future. The name argument can be // class boilerplate in the future. The name argument can be
// passed to the DefineClass runtime function and have it set // passed to the DefineClass runtime function and have it set
...@@ -2461,8 +2461,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { ...@@ -2461,8 +2461,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
} }
RegisterList args = register_allocator()->NewRegisterList(1); RegisterList args = register_allocator()->NewRegisterList(1);
Register initializer = Register initializer = VisitForRegisterValue(expr->static_initializer());
VisitForRegisterValue(expr->static_fields_initializer());
builder() builder()
->MoveRegister(class_constructor, args[0]) ->MoveRegister(class_constructor, args[0])
...@@ -2488,16 +2487,13 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr, Register name) { ...@@ -2488,16 +2487,13 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr, Register name) {
} }
} }
void BytecodeGenerator::VisitInitializeClassMembersStatement( void BytecodeGenerator::BuildClassProperty(ClassLiteral::Property* property) {
InitializeClassMembersStatement* stmt) { RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewRegisterList(3); RegisterList args = register_allocator()->NewRegisterList(3);
Register constructor = args[0], key = args[1], value = args[2]; Register constructor = args[0], key = args[1], value = args[2];
builder()->MoveRegister(builder()->Receiver(), constructor); builder()->MoveRegister(builder()->Receiver(), constructor);
for (int i = 0; i < stmt->fields()->length(); i++) { // Private methods are not initialized in BuildClassProperty.
ClassLiteral::Property* property = stmt->fields()->at(i);
// Private methods are not initialized in the
// InitializeClassMembersStatement.
DCHECK_IMPLIES(property->is_private(), DCHECK_IMPLIES(property->is_private(),
property->kind() == ClassLiteral::Property::FIELD); property->kind() == ClassLiteral::Property::FIELD);
...@@ -2506,8 +2502,8 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement( ...@@ -2506,8 +2502,8 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement(
DCHECK(!property->is_private()); DCHECK(!property->is_private());
Variable* var = property->computed_name_var(); Variable* var = property->computed_name_var();
DCHECK_NOT_NULL(var); DCHECK_NOT_NULL(var);
// The computed name is already evaluated and stored in a // The computed name is already evaluated and stored in a variable at class
// variable at class definition time. // definition time.
BuildVariableLoad(var, HoleCheckMode::kElided); BuildVariableLoad(var, HoleCheckMode::kElided);
builder()->StoreAccumulatorInRegister(key); builder()->StoreAccumulatorInRegister(key);
} else if (property->is_private()) { } else if (property->is_private()) {
...@@ -2528,6 +2524,27 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement( ...@@ -2528,6 +2524,27 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement(
? Runtime::kCreateDataProperty ? Runtime::kCreateDataProperty
: Runtime::kAddPrivateField; : Runtime::kAddPrivateField;
builder()->CallRuntime(function_id, args); builder()->CallRuntime(function_id, args);
}
void BytecodeGenerator::VisitInitializeClassMembersStatement(
InitializeClassMembersStatement* stmt) {
for (int i = 0; i < stmt->fields()->length(); i++) {
BuildClassProperty(stmt->fields()->at(i));
}
}
void BytecodeGenerator::VisitInitializeClassStaticElementsStatement(
InitializeClassStaticElementsStatement* stmt) {
for (int i = 0; i < stmt->elements()->length(); i++) {
ClassLiteral::StaticElement* element = stmt->elements()->at(i);
switch (element->kind()) {
case ClassLiteral::StaticElement::PROPERTY:
BuildClassProperty(element->property());
break;
case ClassLiteral::StaticElement::STATIC_BLOCK:
VisitBlock(element->static_block());
break;
}
} }
} }
...@@ -2876,7 +2893,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ...@@ -2876,7 +2893,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
// the class, meaning we can't wait until the // the class, meaning we can't wait until the
// StoreDataPropertyInLiteral call later to set the name. // StoreDataPropertyInLiteral call later to set the name.
if (property->value()->IsClassLiteral() && if (property->value()->IsClassLiteral() &&
property->value()->AsClassLiteral()->static_fields_initializer() != property->value()->AsClassLiteral()->static_initializer() !=
nullptr) { nullptr) {
value = register_allocator()->NewRegister(); value = register_allocator()->NewRegister();
VisitClassLiteral(property->value()->AsClassLiteral(), key); VisitClassLiteral(property->value()->AsClassLiteral(), key);
......
...@@ -319,6 +319,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -319,6 +319,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
Register value); Register value);
void BuildPrivateMethods(ClassLiteral* expr, bool is_static, void BuildPrivateMethods(ClassLiteral* expr, bool is_static,
Register home_object); Register home_object);
void BuildClassProperty(ClassLiteral::Property* property);
void BuildClassLiteral(ClassLiteral* expr, Register name); void BuildClassLiteral(ClassLiteral* expr, Register name);
void VisitClassLiteral(ClassLiteral* expr, Register name); void VisitClassLiteral(ClassLiteral* expr, Register name);
void VisitNewTargetVariable(Variable* variable); void VisitNewTargetVariable(Variable* variable);
......
...@@ -58,10 +58,10 @@ enum FunctionKind : uint8_t { ...@@ -58,10 +58,10 @@ enum FunctionKind : uint8_t {
kConciseMethod, kConciseMethod,
kStaticConciseMethod, kStaticConciseMethod,
kClassMembersInitializerFunction, kClassMembersInitializerFunction,
kStaticClassMembersInitializerFunction, kClassStaticInitializerFunction,
// END concise methods 2 // END concise methods 2
kLastFunctionKind = kStaticClassMembersInitializerFunction, kLastFunctionKind = kClassStaticInitializerFunction,
}; };
constexpr int kFunctionKindBitSize = 5; constexpr int kFunctionKindBitSize = 5;
...@@ -104,7 +104,7 @@ inline bool IsConciseMethod(FunctionKind kind) { ...@@ -104,7 +104,7 @@ inline bool IsConciseMethod(FunctionKind kind) {
return base::IsInRange(kind, FunctionKind::kAsyncConciseMethod, return base::IsInRange(kind, FunctionKind::kAsyncConciseMethod,
FunctionKind::kStaticAsyncConciseGeneratorMethod) || FunctionKind::kStaticAsyncConciseGeneratorMethod) ||
base::IsInRange(kind, FunctionKind::kConciseGeneratorMethod, base::IsInRange(kind, FunctionKind::kConciseGeneratorMethod,
FunctionKind::kStaticClassMembersInitializerFunction); FunctionKind::kClassStaticInitializerFunction);
} }
inline bool IsStrictFunctionWithoutPrototype(FunctionKind kind) { inline bool IsStrictFunctionWithoutPrototype(FunctionKind kind) {
...@@ -113,7 +113,7 @@ inline bool IsStrictFunctionWithoutPrototype(FunctionKind kind) { ...@@ -113,7 +113,7 @@ inline bool IsStrictFunctionWithoutPrototype(FunctionKind kind) {
base::IsInRange(kind, FunctionKind::kAsyncConciseMethod, base::IsInRange(kind, FunctionKind::kAsyncConciseMethod,
FunctionKind::kStaticAsyncConciseGeneratorMethod) || FunctionKind::kStaticAsyncConciseGeneratorMethod) ||
base::IsInRange(kind, FunctionKind::kConciseGeneratorMethod, base::IsInRange(kind, FunctionKind::kConciseGeneratorMethod,
FunctionKind::kStaticClassMembersInitializerFunction); FunctionKind::kClassStaticInitializerFunction);
} }
inline bool IsGetterFunction(FunctionKind kind) { inline bool IsGetterFunction(FunctionKind kind) {
...@@ -153,7 +153,7 @@ inline bool IsClassConstructor(FunctionKind kind) { ...@@ -153,7 +153,7 @@ inline bool IsClassConstructor(FunctionKind kind) {
inline bool IsClassMembersInitializerFunction(FunctionKind kind) { inline bool IsClassMembersInitializerFunction(FunctionKind kind) {
return base::IsInRange(kind, FunctionKind::kClassMembersInitializerFunction, return base::IsInRange(kind, FunctionKind::kClassMembersInitializerFunction,
FunctionKind::kStaticClassMembersInitializerFunction); FunctionKind::kClassStaticInitializerFunction);
} }
inline bool IsConstructable(FunctionKind kind) { inline bool IsConstructable(FunctionKind kind) {
...@@ -169,7 +169,7 @@ inline bool IsStatic(FunctionKind kind) { ...@@ -169,7 +169,7 @@ inline bool IsStatic(FunctionKind kind) {
case FunctionKind::kStaticConciseGeneratorMethod: case FunctionKind::kStaticConciseGeneratorMethod:
case FunctionKind::kStaticAsyncConciseMethod: case FunctionKind::kStaticAsyncConciseMethod:
case FunctionKind::kStaticAsyncConciseGeneratorMethod: case FunctionKind::kStaticAsyncConciseGeneratorMethod:
case FunctionKind::kStaticClassMembersInitializerFunction: case FunctionKind::kClassStaticInitializerFunction:
return true; return true;
default: default:
return false; return false;
...@@ -213,8 +213,8 @@ inline const char* FunctionKind2String(FunctionKind kind) { ...@@ -213,8 +213,8 @@ inline const char* FunctionKind2String(FunctionKind kind) {
return "AsyncModule"; return "AsyncModule";
case FunctionKind::kClassMembersInitializerFunction: case FunctionKind::kClassMembersInitializerFunction:
return "ClassMembersInitializerFunction"; return "ClassMembersInitializerFunction";
case FunctionKind::kStaticClassMembersInitializerFunction: case FunctionKind::kClassStaticInitializerFunction:
return "StaticClassMembersInitializerFunction"; return "ClassStaticInitializerFunction";
case FunctionKind::kDefaultBaseConstructor: case FunctionKind::kDefaultBaseConstructor:
return "DefaultBaseConstructor"; return "DefaultBaseConstructor";
case FunctionKind::kDefaultDerivedConstructor: case FunctionKind::kDefaultDerivedConstructor:
......
...@@ -214,6 +214,7 @@ class ParserBase { ...@@ -214,6 +214,7 @@ class ParserBase {
using BreakableStatementT = typename Types::BreakableStatement; using BreakableStatementT = typename Types::BreakableStatement;
using ClassLiteralPropertyT = typename Types::ClassLiteralProperty; using ClassLiteralPropertyT = typename Types::ClassLiteralProperty;
using ClassPropertyListT = typename Types::ClassPropertyList; using ClassPropertyListT = typename Types::ClassPropertyList;
using ClassStaticElementListT = typename Types::ClassStaticElementList;
using ExpressionT = typename Types::Expression; using ExpressionT = typename Types::Expression;
using ExpressionListT = typename Types::ExpressionList; using ExpressionListT = typename Types::ExpressionList;
using FormalParametersT = typename Types::FormalParameters; using FormalParametersT = typename Types::FormalParameters;
...@@ -589,38 +590,40 @@ class ParserBase { ...@@ -589,38 +590,40 @@ class ParserBase {
: extends(parser->impl()->NullExpression()), : extends(parser->impl()->NullExpression()),
public_members(parser->impl()->NewClassPropertyList(4)), public_members(parser->impl()->NewClassPropertyList(4)),
private_members(parser->impl()->NewClassPropertyList(4)), private_members(parser->impl()->NewClassPropertyList(4)),
static_fields(parser->impl()->NewClassPropertyList(4)), static_elements(parser->impl()->NewClassStaticElementList(4)),
instance_fields(parser->impl()->NewClassPropertyList(4)), instance_fields(parser->impl()->NewClassPropertyList(4)),
constructor(parser->impl()->NullExpression()), constructor(parser->impl()->NullExpression()),
has_seen_constructor(false), has_seen_constructor(false),
has_name_static_property(false), has_name_static_property(false),
has_static_computed_names(false), has_static_computed_names(false),
has_static_class_fields(false), has_static_elements(false),
has_static_private_methods(false), has_static_private_methods(false),
has_static_blocks(false),
has_instance_members(false), has_instance_members(false),
requires_brand(false), requires_brand(false),
is_anonymous(false), is_anonymous(false),
has_private_methods(false), has_private_methods(false),
static_fields_scope(nullptr), static_elements_scope(nullptr),
instance_members_scope(nullptr), instance_members_scope(nullptr),
computed_field_count(0) {} computed_field_count(0) {}
ExpressionT extends; ExpressionT extends;
ClassPropertyListT public_members; ClassPropertyListT public_members;
ClassPropertyListT private_members; ClassPropertyListT private_members;
ClassPropertyListT static_fields; ClassStaticElementListT static_elements;
ClassPropertyListT instance_fields; ClassPropertyListT instance_fields;
FunctionLiteralT constructor; FunctionLiteralT constructor;
bool has_seen_constructor; bool has_seen_constructor;
bool has_name_static_property; bool has_name_static_property;
bool has_static_computed_names; bool has_static_computed_names;
bool has_static_class_fields; bool has_static_elements;
bool has_static_private_methods; bool has_static_private_methods;
bool has_static_blocks;
bool has_instance_members; bool has_instance_members;
bool requires_brand; bool requires_brand;
bool is_anonymous; bool is_anonymous;
bool has_private_methods; bool has_private_methods;
DeclarationScope* static_fields_scope; DeclarationScope* static_elements_scope;
DeclarationScope* instance_members_scope; DeclarationScope* instance_members_scope;
int computed_field_count; int computed_field_count;
Variable* home_object_variable = nullptr; Variable* home_object_variable = nullptr;
...@@ -1057,6 +1060,10 @@ class ParserBase { ...@@ -1057,6 +1060,10 @@ class ParserBase {
bool is_resumable() const { bool is_resumable() const {
return IsResumableFunction(function_state_->kind()); return IsResumableFunction(function_state_->kind());
} }
bool is_class_static_block() const {
return function_state_->kind() ==
FunctionKind::kClassStaticInitializerFunction;
}
bool is_await_allowed() const { bool is_await_allowed() const {
return is_async_function() || (flags().allow_harmony_top_level_await() && return is_async_function() || (flags().allow_harmony_top_level_await() &&
IsModule(function_state_->kind())); IsModule(function_state_->kind()));
...@@ -1176,6 +1183,7 @@ class ParserBase { ...@@ -1176,6 +1183,7 @@ class ParserBase {
bool* has_seen_constructor); bool* has_seen_constructor);
ExpressionT ParseMemberInitializer(ClassInfo* class_info, int beg_pos, ExpressionT ParseMemberInitializer(ClassInfo* class_info, int beg_pos,
bool is_static); bool is_static);
BlockT ParseClassStaticBlock(ClassInfo* class_info);
ObjectLiteralPropertyT ParseObjectPropertyDefinition( ObjectLiteralPropertyT ParseObjectPropertyDefinition(
ParsePropertyInfo* prop_info, bool* has_seen_proto); ParsePropertyInfo* prop_info, bool* has_seen_proto);
void ParseArguments( void ParseArguments(
...@@ -1295,6 +1303,8 @@ class ParserBase { ...@@ -1295,6 +1303,8 @@ class ParserBase {
StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, ZonePtrList<const AstRawString>* own_labels,
AllowLabelledFunctionStatement allow_function); AllowLabelledFunctionStatement allow_function);
BlockT ParseBlock(ZonePtrList<const AstRawString>* labels,
Scope* block_scope);
BlockT ParseBlock(ZonePtrList<const AstRawString>* labels); BlockT ParseBlock(ZonePtrList<const AstRawString>* labels);
// Parse a SubStatement in strict mode, or with an extra block scope in // Parse a SubStatement in strict mode, or with an extra block scope in
...@@ -1633,14 +1643,16 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(Token::Value next) { ...@@ -1633,14 +1643,16 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(Token::Value next) {
IdentifierT name = impl()->GetIdentifier(); IdentifierT name = impl()->GetIdentifier();
if (V8_UNLIKELY(impl()->IsArguments(name) && if (V8_UNLIKELY(impl()->IsArguments(name) &&
scope()->ShouldBanArguments())) { scope()->ShouldBanArguments())) {
ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer); ReportMessage(
MessageTemplate::kArgumentsDisallowedInInitializerAndStaticBlock);
return impl()->EmptyIdentifierString(); return impl()->EmptyIdentifierString();
} }
return name; return name;
} }
if (!Token::IsValidIdentifier(next, language_mode(), is_generator(), if (!Token::IsValidIdentifier(next, language_mode(), is_generator(),
flags().is_module() || is_async_function())) { flags().is_module() || is_async_function() ||
is_class_static_block())) {
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
return impl()->EmptyIdentifierString(); return impl()->EmptyIdentifierString();
} }
...@@ -2433,10 +2445,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer( ...@@ -2433,10 +2445,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
ClassInfo* class_info, int beg_pos, bool is_static) { ClassInfo* class_info, int beg_pos, bool is_static) {
FunctionParsingScope body_parsing_scope(impl()); FunctionParsingScope body_parsing_scope(impl());
DeclarationScope* initializer_scope = DeclarationScope* initializer_scope =
is_static ? class_info->static_fields_scope is_static ? class_info->static_elements_scope
: class_info->instance_members_scope; : class_info->instance_members_scope;
FunctionKind function_kind = FunctionKind function_kind =
is_static ? FunctionKind::kStaticClassMembersInitializerFunction is_static ? FunctionKind::kClassStaticInitializerFunction
: FunctionKind::kClassMembersInitializerFunction; : FunctionKind::kClassMembersInitializerFunction;
if (initializer_scope == nullptr) { if (initializer_scope == nullptr) {
...@@ -2459,8 +2471,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer( ...@@ -2459,8 +2471,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
initializer_scope->set_end_position(end_position()); initializer_scope->set_end_position(end_position());
if (is_static) { if (is_static) {
class_info->static_fields_scope = initializer_scope; class_info->static_elements_scope = initializer_scope;
class_info->has_static_class_fields = true; class_info->has_static_elements = true;
} else { } else {
class_info->instance_members_scope = initializer_scope; class_info->instance_members_scope = initializer_scope;
class_info->has_instance_members = true; class_info->has_instance_members = true;
...@@ -2469,6 +2481,32 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer( ...@@ -2469,6 +2481,32 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
return initializer; return initializer;
} }
template <typename Impl>
typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseClassStaticBlock(
ClassInfo* class_info) {
Consume(Token::STATIC);
DeclarationScope* initializer_scope = class_info->static_elements_scope;
if (initializer_scope == nullptr) {
initializer_scope =
NewFunctionScope(FunctionKind::kClassStaticInitializerFunction);
initializer_scope->set_start_position(position());
initializer_scope->SetLanguageMode(LanguageMode::kStrict);
class_info->static_elements_scope = initializer_scope;
}
FunctionState initializer_state(&function_state_, &scope_, initializer_scope);
AcceptINScope accept_in(this, true);
// Each static block has its own var and lexical scope, so make a new var
// block scope instead of using the synthetic members initializer function
// scope.
BlockT static_block = ParseBlock(nullptr, NewVarblockScope());
initializer_scope->set_end_position(end_position());
class_info->has_static_elements = true;
return static_block;
}
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::ObjectLiteralPropertyT typename ParserBase<Impl>::ObjectLiteralPropertyT
ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info,
...@@ -4623,12 +4661,22 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( ...@@ -4623,12 +4661,22 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
const bool has_extends = !impl()->IsNull(class_info.extends); const bool has_extends = !impl()->IsNull(class_info.extends);
while (peek() != Token::RBRACE) { while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue; if (Check(Token::SEMICOLON)) continue;
// Either we're parsing a `static { }` initialization block or a property.
if (FLAG_harmony_class_static_blocks && peek() == Token::STATIC &&
PeekAhead() == Token::LBRACE) {
BlockT static_block = ParseClassStaticBlock(&class_info);
impl()->AddClassStaticBlock(static_block, &class_info);
continue;
}
FuncNameInferrerState fni_state(&fni_); FuncNameInferrerState fni_state(&fni_);
// If we haven't seen the constructor yet, it potentially is the next // If we haven't seen the constructor yet, it potentially is the next
// property. // property.
bool is_constructor = !class_info.has_seen_constructor; bool is_constructor = !class_info.has_seen_constructor;
ParsePropertyInfo prop_info(this); ParsePropertyInfo prop_info(this);
prop_info.position = PropertyPosition::kClassLiteral; prop_info.position = PropertyPosition::kClassLiteral;
ClassLiteralPropertyT property = ClassLiteralPropertyT property =
ParseClassPropertyDefinition(&class_info, &prop_info, has_extends); ParseClassPropertyDefinition(&class_info, &prop_info, has_extends);
...@@ -5196,7 +5244,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( ...@@ -5196,7 +5244,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
ZonePtrList<const AstRawString>* labels) { ZonePtrList<const AstRawString>* labels, Scope* block_scope) {
// Block :: // Block ::
// '{' StatementList '}' // '{' StatementList '}'
...@@ -5207,7 +5255,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( ...@@ -5207,7 +5255,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
CheckStackOverflow(); CheckStackOverflow();
{ {
BlockState block_state(zone(), &scope_); BlockState block_state(&scope_, block_scope);
scope()->set_start_position(peek_position()); scope()->set_start_position(peek_position());
Target target(this, body, labels, nullptr, Target::TARGET_FOR_NAMED_ONLY); Target target(this, body, labels, nullptr, Target::TARGET_FOR_NAMED_ONLY);
...@@ -5233,6 +5281,12 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( ...@@ -5233,6 +5281,12 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
return body; return body;
} }
template <typename Impl>
typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
ZonePtrList<const AstRawString>* labels) {
return ParseBlock(labels, NewScope(BLOCK_SCOPE));
}
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement( typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement(
ZonePtrList<const AstRawString>* labels) { ZonePtrList<const AstRawString>* labels) {
......
...@@ -3026,7 +3026,8 @@ void Parser::DeclarePublicClassField(ClassScope* scope, ...@@ -3026,7 +3026,8 @@ void Parser::DeclarePublicClassField(ClassScope* scope,
bool is_static, bool is_computed_name, bool is_static, bool is_computed_name,
ClassInfo* class_info) { ClassInfo* class_info) {
if (is_static) { if (is_static) {
class_info->static_fields->Add(property, zone()); class_info->static_elements->Add(
factory()->NewClassLiteralStaticElement(property), zone());
} else { } else {
class_info->instance_fields->Add(property, zone()); class_info->instance_fields->Add(property, zone());
} }
...@@ -3049,7 +3050,8 @@ void Parser::DeclarePrivateClassMember(ClassScope* scope, ...@@ -3049,7 +3050,8 @@ void Parser::DeclarePrivateClassMember(ClassScope* scope,
bool is_static, ClassInfo* class_info) { bool is_static, ClassInfo* class_info) {
if (kind == ClassLiteralProperty::Kind::FIELD) { if (kind == ClassLiteralProperty::Kind::FIELD) {
if (is_static) { if (is_static) {
class_info->static_fields->Add(property, zone()); class_info->static_elements->Add(
factory()->NewClassLiteralStaticElement(property), zone());
} else { } else {
class_info->instance_fields->Add(property, zone()); class_info->instance_fields->Add(property, zone());
} }
...@@ -3089,15 +3091,18 @@ void Parser::DeclarePublicClassMethod(const AstRawString* class_name, ...@@ -3089,15 +3091,18 @@ void Parser::DeclarePublicClassMethod(const AstRawString* class_name,
class_info->public_members->Add(property, zone()); class_info->public_members->Add(property, zone());
} }
void Parser::AddClassStaticBlock(Block* block, ClassInfo* class_info) {
DCHECK(class_info->has_static_elements);
class_info->static_elements->Add(
factory()->NewClassLiteralStaticElement(block), zone());
}
FunctionLiteral* Parser::CreateInitializerFunction( FunctionLiteral* Parser::CreateInitializerFunction(
const char* name, DeclarationScope* scope, const char* name, DeclarationScope* scope, Statement* initializer_stmt) {
ZonePtrList<ClassLiteral::Property>* fields) {
DCHECK(IsClassMembersInitializerFunction(scope->function_kind())); DCHECK(IsClassMembersInitializerFunction(scope->function_kind()));
// function() { .. class fields initializer .. } // function() { .. class fields initializer .. }
ScopedPtrList<Statement> statements(pointer_buffer()); ScopedPtrList<Statement> statements(pointer_buffer());
InitializeClassMembersStatement* stmt = statements.Add(initializer_stmt);
factory()->NewInitializeClassMembersStatement(fields, kNoSourcePosition);
statements.Add(stmt);
FunctionLiteral* result = factory()->NewFunctionLiteral( FunctionLiteral* result = factory()->NewFunctionLiteral(
ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0, ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kNoDuplicateParameters,
...@@ -3138,18 +3143,20 @@ Expression* Parser::RewriteClassLiteral(ClassScope* block_scope, ...@@ -3138,18 +3143,20 @@ Expression* Parser::RewriteClassLiteral(ClassScope* block_scope,
block_scope->class_variable()->set_initializer_position(end_pos); block_scope->class_variable()->set_initializer_position(end_pos);
} }
FunctionLiteral* static_fields_initializer = nullptr; FunctionLiteral* static_initializer = nullptr;
if (class_info->has_static_class_fields) { if (class_info->has_static_elements) {
static_fields_initializer = CreateInitializerFunction( static_initializer = CreateInitializerFunction(
"<static_fields_initializer>", class_info->static_fields_scope, "<static_initializer>", class_info->static_elements_scope,
class_info->static_fields); factory()->NewInitializeClassStaticElementsStatement(
class_info->static_elements, kNoSourcePosition));
} }
FunctionLiteral* instance_members_initializer_function = nullptr; FunctionLiteral* instance_members_initializer_function = nullptr;
if (class_info->has_instance_members) { if (class_info->has_instance_members) {
instance_members_initializer_function = CreateInitializerFunction( instance_members_initializer_function = CreateInitializerFunction(
"<instance_members_initializer>", class_info->instance_members_scope, "<instance_members_initializer>", class_info->instance_members_scope,
class_info->instance_fields); factory()->NewInitializeClassMembersStatement(
class_info->instance_fields, kNoSourcePosition));
class_info->constructor->set_requires_instance_members_initializer(true); class_info->constructor->set_requires_instance_members_initializer(true);
class_info->constructor->add_expected_properties( class_info->constructor->add_expected_properties(
class_info->instance_fields->length()); class_info->instance_fields->length());
...@@ -3164,8 +3171,8 @@ Expression* Parser::RewriteClassLiteral(ClassScope* block_scope, ...@@ -3164,8 +3171,8 @@ Expression* Parser::RewriteClassLiteral(ClassScope* block_scope,
ClassLiteral* class_literal = factory()->NewClassLiteral( ClassLiteral* class_literal = factory()->NewClassLiteral(
block_scope, class_info->extends, class_info->constructor, block_scope, class_info->extends, class_info->constructor,
class_info->public_members, class_info->private_members, class_info->public_members, class_info->private_members,
static_fields_initializer, instance_members_initializer_function, pos, static_initializer, instance_members_initializer_function, pos, end_pos,
end_pos, class_info->has_name_static_property, class_info->has_name_static_property,
class_info->has_static_computed_names, class_info->is_anonymous, class_info->has_static_computed_names, class_info->is_anonymous,
class_info->has_private_methods, class_info->home_object_variable, class_info->has_private_methods, class_info->home_object_variable,
class_info->static_home_object_variable); class_info->static_home_object_variable);
......
...@@ -103,7 +103,9 @@ struct ParserTypes<Parser> { ...@@ -103,7 +103,9 @@ struct ParserTypes<Parser> {
using Block = v8::internal::Block*; using Block = v8::internal::Block*;
using BreakableStatement = v8::internal::BreakableStatement*; using BreakableStatement = v8::internal::BreakableStatement*;
using ClassLiteralProperty = ClassLiteral::Property*; using ClassLiteralProperty = ClassLiteral::Property*;
using ClassLiteralStaticElement = ClassLiteral::StaticElement*;
using ClassPropertyList = ZonePtrList<ClassLiteral::Property>*; using ClassPropertyList = ZonePtrList<ClassLiteral::Property>*;
using ClassStaticElementList = ZonePtrList<ClassLiteral::StaticElement>*;
using Expression = v8::internal::Expression*; using Expression = v8::internal::Expression*;
using ExpressionList = ScopedPtrList<v8::internal::Expression>; using ExpressionList = ScopedPtrList<v8::internal::Expression>;
using FormalParameters = ParserFormalParameters; using FormalParameters = ParserFormalParameters;
...@@ -313,9 +315,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -313,9 +315,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Variable* CreatePrivateNameVariable(ClassScope* scope, VariableMode mode, Variable* CreatePrivateNameVariable(ClassScope* scope, VariableMode mode,
IsStaticFlag is_static_flag, IsStaticFlag is_static_flag,
const AstRawString* name); const AstRawString* name);
FunctionLiteral* CreateInitializerFunction( FunctionLiteral* CreateInitializerFunction(const char* name,
const char* name, DeclarationScope* scope, DeclarationScope* scope,
ZonePtrList<ClassLiteral::Property>* fields); Statement* initializer_stmt);
bool IdentifierEquals(const AstRawString* identifier, bool IdentifierEquals(const AstRawString* identifier,
const AstRawString* other) { const AstRawString* other) {
...@@ -347,6 +349,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -347,6 +349,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
const AstRawString* property_name, bool is_static, const AstRawString* property_name, bool is_static,
bool is_computed_name, bool is_private, bool is_computed_name, bool is_private,
ClassInfo* class_info); ClassInfo* class_info);
void AddClassStaticBlock(Block* block, ClassInfo* class_info);
Expression* RewriteClassLiteral(ClassScope* block_scope, Expression* RewriteClassLiteral(ClassScope* block_scope,
const AstRawString* name, const AstRawString* name,
ClassInfo* class_info, int pos, int end_pos); ClassInfo* class_info, int pos, int end_pos);
...@@ -842,6 +845,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -842,6 +845,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
int size) const { int size) const {
return zone()->New<ZonePtrList<ClassLiteral::Property>>(size, zone()); return zone()->New<ZonePtrList<ClassLiteral::Property>>(size, zone());
} }
V8_INLINE ZonePtrList<ClassLiteral::StaticElement>* NewClassStaticElementList(
int size) const {
return zone()->New<ZonePtrList<ClassLiteral::StaticElement>>(size, zone());
}
V8_INLINE ZonePtrList<Statement>* NewStatementList(int size) const { V8_INLINE ZonePtrList<Statement>* NewStatementList(int size) const {
return zone()->New<ZonePtrList<Statement>>(size, zone()); return zone()->New<ZonePtrList<Statement>>(size, zone());
} }
......
...@@ -876,6 +876,7 @@ struct ParserTypes<PreParser> { ...@@ -876,6 +876,7 @@ struct ParserTypes<PreParser> {
// Return types for traversing functions. // Return types for traversing functions.
using ClassLiteralProperty = PreParserExpression; using ClassLiteralProperty = PreParserExpression;
using ClassLiteralStaticElement = PreParserExpression;
using Expression = PreParserExpression; using Expression = PreParserExpression;
using FunctionLiteral = PreParserExpression; using FunctionLiteral = PreParserExpression;
using ObjectLiteralProperty = PreParserExpression; using ObjectLiteralProperty = PreParserExpression;
...@@ -885,6 +886,7 @@ struct ParserTypes<PreParser> { ...@@ -885,6 +886,7 @@ struct ParserTypes<PreParser> {
using FormalParameters = PreParserFormalParameters; using FormalParameters = PreParserFormalParameters;
using Identifier = PreParserIdentifier; using Identifier = PreParserIdentifier;
using ClassPropertyList = PreParserPropertyList; using ClassPropertyList = PreParserPropertyList;
using ClassStaticElementList = PreParserPropertyList;
using StatementList = PreParserScopedStatementList; using StatementList = PreParserScopedStatementList;
using Block = PreParserBlock; using Block = PreParserBlock;
using BreakableStatement = PreParserStatement; using BreakableStatement = PreParserStatement;
...@@ -1239,6 +1241,11 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1239,6 +1241,11 @@ class PreParser : public ParserBase<PreParser> {
} }
} }
V8_INLINE void AddClassStaticBlock(PreParserBlock block,
ClassInfo* class_info) {
DCHECK(class_info->has_static_elements);
}
V8_INLINE PreParserExpression V8_INLINE PreParserExpression
RewriteClassLiteral(ClassScope* scope, const PreParserIdentifier& name, RewriteClassLiteral(ClassScope* scope, const PreParserIdentifier& name,
ClassInfo* class_info, int pos, int end_pos) { ClassInfo* class_info, int pos, int end_pos) {
...@@ -1260,7 +1267,7 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1260,7 +1267,7 @@ class PreParser : public ParserBase<PreParser> {
FunctionState function_state(&function_state_, &scope_, function_scope); FunctionState function_state(&function_state_, &scope_, function_scope);
GetNextFunctionLiteralId(); GetNextFunctionLiteralId();
} }
if (class_info->has_static_class_fields) { if (class_info->has_static_elements) {
GetNextFunctionLiteralId(); GetNextFunctionLiteralId();
} }
if (class_info->has_instance_members) { if (class_info->has_instance_members) {
...@@ -1601,6 +1608,10 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1601,6 +1608,10 @@ class PreParser : public ParserBase<PreParser> {
return PreParserPropertyList(); return PreParserPropertyList();
} }
V8_INLINE PreParserPropertyList NewClassStaticElementList(int size) const {
return PreParserPropertyList();
}
V8_INLINE PreParserStatementList NewStatementList(int size) const { V8_INLINE PreParserStatementList NewStatementList(int size) const {
return PreParserStatementList(); return PreParserStatementList();
} }
......
...@@ -360,6 +360,11 @@ void Processor::VisitInitializeClassMembersStatement( ...@@ -360,6 +360,11 @@ void Processor::VisitInitializeClassMembersStatement(
replacement_ = node; replacement_ = node;
} }
void Processor::VisitInitializeClassStaticElementsStatement(
InitializeClassStaticElementsStatement* node) {
replacement_ = node;
}
// Expressions are never visited. // Expressions are never visited.
#define DEF_VISIT(type) \ #define DEF_VISIT(type) \
void Processor::Visit##type(type* expr) { UNREACHABLE(); } void Processor::Visit##type(type* expr) { UNREACHABLE(); }
......
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
static x = foo(); static x = foo();
^ ^
ReferenceError: foo is not defined ReferenceError: foo is not defined
at Function.<static_fields_initializer> (*%(basename)s:8:14) at Function.<static_initializer> (*%(basename)s:8:14)
at *%(basename)s:1:1 at *%(basename)s:1:1
// Copyright 2021 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-class-static-blocks
{
// Basic functionality
let log = [];
class C {
static { log.push("block1"); }
static { log.push("block2"); }
}
assertArrayEquals(["block1", "block2"], log);
}
{
// Static blocks run in textual order interleaved with field initializers.
let log = [];
class C {
static { log.push("block1"); }
static public_static_method() {}
static public_field = log.push("public_field");
static { log.push("block2"); }
static #private_field = log.push("private_field");
static { log.push("block3"); }
}
assertArrayEquals(["block1",
"public_field",
"block2",
"private_field",
"block3"], log);
}
{
// Static blocks have access to private fields.
let exfil;
class C {
#foo;
constructor(x) { this.#foo = x; }
static {
exfil = function(o) { return o.#foo; };
}
}
assertEquals(exfil(new C(42)), 42);
}
{
// 'this' is the constructor.
let log = [];
class C {
static x = 42;
static {
log.push(this.x);
}
}
assertArrayEquals([42], log);
}
{
// super.property accesses work as expected.
let log = [];
class B {
static foo = 42;
static get field_getter() { return "field_getter"; }
static set field_setter(x) { log.push(x); };
static method() { return "bar"; }
}
class C extends B {
static {
log.push(super.foo);
log.push(super.field_getter);
super.field_setter = "C";
log.push(super.method());
}
}
assertArrayEquals([42, "field_getter", "C", "bar"], log);
}
{
// Each static block is its own var and let scope.
let log = [];
let f;
class C {
static {
var x = "x1";
let y = "y1";
log.push(x);
log.push(y);
}
static {
var x = "x2";
let y = "y2";
f = () => [x, y];
}
static {
assertThrows(() => x, ReferenceError);
assertThrows(() => y, ReferenceError);
}
}
assertArrayEquals(["x1", "y1"], log);
assertArrayEquals(["x2", "y2"], f());
}
{
// new.target is undefined.
let log = [];
class C {
static {
log.push(new.target);
}
}
assertArrayEquals([undefined], log);
}
function assertDoesntParse(expr, context_start, context_end) {
assertThrows(() => {
eval(`${context_start} class C { static { ${expr} } } ${context_end}`);
}, SyntaxError);
}
for (let [s, e] of [['', ''],
['function* g() {', '}'],
['async function af() {', '}'],
['async function* ag() {', '}']]) {
assertDoesntParse('arguments;', s, e);
assertDoesntParse('arguments[0] = 42;', s, e);
assertDoesntParse('super();', s, e);
assertDoesntParse('yield 42;', s, e);
assertDoesntParse('await 42;', s, e);
// 'await' is disallowed as an identifier.
assertDoesntParse('let await;', s, e);
assertDoesntParse('await;', s, e);
}
...@@ -43,13 +43,13 @@ function testClassConstruction() { ...@@ -43,13 +43,13 @@ function testClassConstruction() {
// ReferenceError: FAIL is not defined // ReferenceError: FAIL is not defined
// at thrower // at thrower
// at <static_fields_initializer> // at <static_initializer>
// at testClassConstruction // at testClassConstruction
// at testTrace // at testTrace
testTrace( testTrace(
"during class construction", "during class construction",
testClassConstruction, testClassConstruction,
["thrower", "<static_fields_initializer>"], ["thrower", "<static_initializer>"],
["anonymous"] ["anonymous"]
); );
......
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