Commit 3cf32599 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[class] Lazy parse class constructor with class fields

Previously, we had lazy parsing of class constructor disabled when a
class literal had class fields because we were using a reference to
the initializer function variable to load the function and call it.

Instead, in this patch, we use the scope analysis to lookup this
initializer function variable.

Bug: v8:5367
Change-Id: Ib73d7e6abed33c04d1f574e7976bea4869d54757
Reviewed-on: https://chromium-review.googlesource.com/768384
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49406}
parent 77b0baa6
...@@ -2291,10 +2291,10 @@ class FunctionLiteral final : public Expression { ...@@ -2291,10 +2291,10 @@ class FunctionLiteral final : public Expression {
function_literal_id_ = function_literal_id; function_literal_id_ = function_literal_id;
} }
void set_instance_class_fields_initializer(Variable* initializer) { void set_instance_class_fields_initializer(VariableProxy* initializer) {
instance_class_fields_initializer_ = initializer; instance_class_fields_initializer_ = initializer;
} }
Variable* instance_class_fields_initializer() { VariableProxy* instance_class_fields_initializer() {
return instance_class_fields_initializer_; return instance_class_fields_initializer_;
} }
...@@ -2356,7 +2356,7 @@ class FunctionLiteral final : public Expression { ...@@ -2356,7 +2356,7 @@ class FunctionLiteral final : public Expression {
const AstConsString* raw_inferred_name_; const AstConsString* raw_inferred_name_;
Handle<String> inferred_name_; Handle<String> inferred_name_;
int function_literal_id_; int function_literal_id_;
Variable* instance_class_fields_initializer_; VariableProxy* instance_class_fields_initializer_;
ProducedPreParsedScopeData* produced_preparsed_scope_data_; ProducedPreParsedScopeData* produced_preparsed_scope_data_;
}; };
...@@ -2431,8 +2431,8 @@ class ClassLiteral final : public Expression { ...@@ -2431,8 +2431,8 @@ class ClassLiteral final : public Expression {
return instance_fields_initializer_function_; return instance_fields_initializer_function_;
} }
Variable* instance_fields_initializer_var() const { VariableProxy* instance_fields_initializer_proxy() const {
return instance_fields_initializer_var_; return instance_fields_initializer_proxy_;
} }
private: private:
...@@ -2442,9 +2442,10 @@ class ClassLiteral final : public Expression { ...@@ -2442,9 +2442,10 @@ class ClassLiteral final : public Expression {
FunctionLiteral* constructor, ZoneList<Property*>* properties, FunctionLiteral* constructor, ZoneList<Property*>* properties,
FunctionLiteral* static_fields_initializer, FunctionLiteral* static_fields_initializer,
FunctionLiteral* instance_fields_initializer_function, FunctionLiteral* instance_fields_initializer_function,
Variable* instance_fields_initializer_var, int start_position, VariableProxy* instance_fields_initializer_proxy,
int end_position, bool has_name_static_property, int start_position, int end_position,
bool has_static_computed_names, bool is_anonymous) bool has_name_static_property, bool has_static_computed_names,
bool is_anonymous)
: Expression(start_position, kClassLiteral), : Expression(start_position, kClassLiteral),
end_position_(end_position), end_position_(end_position),
scope_(scope), scope_(scope),
...@@ -2455,7 +2456,7 @@ class ClassLiteral final : public Expression { ...@@ -2455,7 +2456,7 @@ class ClassLiteral final : public Expression {
static_fields_initializer_(static_fields_initializer), static_fields_initializer_(static_fields_initializer),
instance_fields_initializer_function_( instance_fields_initializer_function_(
instance_fields_initializer_function), instance_fields_initializer_function),
instance_fields_initializer_var_(instance_fields_initializer_var) { instance_fields_initializer_proxy_(instance_fields_initializer_proxy) {
bit_field_ |= HasNameStaticProperty::encode(has_name_static_property) | bit_field_ |= HasNameStaticProperty::encode(has_name_static_property) |
HasStaticComputedNames::encode(has_static_computed_names) | HasStaticComputedNames::encode(has_static_computed_names) |
IsAnonymousExpression::encode(is_anonymous); IsAnonymousExpression::encode(is_anonymous);
...@@ -2469,7 +2470,7 @@ class ClassLiteral final : public Expression { ...@@ -2469,7 +2470,7 @@ class ClassLiteral final : public Expression {
ZoneList<Property*>* properties_; ZoneList<Property*>* properties_;
FunctionLiteral* static_fields_initializer_; FunctionLiteral* static_fields_initializer_;
FunctionLiteral* instance_fields_initializer_function_; FunctionLiteral* instance_fields_initializer_function_;
Variable* instance_fields_initializer_var_; VariableProxy* instance_fields_initializer_proxy_;
class HasNameStaticProperty class HasNameStaticProperty
: public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class HasStaticComputedNames class HasStaticComputedNames
...@@ -3159,7 +3160,7 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3159,7 +3160,7 @@ class AstNodeFactory final BASE_EMBEDDED {
ZoneList<ClassLiteral::Property*>* properties, ZoneList<ClassLiteral::Property*>* properties,
FunctionLiteral* static_fields_initializer, FunctionLiteral* static_fields_initializer,
FunctionLiteral* instance_fields_initializer_function, FunctionLiteral* instance_fields_initializer_function,
Variable* instance_fields_initializer_var, int start_position, VariableProxy* instance_fields_initializer_var, int start_position,
int end_position, bool has_name_static_property, int end_position, bool has_name_static_property,
bool has_static_computed_names, bool is_anonymous) { bool has_static_computed_names, bool is_anonymous) {
return new (zone_) ClassLiteral( return new (zone_) ClassLiteral(
......
...@@ -1835,7 +1835,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) { ...@@ -1835,7 +1835,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
// initializers. // initializers.
builder()->LoadAccumulatorWithRegister(initializer); builder()->LoadAccumulatorWithRegister(initializer);
BuildVariableAssignment(expr->instance_fields_initializer_var(), BuildVariableAssignment(expr->instance_fields_initializer_proxy()->var(),
Token::INIT, HoleCheckMode::kElided); Token::INIT, HoleCheckMode::kElided);
builder()->LoadAccumulatorWithRegister(constructor); builder()->LoadAccumulatorWithRegister(constructor);
} }
...@@ -1990,10 +1990,10 @@ void BytecodeGenerator::VisitInitializeClassFieldsStatement( ...@@ -1990,10 +1990,10 @@ void BytecodeGenerator::VisitInitializeClassFieldsStatement(
} }
void BytecodeGenerator::BuildInstanceFieldInitialization( void BytecodeGenerator::BuildInstanceFieldInitialization(
Variable* initializer_var) { VariableProxy* initializer_proxy) {
RegisterList args = register_allocator()->NewRegisterList(1); RegisterList args = register_allocator()->NewRegisterList(1);
Register initializer = register_allocator()->NewRegister(); Register initializer = register_allocator()->NewRegister();
BuildVariableLoad(initializer_var, HoleCheckMode::kElided); BuildVariableLoad(initializer_proxy->var(), HoleCheckMode::kElided);
builder() builder()
->StoreAccumulatorInRegister(initializer) ->StoreAccumulatorInRegister(initializer)
......
...@@ -161,7 +161,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -161,7 +161,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildClassLiteral(ClassLiteral* expr); void BuildClassLiteral(ClassLiteral* expr);
void VisitNewTargetVariable(Variable* variable); void VisitNewTargetVariable(Variable* variable);
void VisitThisFunctionVariable(Variable* variable); void VisitThisFunctionVariable(Variable* variable);
void BuildInstanceFieldInitialization(Variable* initializer_var); void BuildInstanceFieldInitialization(VariableProxy* initializer_proxy);
void BuildGeneratorObjectVariableInitialization(); void BuildGeneratorObjectVariableInitialization();
void VisitBlockDeclarationsAndStatements(Block* stmt); void VisitBlockDeclarationsAndStatements(Block* stmt);
void VisitFunctionClosureForContext(); void VisitFunctionClosureForContext();
......
...@@ -13780,7 +13780,10 @@ void SharedFunctionInfo::InitFromFunctionLiteral( ...@@ -13780,7 +13780,10 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
} }
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject()); shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_function_literal_id(lit->function_literal_id()); shared_info->set_function_literal_id(lit->function_literal_id());
DCHECK_IMPLIES(lit->instance_class_fields_initializer() != nullptr,
IsClassConstructor(lit->kind()));
shared_info->set_requires_instance_fields_initializer(
lit->instance_class_fields_initializer() != nullptr);
// For lazy parsed functions, the following flags will be inaccurate since we // For lazy parsed functions, the following flags will be inaccurate since we
// don't have the information yet. They're set later in // don't have the information yet. They're set later in
// SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
......
...@@ -94,6 +94,9 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, native, ...@@ -94,6 +94,9 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, native,
SharedFunctionInfo::IsNativeBit) SharedFunctionInfo::IsNativeBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, is_asm_wasm_broken, BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, is_asm_wasm_broken,
SharedFunctionInfo::IsAsmWasmBrokenBit) SharedFunctionInfo::IsAsmWasmBrokenBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints,
requires_instance_fields_initializer,
SharedFunctionInfo::RequiresInstanceFieldsInitializer)
bool SharedFunctionInfo::optimization_disabled() const { bool SharedFunctionInfo::optimization_disabled() const {
return disable_optimization_reason() != BailoutReason::kNoReason; return disable_optimization_reason() != BailoutReason::kNoReason;
......
...@@ -328,6 +328,12 @@ class SharedFunctionInfo : public HeapObject { ...@@ -328,6 +328,12 @@ class SharedFunctionInfo : public HeapObject {
// shared function info. // shared function info.
void DisableOptimization(BailoutReason reason); void DisableOptimization(BailoutReason reason);
// This class constructor needs to call out to an instance fields
// initializer. This flag is set when creating the
// SharedFunctionInfo as a reminder to emit the initializer call
// when generating code later.
DECL_BOOLEAN_ACCESSORS(requires_instance_fields_initializer)
// [source code]: Source code for the function. // [source code]: Source code for the function.
bool HasSourceCode() const; bool HasSourceCode() const;
Handle<Object> GetSourceCode(); Handle<Object> GetSourceCode();
...@@ -457,17 +463,18 @@ class SharedFunctionInfo : public HeapObject { ...@@ -457,17 +463,18 @@ class SharedFunctionInfo : public HeapObject {
#undef START_POSITION_AND_TYPE_BIT_FIELDS #undef START_POSITION_AND_TYPE_BIT_FIELDS
// Bit positions in |compiler_hints|. // Bit positions in |compiler_hints|.
#define COMPILER_HINTS_BIT_FIELDS(V, _) \ #define COMPILER_HINTS_BIT_FIELDS(V, _) \
V(IsNativeBit, bool, 1, _) \ V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \ V(IsStrictBit, bool, 1, _) \
V(FunctionKindBits, FunctionKind, 10, _) \ V(FunctionKindBits, FunctionKind, 10, _) \
V(HasDuplicateParametersBit, bool, 1, _) \ V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \ V(AllowLazyCompilationBit, bool, 1, _) \
V(NeedsHomeObjectBit, bool, 1, _) \ V(NeedsHomeObjectBit, bool, 1, _) \
V(IsDeclarationBit, bool, 1, _) \ V(IsDeclarationBit, bool, 1, _) \
V(IsAsmWasmBrokenBit, bool, 1, _) \ V(IsAsmWasmBrokenBit, bool, 1, _) \
V(FunctionMapIndexBits, int, 5, _) \ V(FunctionMapIndexBits, int, 5, _) \
V(DisabledOptimizationReasonBits, BailoutReason, 7, _) V(DisabledOptimizationReasonBits, BailoutReason, 7, _) \
V(RequiresInstanceFieldsInitializer, bool, 1, _)
DEFINE_BIT_FIELDS(COMPILER_HINTS_BIT_FIELDS) DEFINE_BIT_FIELDS(COMPILER_HINTS_BIT_FIELDS)
#undef COMPILER_HINTS_BIT_FIELDS #undef COMPILER_HINTS_BIT_FIELDS
......
...@@ -54,6 +54,8 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared) ...@@ -54,6 +54,8 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
function_literal_id_ = shared->function_literal_id(); function_literal_id_ = shared->function_literal_id();
set_language_mode(shared->language_mode()); set_language_mode(shared->language_mode());
set_asm_wasm_broken(shared->is_asm_wasm_broken()); set_asm_wasm_broken(shared->is_asm_wasm_broken());
set_requires_instance_fields_initializer(
shared->requires_instance_fields_initializer());
Handle<Script> script(Script::cast(shared->script())); Handle<Script> script(Script::cast(shared->script()));
set_script(script); set_script(script);
......
...@@ -79,6 +79,9 @@ class V8_EXPORT_PRIVATE ParseInfo { ...@@ -79,6 +79,9 @@ class V8_EXPORT_PRIVATE ParseInfo {
FLAG_ACCESSOR(kCollectTypeProfile, collect_type_profile, FLAG_ACCESSOR(kCollectTypeProfile, collect_type_profile,
set_collect_type_profile) set_collect_type_profile)
FLAG_ACCESSOR(kIsAsmWasmBroken, is_asm_wasm_broken, set_asm_wasm_broken) FLAG_ACCESSOR(kIsAsmWasmBroken, is_asm_wasm_broken, set_asm_wasm_broken)
FLAG_ACCESSOR(kRequiresInstanceFieldsInitializer,
requires_instance_fields_initializer,
set_requires_instance_fields_initializer)
FLAG_ACCESSOR(kBlockCoverageEnabled, block_coverage_enabled, FLAG_ACCESSOR(kBlockCoverageEnabled, block_coverage_enabled,
set_block_coverage_enabled) set_block_coverage_enabled)
FLAG_ACCESSOR(kOnBackgroundThread, on_background_thread, FLAG_ACCESSOR(kOnBackgroundThread, on_background_thread,
...@@ -257,6 +260,7 @@ class V8_EXPORT_PRIVATE ParseInfo { ...@@ -257,6 +260,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
kCollectTypeProfile = 1 << 10, kCollectTypeProfile = 1 << 10,
kBlockCoverageEnabled = 1 << 11, kBlockCoverageEnabled = 1 << 11,
kIsAsmWasmBroken = 1 << 12, kIsAsmWasmBroken = 1 << 12,
kRequiresInstanceFieldsInitializer = 1 << 13,
kOnBackgroundThread = 1 << 14, kOnBackgroundThread = 1 << 14,
}; };
......
...@@ -212,7 +212,6 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, ...@@ -212,7 +212,6 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
parameter_count, FunctionLiteral::kNoDuplicateParameters, parameter_count, FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos, FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos,
true, GetNextFunctionLiteralId()); true, GetNextFunctionLiteralId());
return function_literal; return function_literal;
} }
...@@ -924,10 +923,22 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, ...@@ -924,10 +923,22 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
DCHECK_EQ(scope(), outer); DCHECK_EQ(scope(), outer);
result = DefaultConstructor(raw_name, IsDerivedConstructor(kind), result = DefaultConstructor(raw_name, IsDerivedConstructor(kind),
info->start_position(), info->end_position()); info->start_position(), info->end_position());
if (info->requires_instance_fields_initializer()) {
result->set_instance_class_fields_initializer(
result->scope()->NewUnresolved(
factory(),
ast_value_factory()->dot_instance_fields_initializer_string()));
}
} else { } else {
result = ParseFunctionLiteral( result = ParseFunctionLiteral(
raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind, raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind,
kNoSourcePosition, function_type, info->language_mode(), &ok); kNoSourcePosition, function_type, info->language_mode(), &ok);
if (info->requires_instance_fields_initializer()) {
result->set_instance_class_fields_initializer(
result->scope()->NewUnresolved(
factory(),
ast_value_factory()->dot_instance_fields_initializer_string()));
}
} }
// Make sure the results agree. // Make sure the results agree.
DCHECK(ok == (result != nullptr)); DCHECK(ok == (result != nullptr));
...@@ -3326,26 +3337,25 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope, ...@@ -3326,26 +3337,25 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope,
} }
FunctionLiteral* instance_fields_initializer_function = nullptr; FunctionLiteral* instance_fields_initializer_function = nullptr;
Variable* instance_fields_initializer_var = nullptr; VariableProxy* instance_fields_initializer_proxy = nullptr;
if (class_info->has_instance_class_fields) { if (class_info->has_instance_class_fields) {
instance_fields_initializer_function = CreateInitializerFunction( instance_fields_initializer_function = CreateInitializerFunction(
class_info->instance_fields_scope, class_info->instance_fields); class_info->instance_fields_scope, class_info->instance_fields);
instance_fields_initializer_var = CreateSyntheticContextVariable( Variable* instance_fields_initializer_var = CreateSyntheticContextVariable(
ast_value_factory()->dot_instance_fields_initializer_string(), ast_value_factory()->dot_instance_fields_initializer_string(),
CHECK_OK); CHECK_OK);
instance_fields_initializer_proxy =
factory()->NewVariableProxy(instance_fields_initializer_var);
class_info->constructor->set_instance_class_fields_initializer( class_info->constructor->set_instance_class_fields_initializer(
instance_fields_initializer_var); instance_fields_initializer_proxy);
// TODO(gsathya): Add support for lazy parsing instance class fields.
class_info->constructor->SetShouldEagerCompile();
} }
ClassLiteral* class_literal = factory()->NewClassLiteral( ClassLiteral* class_literal = factory()->NewClassLiteral(
block_scope, class_info->variable, class_info->extends, block_scope, class_info->variable, class_info->extends,
class_info->constructor, class_info->properties, class_info->constructor, class_info->properties,
static_fields_initializer, instance_fields_initializer_function, static_fields_initializer, instance_fields_initializer_function,
instance_fields_initializer_var, pos, end_pos, instance_fields_initializer_proxy, 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);
......
...@@ -956,11 +956,12 @@ class PreParser : public ParserBase<PreParser> { ...@@ -956,11 +956,12 @@ class PreParser : public ParserBase<PreParser> {
bool is_inner_function, bool may_abort, bool* ok) { bool is_inner_function, bool may_abort, bool* ok) {
UNREACHABLE(); UNREACHABLE();
} }
Expression ParseFunctionLiteral( Expression ParseFunctionLiteral(Identifier name,
Identifier name, Scanner::Location function_name_location, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind, FunctionNameValidity function_name_validity,
int function_token_pos, FunctionLiteral::FunctionType function_type, FunctionKind kind, int function_token_pos,
LanguageMode language_mode, bool* ok); FunctionLiteral::FunctionType function_type,
LanguageMode language_mode, bool* ok);
LazyParsingResult ParseStatementListAndLogFunction( LazyParsingResult ParseStatementListAndLogFunction(
PreParserFormalParameters* formals, bool maybe_abort, bool* ok); PreParserFormalParameters* formals, bool maybe_abort, bool* ok);
......
...@@ -21,6 +21,16 @@ ...@@ -21,6 +21,16 @@
assertEquals(undefined, c.a); assertEquals(undefined, c.a);
} }
{
class C {
x = 1;
constructor() {}
}
let c = new C;
assertEquals(1, c.x);
}
{ {
let x = 'a'; let x = 'a';
class C { class C {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment