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}
This commit is contained in:
jochen 2016-11-28 03:40:22 -08:00 committed by Commit bot
parent e1470db7a3
commit cfebe6034c
23 changed files with 241 additions and 48 deletions

View File

@ -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",

View File

@ -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

View File

@ -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<AstFunctionLiteralIdReindexer> {
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

View File

@ -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<String> 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(

View File

@ -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<ScopeInfo> outer_scope_info(

View File

@ -1001,6 +1001,7 @@ Handle<SharedFunctionInfo> 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<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
CompilationInfo info(&parse_info, Handle<JSFunction>::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());

View File

@ -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<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
Handle<TypeFeedbackMetadata> 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

View File

@ -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

View File

@ -13638,8 +13638,10 @@ MaybeHandle<SharedFunctionInfo> 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<SharedFunctionInfo>(shared);
}
DCHECK_NE(fun->function_literal_id(), shared->function_literal_id());
}
return MaybeHandle<SharedFunctionInfo>();
}
@ -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);
}

View File

@ -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

View File

@ -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<SharedFunctionInfo> 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());

View File

@ -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_;

View File

@ -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<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
template <typename Impl>
typename ParserBase<Impl>::ClassLiteralPropertyT
ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
bool has_extends,
bool* is_computed_name,
bool* has_seen_constructor,
bool* ok) {
ParserBase<Impl>::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<Impl>::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<Impl>::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<Impl>::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<Impl>::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<Impl>::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<Impl>::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<Impl>::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<Impl>::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<Impl>::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<Impl>::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<Impl>::ExpressionT ParserBase<Impl>::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();
}

View File

@ -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(

View File

@ -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<Parser>) {
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,

View File

@ -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;

View File

@ -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() {

View File

@ -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();

View File

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

View File

@ -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<PreParser> {
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();
}

View File

@ -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<Object>(source_shared->script(), isolate));

View File

@ -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',

View File

@ -84,6 +84,7 @@ Handle<SharedFunctionInfo> 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);
}