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); }