From cfebe6034c39562681c11e8381448f4934972429 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 28 Nov 2016 03:40:22 -0800 Subject: [PATCH] Assign unique IDs to FunctionLiterals They're supposed to be stable across several parse passes, so we'll also store them in the associated SharedFunctionInfos To achieve this, the PreParser and Parser need to generated the same number of FunctionLiterals. To achieve this, we teach the PreParser about desuggaring of class literals. For regular functions, the function IDs are assigned in the order they occur in the source. For arrow functions, however, we only know that it's an arrow function after parsing the parameter list, and so the ID assigned to the arrow function is larger than the IDs assigned to functions defined in the parameter list. This implies that we have to reset the function ID counter to before the parameter list when re-parsing an arrow function. To be able to do this, we store the number of function literals found in the parameter list of arrow functions as well. BUG=v8:5589 Review-Url: https://codereview.chromium.org/2481163002 Cr-Commit-Position: refs/heads/master@{#41309} --- BUILD.gn | 2 + src/ast/ast-function-literal-id-reindexer.cc | 28 ++++++++ src/ast/ast-function-literal-id-reindexer.h | 36 ++++++++++ src/ast/ast.h | 20 ++++-- .../compiler-dispatcher-job.cc | 1 + src/compiler.cc | 2 + src/factory.cc | 2 + src/objects-inl.h | 1 + src/objects.cc | 3 + src/objects.h | 14 +++- src/parsing/parse-info.cc | 2 + src/parsing/parse-info.h | 6 ++ src/parsing/parser-base.h | 69 ++++++++++++------- src/parsing/parser.cc | 43 ++++++++++-- src/parsing/parser.h | 4 ++ src/parsing/preparse-data-format.h | 2 +- src/parsing/preparse-data.cc | 4 +- src/parsing/preparse-data.h | 12 ++-- src/parsing/preparser.cc | 14 ++-- src/parsing/preparser.h | 20 +++++- src/runtime/runtime-function.cc | 1 + src/v8.gyp | 2 + .../compiler-dispatcher-job-unittest.cc | 1 + 23 files changed, 241 insertions(+), 48 deletions(-) create mode 100644 src/ast/ast-function-literal-id-reindexer.cc create mode 100644 src/ast/ast-function-literal-id-reindexer.h diff --git a/BUILD.gn b/BUILD.gn index 99f700a824..be9a23ebb5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -897,6 +897,8 @@ v8_source_set("v8_base") { "src/assert-scope.h", "src/ast/ast-expression-rewriter.cc", "src/ast/ast-expression-rewriter.h", + "src/ast/ast-function-literal-id-reindexer.cc", + "src/ast/ast-function-literal-id-reindexer.h", "src/ast/ast-literal-reindexer.cc", "src/ast/ast-literal-reindexer.h", "src/ast/ast-numbering.cc", diff --git a/src/ast/ast-function-literal-id-reindexer.cc b/src/ast/ast-function-literal-id-reindexer.cc new file mode 100644 index 0000000000..2ffc143606 --- /dev/null +++ b/src/ast/ast-function-literal-id-reindexer.cc @@ -0,0 +1,28 @@ +// Copyright 2016 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. + +#include "src/ast/ast-function-literal-id-reindexer.h" + +#include "src/ast/ast.h" + +namespace v8 { +namespace internal { + +AstFunctionLiteralIdReindexer::AstFunctionLiteralIdReindexer(size_t stack_limit, + int delta) + : AstTraversalVisitor(stack_limit), delta_(delta) {} + +AstFunctionLiteralIdReindexer::~AstFunctionLiteralIdReindexer() {} + +void AstFunctionLiteralIdReindexer::Reindex(Expression* pattern) { + Visit(pattern); +} + +void AstFunctionLiteralIdReindexer::VisitFunctionLiteral(FunctionLiteral* lit) { + AstTraversalVisitor::VisitFunctionLiteral(lit); + lit->set_function_literal_id(lit->function_literal_id() + delta_); +} + +} // namespace internal +} // namespace v8 diff --git a/src/ast/ast-function-literal-id-reindexer.h b/src/ast/ast-function-literal-id-reindexer.h new file mode 100644 index 0000000000..837595f41b --- /dev/null +++ b/src/ast/ast-function-literal-id-reindexer.h @@ -0,0 +1,36 @@ +// Copyright 2016 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. + +#ifndef V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER +#define V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER + +#include "src/ast/ast-traversal-visitor.h" +#include "src/base/macros.h" + +namespace v8 { +namespace internal { + +// Changes the ID of all FunctionLiterals in the given Expression by adding the +// given delta. +class AstFunctionLiteralIdReindexer final + : public AstTraversalVisitor { + public: + AstFunctionLiteralIdReindexer(size_t stack_limit, int delta); + ~AstFunctionLiteralIdReindexer(); + + void Reindex(Expression* pattern); + + // AstTraversalVisitor implementation. + void VisitFunctionLiteral(FunctionLiteral* lit); + + private: + int delta_; + + DISALLOW_COPY_AND_ASSIGN(AstFunctionLiteralIdReindexer); +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER diff --git a/src/ast/ast.h b/src/ast/ast.h index 89dc75922a..a82fb6f372 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2572,6 +2572,8 @@ class FunctionLiteral final : public Expression { kAccessorOrMethod }; + enum IdType { kIdTypeInvalid = -1, kIdTypeTopLevel = 0 }; + enum ParameterFlag { kNoDuplicateParameters, kHasDuplicateParameters }; enum EagerCompileHint { kShouldEagerCompile, kShouldLazyCompile }; @@ -2711,6 +2713,11 @@ class FunctionLiteral final : public Expression { return std::max(start_position(), end_position() - (has_braces_ ? 1 : 0)); } + int function_literal_id() const { return function_literal_id_; } + void set_function_literal_id(int function_literal_id) { + function_literal_id_ = function_literal_id; + } + private: friend class AstNodeFactory; @@ -2721,7 +2728,7 @@ class FunctionLiteral final : public Expression { int function_length, FunctionType function_type, ParameterFlag has_duplicate_parameters, EagerCompileHint eager_compile_hint, int position, - bool is_function, bool has_braces) + bool is_function, bool has_braces, int function_literal_id) : Expression(position, kFunctionLiteral), materialized_literal_count_(materialized_literal_count), expected_property_count_(expected_property_count), @@ -2734,7 +2741,8 @@ class FunctionLiteral final : public Expression { scope_(scope), body_(body), raw_inferred_name_(ast_value_factory->empty_string()), - ast_properties_(zone) { + ast_properties_(zone), + function_literal_id_(function_literal_id) { bit_field_ |= FunctionTypeBits::encode(function_type) | Pretenure::encode(false) | HasDuplicateParameters::encode(has_duplicate_parameters == @@ -2775,6 +2783,7 @@ class FunctionLiteral final : public Expression { const AstString* raw_inferred_name_; Handle inferred_name_; AstProperties ast_properties_; + int function_literal_id_; }; // Property is used for passing information @@ -3464,12 +3473,12 @@ class AstNodeFactory final BASE_EMBEDDED { FunctionLiteral::ParameterFlag has_duplicate_parameters, FunctionLiteral::FunctionType function_type, FunctionLiteral::EagerCompileHint eager_compile_hint, int position, - bool has_braces) { + bool has_braces, int function_literal_id) { return new (zone_) FunctionLiteral( zone_, name, ast_value_factory_, scope, body, materialized_literal_count, expected_property_count, parameter_count, function_length, function_type, has_duplicate_parameters, - eager_compile_hint, position, true, has_braces); + eager_compile_hint, position, true, has_braces, function_literal_id); } // Creates a FunctionLiteral representing a top-level script, the @@ -3484,7 +3493,8 @@ class AstNodeFactory final BASE_EMBEDDED { body, materialized_literal_count, expected_property_count, parameter_count, parameter_count, FunctionLiteral::kAnonymousExpression, FunctionLiteral::kNoDuplicateParameters, - FunctionLiteral::kShouldLazyCompile, 0, false, true); + FunctionLiteral::kShouldLazyCompile, 0, false, true, + FunctionLiteral::kIdTypeTopLevel); } ClassLiteral::Property* NewClassLiteralProperty( diff --git a/src/compiler-dispatcher/compiler-dispatcher-job.cc b/src/compiler-dispatcher/compiler-dispatcher-job.cc index b87a4a5c32..40ea26fb8e 100644 --- a/src/compiler-dispatcher/compiler-dispatcher-job.cc +++ b/src/compiler-dispatcher/compiler-dispatcher-job.cc @@ -76,6 +76,7 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() { parse_info_->set_end_position(shared_->end_position()); parse_info_->set_unicode_cache(unicode_cache_.get()); parse_info_->set_language_mode(shared_->language_mode()); + parse_info_->set_function_literal_id(shared_->function_literal_id()); parser_.reset(new Parser(parse_info_.get())); Handle outer_scope_info( diff --git a/src/compiler.cc b/src/compiler.cc index 57a010c316..1c94c9ed14 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -1001,6 +1001,7 @@ Handle CompileToplevel(CompilationInfo* info) { result = NewSharedFunctionInfoForLiteral(isolate, lit, script); result->set_is_toplevel(true); parse_info->set_shared_info(result); + parse_info->set_function_literal_id(result->function_literal_id()); // Compile the code. if (!CompileUnoptimizedCode(info)) { @@ -1588,6 +1589,7 @@ Handle Compiler::GetSharedFunctionInfo( CompilationInfo info(&parse_info, Handle::null()); parse_info.set_literal(literal); parse_info.set_shared_info(result); + parse_info.set_function_literal_id(result->function_literal_id()); parse_info.set_language_mode(literal->scope()->language_mode()); parse_info.set_ast_value_factory( outer_info->parse_info()->ast_value_factory()); diff --git a/src/factory.cc b/src/factory.cc index 958adcfa29..e38b2f6730 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -6,6 +6,7 @@ #include "src/accessors.h" #include "src/allocation-site-scopes.h" +#include "src/ast/ast.h" #include "src/base/bits.h" #include "src/bootstrapper.h" #include "src/compiler.h" @@ -2312,6 +2313,7 @@ Handle Factory::NewSharedFunctionInfo( Handle feedback_metadata = TypeFeedbackMetadata::New(isolate(), &empty_spec); share->set_feedback_metadata(*feedback_metadata, SKIP_WRITE_BARRIER); + share->set_function_literal_id(FunctionLiteral::kIdTypeInvalid); #if TRACE_MAPS share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId()); #endif diff --git a/src/objects-inl.h b/src/objects-inl.h index 42f1cb63b3..8bbcd93218 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -5993,6 +5993,7 @@ ACCESSORS(SharedFunctionInfo, optimized_code_map, FixedArray, ACCESSORS(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset) ACCESSORS(SharedFunctionInfo, feedback_metadata, TypeFeedbackMetadata, kFeedbackMetadataOffset) +SMI_ACCESSORS(SharedFunctionInfo, function_literal_id, kFunctionLiteralIdOffset) #if TRACE_MAPS SMI_ACCESSORS(SharedFunctionInfo, unique_id, kUniqueIdOffset) #endif diff --git a/src/objects.cc b/src/objects.cc index 9a903f1ff5..f7812a4332 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -13638,8 +13638,10 @@ MaybeHandle Script::FindSharedFunctionInfo( if (fun->function_token_position() == shared->function_token_position() && fun->start_position() == shared->start_position() && fun->end_position() == shared->end_position()) { + DCHECK_EQ(fun->function_literal_id(), shared->function_literal_id()); return Handle(shared); } + DCHECK_NE(fun->function_literal_id(), shared->function_literal_id()); } return MaybeHandle(); } @@ -13991,6 +13993,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral( shared_info->set_requires_class_field_init(lit->requires_class_field_init()); shared_info->set_is_class_field_initializer( lit->is_class_field_initializer()); + shared_info->set_function_literal_id(lit->function_literal_id()); SetExpectedNofPropertiesFromEstimate(shared_info, lit); } diff --git a/src/objects.h b/src/objects.h index f291d692cf..86848b6f95 100644 --- a/src/objects.h +++ b/src/objects.h @@ -7516,6 +7516,12 @@ class SharedFunctionInfo: public HeapObject { // available. DECL_ACCESSORS(feedback_metadata, TypeFeedbackMetadata) + // [function_literal_id] - uniquely identifies the FunctionLiteral this + // SharedFunctionInfo represents within its script, or -1 if this + // SharedFunctionInfo object doesn't correspond to a parsed FunctionLiteral. + inline int function_literal_id() const; + inline void set_function_literal_id(int value); + #if TRACE_MAPS // [unique_id] - For --trace-maps purposes, an identifier that's persistent // even if the GC moves this SharedFunctionInfo. @@ -7824,13 +7830,15 @@ class SharedFunctionInfo: public HeapObject { static const int kFunctionIdentifierOffset = kDebugInfoOffset + kPointerSize; static const int kFeedbackMetadataOffset = kFunctionIdentifierOffset + kPointerSize; + static const int kFunctionLiteralIdOffset = + kFeedbackMetadataOffset + kPointerSize; #if TRACE_MAPS - static const int kUniqueIdOffset = kFeedbackMetadataOffset + kPointerSize; + static const int kUniqueIdOffset = kFunctionLiteralIdOffset + kPointerSize; static const int kLastPointerFieldOffset = kUniqueIdOffset; #else // Just to not break the postmortrem support with conditional offsets - static const int kUniqueIdOffset = kFeedbackMetadataOffset; - static const int kLastPointerFieldOffset = kFeedbackMetadataOffset; + static const int kUniqueIdOffset = kFunctionLiteralIdOffset; + static const int kLastPointerFieldOffset = kFunctionLiteralIdOffset; #endif #if V8_HOST_ARCH_32_BIT diff --git a/src/parsing/parse-info.cc b/src/parsing/parse-info.cc index 78f637bc41..b2d9a85e6c 100644 --- a/src/parsing/parse-info.cc +++ b/src/parsing/parse-info.cc @@ -25,6 +25,7 @@ ParseInfo::ParseInfo(Zone* zone) compiler_hints_(0), start_position_(0), end_position_(0), + function_literal_id_(FunctionLiteral::kIdTypeInvalid), isolate_(nullptr), cached_data_(nullptr), ast_value_factory_(nullptr), @@ -43,6 +44,7 @@ ParseInfo::ParseInfo(Zone* zone, Handle shared) set_compiler_hints(shared->compiler_hints()); set_start_position(shared->start_position()); set_end_position(shared->end_position()); + function_literal_id_ = shared->function_literal_id(); set_stack_limit(isolate_->stack_guard()->real_climit()); set_unicode_cache(isolate_->unicode_cache()); set_language_mode(shared->language_mode()); diff --git a/src/parsing/parse-info.h b/src/parsing/parse-info.h index d3d3bf0356..0988443e8f 100644 --- a/src/parsing/parse-info.h +++ b/src/parsing/parse-info.h @@ -144,6 +144,11 @@ class V8_EXPORT_PRIVATE ParseInfo { int end_position() const { return end_position_; } void set_end_position(int end_position) { end_position_ = end_position; } + int function_literal_id() const { return function_literal_id_; } + void set_function_literal_id(int function_literal_id) { + function_literal_id_ = function_literal_id; + } + // Getters for individual compiler hints. bool is_declaration() const; bool requires_class_field_init() const; @@ -224,6 +229,7 @@ class V8_EXPORT_PRIVATE ParseInfo { int compiler_hints_; int start_position_; int end_position_; + int function_literal_id_; // TODO(titzer): Move handles and isolate out of ParseInfo. Isolate* isolate_; diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h index 69bcb48e69..ae917b82f4 100644 --- a/src/parsing/parser-base.h +++ b/src/parsing/parser-base.h @@ -209,6 +209,7 @@ class ParserBase { scanner_(scanner), stack_overflow_(false), default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile), + function_literal_id_(0), allow_natives_(false), allow_tailcalls_(false), allow_harmony_do_expressions_(false), @@ -246,6 +247,13 @@ class ParserBase { return default_eager_compile_hint_; } + int GetNextFunctionLiteralId() { return ++function_literal_id_; } + int GetLastFunctionLiteralId() const { return function_literal_id_; } + + void SkipFunctionLiterals(int delta) { function_literal_id_ += delta; } + + void ResetFunctionLiteralId() { function_literal_id_ = 0; } + Zone* zone() const { return zone_; } protected: @@ -1159,7 +1167,8 @@ class ParserBase { ExpressionT ParseObjectLiteral(bool* ok); ClassLiteralPropertyT ParseClassPropertyDefinition( ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name, - bool* has_seen_constructor, bool* ok); + bool* has_seen_constructor, ClassLiteralProperty::Kind* property_kind, + bool* is_static, bool* ok); FunctionLiteralT ParseClassFieldForInitializer(bool has_initializer, bool* ok); ObjectLiteralPropertyT ParseObjectPropertyDefinition( @@ -1443,6 +1452,8 @@ class ParserBase { FunctionLiteral::EagerCompileHint default_eager_compile_hint_; + int function_literal_id_; + bool allow_natives_; bool allow_tailcalls_; bool allow_harmony_do_expressions_; @@ -2127,17 +2138,17 @@ typename ParserBase::ExpressionT ParserBase::ParsePropertyName( template typename ParserBase::ClassLiteralPropertyT -ParserBase::ParseClassPropertyDefinition(ClassLiteralChecker* checker, - bool has_extends, - bool* is_computed_name, - bool* has_seen_constructor, - bool* ok) { +ParserBase::ParseClassPropertyDefinition( + ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name, + bool* has_seen_constructor, ClassLiteralProperty::Kind* property_kind, + bool* is_static, bool* ok) { DCHECK(has_seen_constructor != nullptr); bool is_get = false; bool is_set = false; bool is_generator = false; bool is_async = false; - bool is_static = false; + *is_static = false; + *property_kind = ClassLiteralProperty::METHOD; PropertyKind kind = PropertyKind::kNotSet; Token::Value name_token = peek(); @@ -2155,7 +2166,7 @@ ParserBase::ParseClassPropertyDefinition(ClassLiteralChecker* checker, name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static' name_expression = factory()->NewStringLiteral(name, position()); } else { - is_static = true; + *is_static = true; name_expression = ParsePropertyName( &name, &kind, &is_generator, &is_get, &is_set, &is_async, is_computed_name, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); @@ -2182,9 +2193,10 @@ ParserBase::ParseClassPropertyDefinition(ClassLiteralChecker* checker, ExpressionT function_literal = ParseClassFieldForInitializer( has_initializer, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); ExpectSemicolon(CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + *property_kind = ClassLiteralProperty::FIELD; return factory()->NewClassLiteralProperty( - name_expression, function_literal, ClassLiteralProperty::FIELD, - is_static, *is_computed_name); + name_expression, function_literal, *property_kind, *is_static, + *is_computed_name); } else { ReportUnexpectedToken(Next()); *ok = false; @@ -2201,7 +2213,7 @@ ParserBase::ParseClassPropertyDefinition(ClassLiteralChecker* checker, if (!*is_computed_name) { checker->CheckClassMethodName( name_token, PropertyKind::kMethodProperty, is_generator, is_async, - is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + *is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); } FunctionKind kind = is_generator @@ -2209,7 +2221,7 @@ ParserBase::ParseClassPropertyDefinition(ClassLiteralChecker* checker, : is_async ? FunctionKind::kAsyncConciseMethod : FunctionKind::kConciseMethod; - if (!is_static && impl()->IsConstructor(name)) { + if (!*is_static && impl()->IsConstructor(name)) { *has_seen_constructor = true; kind = has_extends ? FunctionKind::kSubclassConstructor : FunctionKind::kBaseConstructor; @@ -2220,9 +2232,10 @@ ParserBase::ParseClassPropertyDefinition(ClassLiteralChecker* checker, kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + *property_kind = ClassLiteralProperty::METHOD; return factory()->NewClassLiteralProperty(name_expression, value, - ClassLiteralProperty::METHOD, - is_static, *is_computed_name); + *property_kind, *is_static, + *is_computed_name); } case PropertyKind::kAccessorProperty: { @@ -2231,7 +2244,7 @@ ParserBase::ParseClassPropertyDefinition(ClassLiteralChecker* checker, if (!*is_computed_name) { checker->CheckClassMethodName( name_token, PropertyKind::kAccessorProperty, false, false, - is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + *is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); // Make sure the name expression is a string since we need a Name for // Runtime_DefineAccessorPropertyUnchecked and since we can determine // this statically we can skip the extra runtime check. @@ -2251,10 +2264,11 @@ ParserBase::ParseClassPropertyDefinition(ClassLiteralChecker* checker, impl()->AddAccessorPrefixToFunctionName(is_get, value, name); } - return factory()->NewClassLiteralProperty( - name_expression, value, - is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER, - is_static, *is_computed_name); + *property_kind = + is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER; + return factory()->NewClassLiteralProperty(name_expression, value, + *property_kind, *is_static, + *is_computed_name); } } UNREACHABLE(); @@ -2292,7 +2306,7 @@ ParserBase::ParseClassFieldForInitializer(bool has_initializer, initializer_state.expected_property_count(), 0, 0, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, default_eager_compile_hint_, - initializer_scope->start_position(), true); + initializer_scope->start_position(), true, GetNextFunctionLiteralId()); function_literal->set_is_class_field_initializer(true); return function_literal; } @@ -3927,6 +3941,7 @@ ParserBase::ParseArrowFunctionLiteral( StatementListT body = impl()->NullStatementList(); int materialized_literal_count = -1; int expected_property_count = -1; + int function_literal_id = GetNextFunctionLiteralId(); FunctionKind kind = formal_parameters.scope->function_kind(); FunctionLiteral::EagerCompileHint eager_compile_hint = @@ -4064,7 +4079,8 @@ ParserBase::ParseArrowFunctionLiteral( formal_parameters.num_parameters(), formal_parameters.function_length, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, eager_compile_hint, - formal_parameters.scope->start_position(), has_braces); + formal_parameters.scope->start_position(), has_braces, + function_literal_id); function_literal->set_function_token_position( formal_parameters.scope->start_position()); @@ -4122,14 +4138,21 @@ typename ParserBase::ExpressionT ParserBase::ParseClassLiteral( FuncNameInferrer::State fni_state(fni_); bool is_computed_name = false; // Classes do not care about computed // property names here. + bool is_static; + ClassLiteralProperty::Kind property_kind; ExpressionClassifier property_classifier(this); + // If we haven't seen the constructor yet, it potentially is the next + // property. + bool is_constructor = !class_info.has_seen_constructor; ClassLiteralPropertyT property = ParseClassPropertyDefinition( &checker, has_extends, &is_computed_name, - &class_info.has_seen_constructor, CHECK_OK); + &class_info.has_seen_constructor, &property_kind, &is_static, CHECK_OK); + is_constructor &= class_info.has_seen_constructor; impl()->RewriteNonPattern(CHECK_OK); impl()->AccumulateFormalParameterContainmentErrors(); - impl()->DeclareClassProperty(name, property, &class_info, CHECK_OK); + impl()->DeclareClassProperty(name, property, property_kind, is_static, + is_constructor, &class_info, CHECK_OK); impl()->InferFunctionName(); } diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc index 42a35958ba..19ca0670d0 100644 --- a/src/parsing/parser.cc +++ b/src/parsing/parser.cc @@ -8,6 +8,7 @@ #include "src/api.h" #include "src/ast/ast-expression-rewriter.h" +#include "src/ast/ast-function-literal-id-reindexer.h" #include "src/ast/ast-literal-reindexer.h" #include "src/ast/ast-traversal-visitor.h" #include "src/ast/ast.h" @@ -290,7 +291,7 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, expected_property_count, parameter_count, parameter_count, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos, - true); + true, GetNextFunctionLiteralId()); function_literal->set_requires_class_field_init(requires_class_field_init); @@ -744,6 +745,9 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { DCHECK_NULL(target_stack_); ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY); + ResetFunctionLiteralId(); + DCHECK(info->function_literal_id() == FunctionLiteral::kIdTypeTopLevel || + info->function_literal_id() == FunctionLiteral::kIdTypeInvalid); FunctionLiteral* result = NULL; { @@ -904,6 +908,10 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); fni_->PushEnclosingName(raw_name); + ResetFunctionLiteralId(); + DCHECK_LT(0, info->function_literal_id()); + SkipFunctionLiterals(info->function_literal_id() - 1); + ParsingModeScope parsing_mode(this, PARSE_EAGERLY); // Place holder for the result. @@ -970,6 +978,21 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, if (ok) { checkpoint.Restore(&formals.materialized_literals_count); + if (GetLastFunctionLiteralId() != info->function_literal_id() - 1) { + // If there were FunctionLiterals in the parameters, we need to + // renumber them to shift down so the next function literal id for + // the arrow function is the one requested. + AstFunctionLiteralIdReindexer reindexer( + stack_limit_, + (info->function_literal_id() - 1) - GetLastFunctionLiteralId()); + for (const auto p : formals.params) { + if (p.pattern != nullptr) reindexer.Reindex(p.pattern); + if (p.initializer != nullptr) reindexer.Reindex(p.initializer); + } + ResetFunctionLiteralId(); + SkipFunctionLiterals(info->function_literal_id() - 1); + } + // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should // not be observable, or else the preparser would have failed. Expression* expression = ParseArrowFunctionLiteral(true, formals, &ok); @@ -1022,6 +1045,8 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, // Make sure the target stack is empty. DCHECK_NULL(target_stack_); + DCHECK_IMPLIES(result, + info->function_literal_id() == result->function_literal_id()); return result; } @@ -2629,6 +2654,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( int num_parameters = -1; int function_length = -1; bool has_duplicate_parameters = false; + int function_literal_id = GetNextFunctionLiteralId(); Zone* outer_zone = zone(); DeclarationScope* scope; @@ -2745,7 +2771,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( FunctionLiteral* function_literal = factory()->NewFunctionLiteral( function_name, scope, body, materialized_literal_count, expected_property_count, num_parameters, function_length, - duplicate_parameters, function_type, eager_compile_hint, pos, true); + duplicate_parameters, function_type, eager_compile_hint, pos, true, + function_literal_id); function_literal->set_function_token_position(function_token_pos); if (should_be_used_once_hint) function_literal->set_should_be_used_once_hint(); @@ -2793,6 +2820,7 @@ Parser::LazyParsingResult Parser::SkipFunction( if (entry.uses_super_property()) function_scope->RecordSuperPropertyUsage(); if (entry.calls_eval()) function_scope->RecordEvalCall(); + SkipFunctionLiterals(entry.num_inner_functions()); return kLazyParsingComplete; } cached_parse_data_->Reject(); @@ -2845,13 +2873,15 @@ Parser::LazyParsingResult Parser::SkipFunction( *has_duplicate_parameters = logger->has_duplicate_parameters(); *materialized_literal_count = logger->literals(); *expected_property_count = logger->properties(); + SkipFunctionLiterals(logger->num_inner_functions()); if (!is_inner_function && produce_cached_parse_data()) { DCHECK(log_); log_->LogFunction( function_scope->start_position(), function_scope->end_position(), *num_parameters, *function_length, *has_duplicate_parameters, *materialized_literal_count, *expected_property_count, language_mode(), - function_scope->uses_super_property(), function_scope->calls_eval()); + function_scope->uses_super_property(), function_scope->calls_eval(), + logger->num_inner_functions()); } return kLazyParsingComplete; } @@ -3432,7 +3462,7 @@ FunctionLiteral* Parser::SynthesizeClassFieldInitializer(int count) { FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, FunctionLiteral::kShouldLazyCompile, initializer_scope->start_position(), - true); + true, GetNextFunctionLiteralId()); function_literal->set_is_class_field_initializer(true); return function_literal; } @@ -3476,8 +3506,11 @@ void Parser::DeclareClassVariable(const AstRawString* name, Scope* block_scope, // - properties void Parser::DeclareClassProperty(const AstRawString* class_name, ClassLiteralProperty* property, + ClassLiteralProperty::Kind kind, + bool is_static, bool is_constructor, ClassInfo* class_info, bool* ok) { - if (class_info->has_seen_constructor && class_info->constructor == nullptr) { + if (is_constructor) { + DCHECK(!class_info->constructor); class_info->constructor = GetPropertyValue(property)->AsFunctionLiteral(); DCHECK_NOT_NULL(class_info->constructor); class_info->constructor->set_raw_name( diff --git a/src/parsing/parser.h b/src/parsing/parser.h index 75e8bdce1d..934b0ce8df 100644 --- a/src/parsing/parser.h +++ b/src/parsing/parser.h @@ -37,6 +37,7 @@ class FunctionEntry BASE_EMBEDDED { kLiteralCountIndex, kPropertyCountIndex, kFlagsIndex, + kNumInnerFunctionsIndex, kSize }; @@ -80,6 +81,7 @@ class FunctionEntry BASE_EMBEDDED { bool has_duplicate_parameters() const { return HasDuplicateParametersField::decode(backing_[kFlagsIndex]); } + int num_inner_functions() const { return backing_[kNumInnerFunctionsIndex]; } bool is_valid() const { return !backing_.is_empty(); } @@ -353,6 +355,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase) { int class_token_pos, bool* ok); V8_INLINE void DeclareClassProperty(const AstRawString* class_name, ClassLiteralProperty* property, + ClassLiteralProperty::Kind kind, + bool is_static, bool is_constructor, ClassInfo* class_info, bool* ok); V8_INLINE Expression* RewriteClassLiteral(const AstRawString* name, ClassInfo* class_info, int pos, diff --git a/src/parsing/preparse-data-format.h b/src/parsing/preparse-data-format.h index 30d1d75a4f..32e9a23709 100644 --- a/src/parsing/preparse-data-format.h +++ b/src/parsing/preparse-data-format.h @@ -14,7 +14,7 @@ struct PreparseDataConstants { public: // Layout and constants of the preparse data exchange format. static const unsigned kMagicNumber = 0xBadDead; - static const unsigned kCurrentVersion = 13; + static const unsigned kCurrentVersion = 14; static const int kMagicOffset = 0; static const int kVersionOffset = 1; diff --git a/src/parsing/preparse-data.cc b/src/parsing/preparse-data.cc index e9a4e8f4b5..c3e261d5ab 100644 --- a/src/parsing/preparse-data.cc +++ b/src/parsing/preparse-data.cc @@ -16,7 +16,8 @@ void ParserLogger::LogFunction(int start, int end, int num_parameters, int function_length, bool has_duplicate_parameters, int literals, int properties, LanguageMode language_mode, - bool uses_super_property, bool calls_eval) { + bool uses_super_property, bool calls_eval, + int num_inner_functions) { function_store_.Add(start); function_store_.Add(end); function_store_.Add(num_parameters); @@ -26,6 +27,7 @@ void ParserLogger::LogFunction(int start, int end, int num_parameters, function_store_.Add( FunctionEntry::EncodeFlags(language_mode, uses_super_property, calls_eval, has_duplicate_parameters)); + function_store_.Add(num_inner_functions); } ParserLogger::ParserLogger() { diff --git a/src/parsing/preparse-data.h b/src/parsing/preparse-data.h index 767484ad7f..ca70f8a45f 100644 --- a/src/parsing/preparse-data.h +++ b/src/parsing/preparse-data.h @@ -52,17 +52,19 @@ class PreParserLogger final { : end_(-1), num_parameters_(-1), function_length_(-1), - has_duplicate_parameters_(false) {} + has_duplicate_parameters_(false), + num_inner_functions_(-1) {} void LogFunction(int end, int num_parameters, int function_length, - bool has_duplicate_parameters, int literals, - int properties) { + bool has_duplicate_parameters, int literals, int properties, + int num_inner_functions) { end_ = end; num_parameters_ = num_parameters; function_length_ = function_length; has_duplicate_parameters_ = has_duplicate_parameters; literals_ = literals; properties_ = properties; + num_inner_functions_ = num_inner_functions; } int end() const { return end_; } @@ -81,6 +83,7 @@ class PreParserLogger final { int properties() const { return properties_; } + int num_inner_functions() const { return num_inner_functions_; } private: int end_; @@ -90,6 +93,7 @@ class PreParserLogger final { bool has_duplicate_parameters_; int literals_; int properties_; + int num_inner_functions_; }; class ParserLogger final { @@ -99,7 +103,7 @@ class ParserLogger final { void LogFunction(int start, int end, int num_parameters, int function_length, bool has_duplicate_parameters, int literals, int properties, LanguageMode language_mode, bool uses_super_property, - bool calls_eval); + bool calls_eval, int num_inner_functions); ScriptData* GetScriptData(); diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc index c7b2e1b5d2..306fb264d1 100644 --- a/src/parsing/preparser.cc +++ b/src/parsing/preparser.cc @@ -92,6 +92,11 @@ PreParser::PreParseResult PreParser::PreParseFunction( DCHECK(!track_unresolved_variables_); track_unresolved_variables_ = is_inner_function; + // In the preparser, we use the function literal ids to count how many + // FunctionLiterals were encountered. The PreParser doesn't actually persist + // FunctionLiterals, so there IDs don't matter. + ResetFunctionLiteralId(); + // The caller passes the function_scope which is not yet inserted into the // scope_state_. All scopes above the function_scope are ignored by the // PreParser. @@ -195,6 +200,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral( FunctionState function_state(&function_state_, &scope_state_, function_scope); DuplicateFinder duplicate_finder(scanner()->unicode_cache()); ExpressionClassifier formals_classifier(this, &duplicate_finder); + GetNextFunctionLiteralId(); Expect(Token::LPAREN, CHECK_OK); int start_position = scanner()->location().beg_pos; @@ -251,10 +257,10 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction( DCHECK_EQ(Token::RBRACE, scanner()->peek()); int body_end = scanner()->peek_location().end_pos; DCHECK(this->scope()->is_function_scope()); - log_.LogFunction(body_end, formals->num_parameters(), - formals->function_length, has_duplicate_parameters, - function_state_->materialized_literal_count(), - function_state_->expected_property_count()); + log_.LogFunction( + body_end, formals->num_parameters(), formals->function_length, + has_duplicate_parameters, function_state_->materialized_literal_count(), + function_state_->expected_property_count(), GetLastFunctionLiteralId()); return kLazyParsingComplete; } diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h index 312bd58546..f8afe17b0a 100644 --- a/src/parsing/preparser.h +++ b/src/parsing/preparser.h @@ -652,7 +652,7 @@ class PreParserFactory { FunctionLiteral::ParameterFlag has_duplicate_parameters, FunctionLiteral::FunctionType function_type, FunctionLiteral::EagerCompileHint eager_compile_hint, int position, - bool has_braces) { + bool has_braces, int function_literal_id) { return PreParserExpression::Default(); } @@ -1071,10 +1071,26 @@ class PreParser : public ParserBase { int class_token_pos, bool* ok) {} V8_INLINE void DeclareClassProperty(PreParserIdentifier class_name, PreParserExpression property, - ClassInfo* class_info, bool* ok) {} + ClassLiteralProperty::Kind kind, + bool is_static, bool is_constructor, + ClassInfo* class_info, bool* ok) { + if (kind == ClassLiteralProperty::FIELD && !is_static && !is_constructor) { + class_info->instance_field_initializers->Add( + PreParserExpression::Default(), zone()); + } + } V8_INLINE PreParserExpression RewriteClassLiteral(PreParserIdentifier name, ClassInfo* class_info, int pos, bool* ok) { + bool has_default_constructor = !class_info->has_seen_constructor; + bool has_instance_fields = + class_info->instance_field_initializers->length() > 0; + // Account for the default constructor. + if (has_default_constructor) GetNextFunctionLiteralId(); + if (allow_harmony_class_fields() && has_instance_fields) { + // Account for initializer function. + GetNextFunctionLiteralId(); + } return PreParserExpression::Default(); } diff --git a/src/runtime/runtime-function.cc b/src/runtime/runtime-function.cc index a91ab28cc6..8cf21c0e85 100644 --- a/src/runtime/runtime-function.cc +++ b/src/runtime/runtime-function.cc @@ -203,6 +203,7 @@ RUNTIME_FUNCTION(Runtime_SetCode) { source_shared->opt_count_and_bailout_reason()); target_shared->set_native(was_native); target_shared->set_profiler_ticks(source_shared->profiler_ticks()); + target_shared->set_function_literal_id(source_shared->function_literal_id()); SharedFunctionInfo::SetScript( target_shared, Handle(source_shared->script(), isolate)); diff --git a/src/v8.gyp b/src/v8.gyp index 043500be1b..a30bf58dd2 100644 --- a/src/v8.gyp +++ b/src/v8.gyp @@ -435,6 +435,8 @@ 'assert-scope.cc', 'ast/ast-expression-rewriter.cc', 'ast/ast-expression-rewriter.h', + 'ast/ast-function-literal-id-reindexer.cc', + 'ast/ast-function-literal-id-reindexer.h', 'ast/ast-literal-reindexer.cc', 'ast/ast-literal-reindexer.h', 'ast/ast-numbering.cc', diff --git a/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc b/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc index d4c54247e2..6f8d364b45 100644 --- a/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc +++ b/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc @@ -84,6 +84,7 @@ Handle CreateSharedFunctionInfo( SharedFunctionInfo::SetScript(shared, script); shared->set_end_position(source->length()); shared->set_outer_scope_info(ScopeInfo::Empty(isolate)); + shared->set_function_literal_id(1); return scope.CloseAndEscape(shared); }