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 {
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;
}
Variable* instance_class_fields_initializer() {
VariableProxy* instance_class_fields_initializer() {
return instance_class_fields_initializer_;
}
......@@ -2356,7 +2356,7 @@ class FunctionLiteral final : public Expression {
const AstConsString* raw_inferred_name_;
Handle<String> inferred_name_;
int function_literal_id_;
Variable* instance_class_fields_initializer_;
VariableProxy* instance_class_fields_initializer_;
ProducedPreParsedScopeData* produced_preparsed_scope_data_;
};
......@@ -2431,8 +2431,8 @@ class ClassLiteral final : public Expression {
return instance_fields_initializer_function_;
}
Variable* instance_fields_initializer_var() const {
return instance_fields_initializer_var_;
VariableProxy* instance_fields_initializer_proxy() const {
return instance_fields_initializer_proxy_;
}
private:
......@@ -2442,9 +2442,10 @@ class ClassLiteral final : public Expression {
FunctionLiteral* constructor, ZoneList<Property*>* properties,
FunctionLiteral* static_fields_initializer,
FunctionLiteral* instance_fields_initializer_function,
Variable* instance_fields_initializer_var, int start_position,
int end_position, bool has_name_static_property,
bool has_static_computed_names, bool is_anonymous)
VariableProxy* instance_fields_initializer_proxy,
int start_position, int end_position,
bool has_name_static_property, bool has_static_computed_names,
bool is_anonymous)
: Expression(start_position, kClassLiteral),
end_position_(end_position),
scope_(scope),
......@@ -2455,7 +2456,7 @@ class ClassLiteral final : public Expression {
static_fields_initializer_(static_fields_initializer),
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) |
HasStaticComputedNames::encode(has_static_computed_names) |
IsAnonymousExpression::encode(is_anonymous);
......@@ -2469,7 +2470,7 @@ class ClassLiteral final : public Expression {
ZoneList<Property*>* properties_;
FunctionLiteral* static_fields_initializer_;
FunctionLiteral* instance_fields_initializer_function_;
Variable* instance_fields_initializer_var_;
VariableProxy* instance_fields_initializer_proxy_;
class HasNameStaticProperty
: public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class HasStaticComputedNames
......@@ -3159,7 +3160,7 @@ class AstNodeFactory final BASE_EMBEDDED {
ZoneList<ClassLiteral::Property*>* properties,
FunctionLiteral* static_fields_initializer,
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,
bool has_static_computed_names, bool is_anonymous) {
return new (zone_) ClassLiteral(
......
......@@ -1835,7 +1835,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
// initializers.
builder()->LoadAccumulatorWithRegister(initializer);
BuildVariableAssignment(expr->instance_fields_initializer_var(),
BuildVariableAssignment(expr->instance_fields_initializer_proxy()->var(),
Token::INIT, HoleCheckMode::kElided);
builder()->LoadAccumulatorWithRegister(constructor);
}
......@@ -1990,10 +1990,10 @@ void BytecodeGenerator::VisitInitializeClassFieldsStatement(
}
void BytecodeGenerator::BuildInstanceFieldInitialization(
Variable* initializer_var) {
VariableProxy* initializer_proxy) {
RegisterList args = register_allocator()->NewRegisterList(1);
Register initializer = register_allocator()->NewRegister();
BuildVariableLoad(initializer_var, HoleCheckMode::kElided);
BuildVariableLoad(initializer_proxy->var(), HoleCheckMode::kElided);
builder()
->StoreAccumulatorInRegister(initializer)
......
......@@ -161,7 +161,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildClassLiteral(ClassLiteral* expr);
void VisitNewTargetVariable(Variable* variable);
void VisitThisFunctionVariable(Variable* variable);
void BuildInstanceFieldInitialization(Variable* initializer_var);
void BuildInstanceFieldInitialization(VariableProxy* initializer_proxy);
void BuildGeneratorObjectVariableInitialization();
void VisitBlockDeclarationsAndStatements(Block* stmt);
void VisitFunctionClosureForContext();
......
......@@ -13780,7 +13780,10 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
}
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
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
// don't have the information yet. They're set later in
// SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
......
......@@ -94,6 +94,9 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, native,
SharedFunctionInfo::IsNativeBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, is_asm_wasm_broken,
SharedFunctionInfo::IsAsmWasmBrokenBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints,
requires_instance_fields_initializer,
SharedFunctionInfo::RequiresInstanceFieldsInitializer)
bool SharedFunctionInfo::optimization_disabled() const {
return disable_optimization_reason() != BailoutReason::kNoReason;
......
......@@ -328,6 +328,12 @@ class SharedFunctionInfo : public HeapObject {
// shared function info.
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.
bool HasSourceCode() const;
Handle<Object> GetSourceCode();
......@@ -457,17 +463,18 @@ class SharedFunctionInfo : public HeapObject {
#undef START_POSITION_AND_TYPE_BIT_FIELDS
// Bit positions in |compiler_hints|.
#define COMPILER_HINTS_BIT_FIELDS(V, _) \
V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \
V(FunctionKindBits, FunctionKind, 10, _) \
V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \
V(NeedsHomeObjectBit, bool, 1, _) \
V(IsDeclarationBit, bool, 1, _) \
V(IsAsmWasmBrokenBit, bool, 1, _) \
V(FunctionMapIndexBits, int, 5, _) \
V(DisabledOptimizationReasonBits, BailoutReason, 7, _)
#define COMPILER_HINTS_BIT_FIELDS(V, _) \
V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \
V(FunctionKindBits, FunctionKind, 10, _) \
V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \
V(NeedsHomeObjectBit, bool, 1, _) \
V(IsDeclarationBit, bool, 1, _) \
V(IsAsmWasmBrokenBit, bool, 1, _) \
V(FunctionMapIndexBits, int, 5, _) \
V(DisabledOptimizationReasonBits, BailoutReason, 7, _) \
V(RequiresInstanceFieldsInitializer, bool, 1, _)
DEFINE_BIT_FIELDS(COMPILER_HINTS_BIT_FIELDS)
#undef COMPILER_HINTS_BIT_FIELDS
......
......@@ -54,6 +54,8 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
function_literal_id_ = shared->function_literal_id();
set_language_mode(shared->language_mode());
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()));
set_script(script);
......
......@@ -79,6 +79,9 @@ class V8_EXPORT_PRIVATE ParseInfo {
FLAG_ACCESSOR(kCollectTypeProfile, collect_type_profile,
set_collect_type_profile)
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,
set_block_coverage_enabled)
FLAG_ACCESSOR(kOnBackgroundThread, on_background_thread,
......@@ -257,6 +260,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
kCollectTypeProfile = 1 << 10,
kBlockCoverageEnabled = 1 << 11,
kIsAsmWasmBroken = 1 << 12,
kRequiresInstanceFieldsInitializer = 1 << 13,
kOnBackgroundThread = 1 << 14,
};
......
......@@ -212,7 +212,6 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
parameter_count, FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos,
true, GetNextFunctionLiteralId());
return function_literal;
}
......@@ -924,10 +923,22 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
DCHECK_EQ(scope(), outer);
result = DefaultConstructor(raw_name, IsDerivedConstructor(kind),
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 {
result = ParseFunctionLiteral(
raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind,
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.
DCHECK(ok == (result != nullptr));
......@@ -3326,26 +3337,25 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope,
}
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) {
instance_fields_initializer_function = CreateInitializerFunction(
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(),
CHECK_OK);
instance_fields_initializer_proxy =
factory()->NewVariableProxy(instance_fields_initializer_var);
class_info->constructor->set_instance_class_fields_initializer(
instance_fields_initializer_var);
// TODO(gsathya): Add support for lazy parsing instance class fields.
class_info->constructor->SetShouldEagerCompile();
instance_fields_initializer_proxy);
}
ClassLiteral* class_literal = factory()->NewClassLiteral(
block_scope, class_info->variable, class_info->extends,
class_info->constructor, class_info->properties,
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_static_computed_names, class_info->is_anonymous);
......
......@@ -956,11 +956,12 @@ class PreParser : public ParserBase<PreParser> {
bool is_inner_function, bool may_abort, bool* ok) {
UNREACHABLE();
}
Expression ParseFunctionLiteral(
Identifier name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
LanguageMode language_mode, bool* ok);
Expression ParseFunctionLiteral(Identifier name,
Scanner::Location function_name_location,
FunctionNameValidity function_name_validity,
FunctionKind kind, int function_token_pos,
FunctionLiteral::FunctionType function_type,
LanguageMode language_mode, bool* ok);
LazyParsingResult ParseStatementListAndLogFunction(
PreParserFormalParameters* formals, bool maybe_abort, bool* ok);
......
......@@ -21,6 +21,16 @@
assertEquals(undefined, c.a);
}
{
class C {
x = 1;
constructor() {}
}
let c = new C;
assertEquals(1, c.x);
}
{
let x = 'a';
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