Commit 4ff2cafe authored by verwaest's avatar verwaest Committed by Commit bot

Preparse lazy function parameters

Parameters of a lazily parsed function used to be parsed eagerly, and parameter
handling was split between Parser::ParseFunctionLiteral and
ParseEagerFunctionBody, leading to inconsistencies.

After this CL, we preparse (lazy parse) the parameters of lazily parsed
functions.

(For arrow functions, we cannot do that ofc.)

This is needed for later features (PreParser with scope analysis).

-- CL adapted from marja's https://codereview.chromium.org/2411793003/

BUG=

Review-Url: https://codereview.chromium.org/2472063002
Cr-Commit-Position: refs/heads/master@{#40771}
parent dfcd5456
...@@ -1261,6 +1261,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, ...@@ -1261,6 +1261,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
DCHECK(is_function_scope()); DCHECK(is_function_scope());
// Reset all non-trivial members. // Reset all non-trivial members.
params_.Clear();
decls_.Clear(); decls_.Clear();
locals_.Clear(); locals_.Clear();
sloppy_block_function_map_.Clear(); sloppy_block_function_map_.Clear();
...@@ -1269,28 +1270,8 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, ...@@ -1269,28 +1270,8 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
inner_scope_ = nullptr; inner_scope_ = nullptr;
unresolved_ = nullptr; unresolved_ = nullptr;
// TODO(verwaest): We should properly preparse the parameters (no declarations if (aborted && !IsArrowFunction(function_kind_)) {
// should be created), and reparse on abort. DeclareDefaultFunctionVariables(ast_value_factory);
if (aborted) {
if (!IsArrowFunction(function_kind_)) {
DeclareDefaultFunctionVariables(ast_value_factory);
}
// Recreate declarations for parameters.
for (int i = 0; i < params_.length(); i++) {
Variable* var = params_[i];
if (var->mode() == TEMPORARY) {
// TODO(verwaest): Remove and unfriend DeclarationScope from Variable.
*var->next() = nullptr;
locals_.Add(var);
} else if (variables_.Lookup(var->raw_name()) == nullptr) {
// TODO(verwaest): Remove and unfriend DeclarationScope from Variable.
*var->next() = nullptr;
variables_.Add(zone(), var);
locals_.Add(var);
}
}
} else {
params_.Rewind(0);
} }
#ifdef DEBUG #ifdef DEBUG
......
...@@ -152,9 +152,6 @@ class Variable final : public ZoneObject { ...@@ -152,9 +152,6 @@ class Variable final : public ZoneObject {
2> {}; 2> {};
Variable** next() { return &next_; } Variable** next() { return &next_; }
friend List; friend List;
// To reset next to nullptr upon resetting after preparsing.
// TODO(verwaest): Remove once we properly preparse parameters.
friend class DeclarationScope;
}; };
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -3953,12 +3953,22 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( ...@@ -3953,12 +3953,22 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
if (peek() == Token::LBRACE) { if (peek() == Token::LBRACE) {
// Multiple statement body // Multiple statement body
Consume(Token::LBRACE);
DCHECK_EQ(scope(), formal_parameters.scope); DCHECK_EQ(scope(), formal_parameters.scope);
if (is_lazy_top_level_function) { if (is_lazy_top_level_function) {
// FIXME(marja): Arrow function parameters will be parsed even if the
// body is preparsed; move relevant parts of parameter handling to
// simulate consistent parameter handling.
Scanner::BookmarkScope bookmark(scanner()); Scanner::BookmarkScope bookmark(scanner());
bookmark.Set(); bookmark.Set();
LazyParsingResult result = impl()->SkipLazyFunctionBody( // For arrow functions, we don't need to retrieve data about function
// parameters.
int dummy_num_parameters = -1;
int dummy_function_length = -1;
bool dummy_has_duplicate_parameters = false;
DCHECK((kind & FunctionKind::kArrowFunction) != 0);
LazyParsingResult result = impl()->SkipFunction(
kind, formal_parameters.scope, &dummy_num_parameters,
&dummy_function_length, &dummy_has_duplicate_parameters,
&materialized_literal_count, &expected_property_count, false, true, &materialized_literal_count, &expected_property_count, false, true,
CHECK_OK); CHECK_OK);
formal_parameters.scope->ResetAfterPreparsing( formal_parameters.scope->ResetAfterPreparsing(
...@@ -3982,6 +3992,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( ...@@ -3982,6 +3992,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
} }
} }
if (!is_lazy_top_level_function) { if (!is_lazy_top_level_function) {
Consume(Token::LBRACE);
body = impl()->ParseEagerFunctionBody( body = impl()->ParseEagerFunctionBody(
impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters, impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters,
kind, FunctionLiteral::kAnonymousExpression, CHECK_OK); kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
......
This diff is collapsed.
...@@ -31,11 +31,11 @@ class FunctionEntry BASE_EMBEDDED { ...@@ -31,11 +31,11 @@ class FunctionEntry BASE_EMBEDDED {
enum { enum {
kStartPositionIndex, kStartPositionIndex,
kEndPositionIndex, kEndPositionIndex,
kNumParametersIndex,
kFunctionLengthIndex,
kLiteralCountIndex, kLiteralCountIndex,
kPropertyCountIndex, kPropertyCountIndex,
kLanguageModeIndex, kFlagsIndex,
kUsesSuperPropertyIndex,
kCallsEvalIndex,
kSize kSize
}; };
...@@ -44,18 +44,43 @@ class FunctionEntry BASE_EMBEDDED { ...@@ -44,18 +44,43 @@ class FunctionEntry BASE_EMBEDDED {
FunctionEntry() : backing_() { } FunctionEntry() : backing_() { }
int start_pos() { return backing_[kStartPositionIndex]; } class LanguageModeField : public BitField<LanguageMode, 0, 1> {};
int end_pos() { return backing_[kEndPositionIndex]; } class UsesSuperPropertyField
int literal_count() { return backing_[kLiteralCountIndex]; } : public BitField<bool, LanguageModeField::kNext, 1> {};
int property_count() { return backing_[kPropertyCountIndex]; } class CallsEvalField
LanguageMode language_mode() { : public BitField<bool, UsesSuperPropertyField::kNext, 1> {};
DCHECK(is_valid_language_mode(backing_[kLanguageModeIndex])); class HasDuplicateParametersField
return static_cast<LanguageMode>(backing_[kLanguageModeIndex]); : public BitField<bool, CallsEvalField::kNext, 1> {};
static uint32_t EncodeFlags(LanguageMode language_mode,
bool uses_super_property, bool calls_eval,
bool has_duplicate_parameters) {
return LanguageModeField::encode(language_mode) |
UsesSuperPropertyField::encode(uses_super_property) |
CallsEvalField::encode(calls_eval) |
HasDuplicateParametersField::encode(has_duplicate_parameters);
}
int start_pos() const { return backing_[kStartPositionIndex]; }
int end_pos() const { return backing_[kEndPositionIndex]; }
int num_parameters() const { return backing_[kNumParametersIndex]; }
int function_length() const { return backing_[kFunctionLengthIndex]; }
int literal_count() const { return backing_[kLiteralCountIndex]; }
int property_count() const { return backing_[kPropertyCountIndex]; }
LanguageMode language_mode() const {
return LanguageModeField::decode(backing_[kFlagsIndex]);
}
bool uses_super_property() const {
return UsesSuperPropertyField::decode(backing_[kFlagsIndex]);
}
bool calls_eval() const {
return CallsEvalField::decode(backing_[kFlagsIndex]);
}
bool has_duplicate_parameters() const {
return HasDuplicateParametersField::decode(backing_[kFlagsIndex]);
} }
bool uses_super_property() { return backing_[kUsesSuperPropertyIndex]; }
bool calls_eval() { return backing_[kCallsEvalIndex]; }
bool is_valid() { return !backing_.is_empty(); } bool is_valid() const { return !backing_.is_empty(); }
private: private:
Vector<unsigned> backing_; Vector<unsigned> backing_;
...@@ -490,13 +515,17 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -490,13 +515,17 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// by parsing the function with PreParser. Consumes the ending }. // by parsing the function with PreParser. Consumes the ending }.
// If may_abort == true, the (pre-)parser may decide to abort skipping // If may_abort == true, the (pre-)parser may decide to abort skipping
// in order to force the function to be eagerly parsed, after all. // in order to force the function to be eagerly parsed, after all.
LazyParsingResult SkipLazyFunctionBody(int* materialized_literal_count, LazyParsingResult SkipFunction(
int* expected_property_count, FunctionKind kind, DeclarationScope* function_scope, int* num_parameters,
bool is_inner_function, bool may_abort, int* function_length, bool* has_duplicate_parameters,
bool* ok); int* materialized_literal_count, int* expected_property_count,
bool is_inner_function, bool may_abort, bool* ok);
PreParser::PreParseResult ParseFunctionBodyWithPreParser(
SingletonLogger* logger, bool is_inner_function, bool may_abort); PreParser::PreParseResult ParseFunctionWithPreParser(FunctionKind kind,
DeclarationScope* scope,
SingletonLogger* logger,
bool is_inner_function,
bool may_abort);
Block* BuildParameterInitializationBlock( Block* BuildParameterInitializationBlock(
const ParserFormalParameters& parameters, bool* ok); const ParserFormalParameters& parameters, bool* ok);
...@@ -508,6 +537,13 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -508,6 +537,13 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
const ParserFormalParameters& parameters, FunctionKind kind, const ParserFormalParameters& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok); FunctionLiteral::FunctionType function_type, bool* ok);
ZoneList<Statement*>* ParseFunction(
const AstRawString* function_name, int pos, FunctionKind kind,
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters,
int* function_length, bool* has_duplicate_parameters,
int* materialized_literal_count, int* expected_property_count, bool* ok);
void ThrowPendingError(Isolate* isolate, Handle<Script> script); void ThrowPendingError(Isolate* isolate, Handle<Script> script);
class TemplateLiteral : public ZoneObject { class TemplateLiteral : public ZoneObject {
......
...@@ -14,7 +14,7 @@ struct PreparseDataConstants { ...@@ -14,7 +14,7 @@ struct PreparseDataConstants {
public: public:
// Layout and constants of the preparse data exchange format. // Layout and constants of the preparse data exchange format.
static const unsigned kMagicNumber = 0xBadDead; static const unsigned kMagicNumber = 0xBadDead;
static const unsigned kCurrentVersion = 11; static const unsigned kCurrentVersion = 12;
static const int kMagicOffset = 0; static const int kMagicOffset = 0;
static const int kVersionOffset = 1; static const int kVersionOffset = 1;
......
...@@ -12,6 +12,20 @@ ...@@ -12,6 +12,20 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
void CompleteParserRecorder::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) {
function_store_.Add(start);
function_store_.Add(end);
function_store_.Add(num_parameters);
function_store_.Add(function_length);
function_store_.Add(literals);
function_store_.Add(properties);
function_store_.Add(
FunctionEntry::EncodeFlags(language_mode, uses_super_property, calls_eval,
has_duplicate_parameters));
}
CompleteParserRecorder::CompleteParserRecorder() { CompleteParserRecorder::CompleteParserRecorder() {
preamble_[PreparseDataConstants::kMagicOffset] = preamble_[PreparseDataConstants::kMagicOffset] =
......
...@@ -53,7 +53,9 @@ class ParserRecorder { ...@@ -53,7 +53,9 @@ class ParserRecorder {
virtual ~ParserRecorder() { } virtual ~ParserRecorder() { }
// Logs the scope and some details of a function literal in the source. // Logs the scope and some details of a function literal in the source.
virtual void LogFunction(int start, int end, int literals, int properties, virtual 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, LanguageMode language_mode, bool uses_super_property,
bool calls_eval) = 0; bool calls_eval) = 0;
...@@ -72,12 +74,20 @@ class ParserRecorder { ...@@ -72,12 +74,20 @@ class ParserRecorder {
class SingletonLogger : public ParserRecorder { class SingletonLogger : public ParserRecorder {
public: public:
SingletonLogger() SingletonLogger()
: has_error_(false), start_(-1), end_(-1), error_type_(kSyntaxError) {} : has_error_(false),
start_(-1),
end_(-1),
num_parameters_(-1),
function_length_(-1),
has_duplicate_parameters_(false),
error_type_(kSyntaxError) {}
virtual ~SingletonLogger() {} virtual ~SingletonLogger() {}
void Reset() { has_error_ = false; } void Reset() { has_error_ = false; }
virtual void LogFunction(int start, int end, int literals, int properties, virtual 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, LanguageMode language_mode, bool uses_super_property,
bool calls_eval) { bool calls_eval) {
DCHECK(!has_error_); DCHECK(!has_error_);
...@@ -85,6 +95,9 @@ class SingletonLogger : public ParserRecorder { ...@@ -85,6 +95,9 @@ class SingletonLogger : public ParserRecorder {
DCHECK(start_ == -1 && end_ == -1); DCHECK(start_ == -1 && end_ == -1);
start_ = start; start_ = start;
end_ = end; end_ = end;
num_parameters_ = num_parameters;
function_length_ = function_length;
has_duplicate_parameters_ = has_duplicate_parameters;
literals_ = literals; literals_ = literals;
properties_ = properties; properties_ = properties;
language_mode_ = language_mode; language_mode_ = language_mode;
...@@ -110,6 +123,18 @@ class SingletonLogger : public ParserRecorder { ...@@ -110,6 +123,18 @@ class SingletonLogger : public ParserRecorder {
int start() const { return start_; } int start() const { return start_; }
int end() const { return end_; } int end() const { return end_; }
int num_parameters() const {
DCHECK(!has_error_);
return num_parameters_;
}
int function_length() const {
DCHECK(!has_error_);
return function_length_;
}
bool has_duplicate_parameters() const {
DCHECK(!has_error_);
return has_duplicate_parameters_;
}
int literals() const { int literals() const {
DCHECK(!has_error_); DCHECK(!has_error_);
return literals_; return literals_;
...@@ -148,6 +173,9 @@ class SingletonLogger : public ParserRecorder { ...@@ -148,6 +173,9 @@ class SingletonLogger : public ParserRecorder {
int start_; int start_;
int end_; int end_;
// For function entries. // For function entries.
int num_parameters_;
int function_length_;
bool has_duplicate_parameters_;
int literals_; int literals_;
int properties_; int properties_;
LanguageMode language_mode_; LanguageMode language_mode_;
...@@ -170,17 +198,11 @@ class CompleteParserRecorder : public ParserRecorder { ...@@ -170,17 +198,11 @@ class CompleteParserRecorder : public ParserRecorder {
CompleteParserRecorder(); CompleteParserRecorder();
virtual ~CompleteParserRecorder() {} virtual ~CompleteParserRecorder() {}
virtual void LogFunction(int start, int end, int literals, int properties, virtual 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, LanguageMode language_mode, bool uses_super_property,
bool calls_eval) { bool calls_eval);
function_store_.Add(start);
function_store_.Add(end);
function_store_.Add(literals);
function_store_.Add(properties);
function_store_.Add(language_mode);
function_store_.Add(uses_super_property);
function_store_.Add(calls_eval);
}
// Logs an error message and marks the log as containing an error. // Logs an error message and marks the log as containing an error.
// Further logging will be ignored, and ExtractData will return a vector // Further logging will be ignored, and ExtractData will return a vector
......
...@@ -84,8 +84,9 @@ PreParserIdentifier PreParser::GetSymbol() const { ...@@ -84,8 +84,9 @@ PreParserIdentifier PreParser::GetSymbol() const {
} }
PreParser::PreParseResult PreParser::PreParseFunction( PreParser::PreParseResult PreParser::PreParseFunction(
DeclarationScope* function_scope, bool parsing_module, SingletonLogger* log, FunctionKind kind, DeclarationScope* function_scope, bool parsing_module,
bool is_inner_function, bool may_abort, int* use_counts) { SingletonLogger* log, bool is_inner_function, bool may_abort,
int* use_counts) {
DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type()); DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
parsing_module_ = parsing_module; parsing_module_ = parsing_module;
log_ = log; log_ = log;
...@@ -98,24 +99,63 @@ PreParser::PreParseResult PreParser::PreParseFunction( ...@@ -98,24 +99,63 @@ PreParser::PreParseResult PreParser::PreParseFunction(
// PreParser. // PreParser.
DCHECK_NULL(scope_state_); DCHECK_NULL(scope_state_);
FunctionState function_state(&function_state_, &scope_state_, function_scope); FunctionState function_state(&function_state_, &scope_state_, function_scope);
DCHECK_EQ(Token::LBRACE, scanner()->current_token()); // This indirection is needed so that we can use the CHECK_OK macros.
bool ok = true; bool ok_holder = true;
int start_position = peek_position(); bool* ok = &ok_holder;
LazyParsingResult result = ParseStatementListAndLogFunction(may_abort, &ok);
PreParserFormalParameters formals(function_scope);
bool has_duplicate_parameters = false;
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
std::unique_ptr<ExpressionClassifier> formals_classifier;
// Parse non-arrow function parameters. For arrow functions, the parameters
// have already been parsed.
if (!IsArrowFunction(kind)) {
formals_classifier.reset(new ExpressionClassifier(this, &duplicate_finder));
// We return kPreParseSuccess in failure cases too - errors are retrieved
// separately by Parser::SkipLazyFunctionBody.
ParseFormalParameterList(&formals, CHECK_OK_VALUE(kPreParseSuccess));
Expect(Token::RPAREN, CHECK_OK_VALUE(kPreParseSuccess));
int formals_end_position = scanner()->location().end_pos;
CheckArityRestrictions(
formals.arity, kind, formals.has_rest, function_scope->start_position(),
formals_end_position, CHECK_OK_VALUE(kPreParseSuccess));
has_duplicate_parameters =
!classifier()->is_valid_formal_parameter_list_without_duplicates();
}
Expect(Token::LBRACE, CHECK_OK_VALUE(kPreParseSuccess));
LazyParsingResult result = ParseStatementListAndLogFunction(
function_scope->start_position(), &formals, has_duplicate_parameters,
may_abort, ok);
use_counts_ = nullptr; use_counts_ = nullptr;
track_unresolved_variables_ = false; track_unresolved_variables_ = false;
if (result == kLazyParsingAborted) { if (result == kLazyParsingAborted) {
return kPreParseAbort; return kPreParseAbort;
} else if (stack_overflow()) { } else if (stack_overflow()) {
return kPreParseStackOverflow; return kPreParseStackOverflow;
} else if (!ok) { } else if (!*ok) {
DCHECK(log->has_error()); DCHECK(log->has_error());
} else { } else {
DCHECK_EQ(Token::RBRACE, scanner()->peek()); DCHECK_EQ(Token::RBRACE, scanner()->peek());
if (!IsArrowFunction(kind)) {
// Validate parameter names. We can do this only after parsing the
// function, since the function can declare itself strict.
const bool allow_duplicate_parameters =
is_sloppy(function_scope->language_mode()) && formals.is_simple &&
!IsConciseMethod(kind);
ValidateFormalParameters(function_scope->language_mode(),
allow_duplicate_parameters,
CHECK_OK_VALUE(kPreParseSuccess));
}
if (is_strict(function_scope->language_mode())) { if (is_strict(function_scope->language_mode())) {
int end_pos = scanner()->location().end_pos; int end_pos = scanner()->location().end_pos;
CheckStrictOctalLiteral(start_position, end_pos, &ok); CheckStrictOctalLiteral(function_scope->start_position(), end_pos, ok);
CheckDecimalLiteralWithLeadingZero(start_position, end_pos); CheckDecimalLiteralWithLeadingZero(function_scope->start_position(),
end_pos);
} }
} }
return kPreParseSuccess; return kPreParseSuccess;
...@@ -195,8 +235,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral( ...@@ -195,8 +235,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
} }
PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction( PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
bool may_abort, bool* ok) { int start_position, PreParserFormalParameters* formals,
int body_start = position(); bool has_duplicate_parameters, bool may_abort, bool* ok) {
PreParserStatementList body; PreParserStatementList body;
LazyParsingResult result = ParseStatementList( LazyParsingResult result = ParseStatementList(
body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete)); body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
...@@ -207,7 +247,8 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction( ...@@ -207,7 +247,8 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
int body_end = scanner()->peek_location().end_pos; int body_end = scanner()->peek_location().end_pos;
DeclarationScope* scope = this->scope()->AsDeclarationScope(); DeclarationScope* scope = this->scope()->AsDeclarationScope();
DCHECK(scope->is_function_scope()); DCHECK(scope->is_function_scope());
log_->LogFunction(body_start, body_end, log_->LogFunction(start_position, body_end, formals->num_parameters(),
formals->function_length, has_duplicate_parameters,
function_state_->materialized_literal_count(), function_state_->materialized_literal_count(),
function_state_->expected_property_count(), language_mode(), function_state_->expected_property_count(), language_mode(),
scope->uses_super_property(), scope->calls_eval()); scope->uses_super_property(), scope->calls_eval());
......
...@@ -887,7 +887,8 @@ class PreParser : public ParserBase<PreParser> { ...@@ -887,7 +887,8 @@ class PreParser : public ParserBase<PreParser> {
// keyword and parameters, and have consumed the initial '{'. // keyword and parameters, and have consumed the initial '{'.
// At return, unless an error occurred, the scanner is positioned before the // At return, unless an error occurred, the scanner is positioned before the
// the final '}'. // the final '}'.
PreParseResult PreParseFunction(DeclarationScope* function_scope, PreParseResult PreParseFunction(FunctionKind kind,
DeclarationScope* function_scope,
bool parsing_module, SingletonLogger* log, bool parsing_module, SingletonLogger* log,
bool track_unresolved_variables, bool track_unresolved_variables,
bool may_abort, int* use_counts); bool may_abort, int* use_counts);
...@@ -910,9 +911,11 @@ class PreParser : public ParserBase<PreParser> { ...@@ -910,9 +911,11 @@ class PreParser : public ParserBase<PreParser> {
bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; } bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; }
V8_INLINE LazyParsingResult SkipLazyFunctionBody( V8_INLINE LazyParsingResult SkipFunction(
FunctionKind kind, DeclarationScope* function_scope, int* num_parameters,
int* function_length, bool* has_duplicate_parameters,
int* materialized_literal_count, int* expected_property_count, int* materialized_literal_count, int* expected_property_count,
bool track_unresolved_variables, bool may_abort, bool* ok) { bool is_inner_function, bool may_abort, bool* ok) {
UNREACHABLE(); UNREACHABLE();
return kLazyParsingComplete; return kLazyParsingComplete;
} }
...@@ -921,7 +924,9 @@ class PreParser : public ParserBase<PreParser> { ...@@ -921,7 +924,9 @@ class PreParser : public ParserBase<PreParser> {
FunctionNameValidity function_name_validity, FunctionKind kind, FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type, int function_token_pos, FunctionLiteral::FunctionType function_type,
LanguageMode language_mode, bool* ok); LanguageMode language_mode, bool* ok);
LazyParsingResult ParseStatementListAndLogFunction(bool may_abort, bool* ok); LazyParsingResult ParseStatementListAndLogFunction(
int position_before_formals, PreParserFormalParameters* formals,
bool has_duplicate_parameters, bool maybe_abort, bool* ok);
struct TemplateLiteralState {}; struct TemplateLiteralState {};
......
...@@ -287,14 +287,30 @@ TEST(PreparseFunctionDataIsUsed) { ...@@ -287,14 +287,30 @@ TEST(PreparseFunctionDataIsUsed) {
i::GetCurrentStackPosition() - 128 * 1024); i::GetCurrentStackPosition() - 128 * 1024);
const char* good_code[] = { const char* good_code[] = {
"function this_is_lazy() { var a; } function foo() { return 25; } foo();", "function z() { var a; } function f() { return 25; } f();",
"var this_is_lazy = () => { var a; }; var foo = () => 25; foo();", "var z = function () { var a; }; function f() { return 25; } f();",
"function *z() { var a; } function f() { return 25; } f();",
"var z = function *() { var a; }; function f() { return 25; } f();",
"function z(p1, p2) { var a; } function f() { return 25; } f();",
"var z = function (p1, p2) { var a; }; function f() { return 25; } f();",
"function *z(p1, p2) { var a; } function f() { return 25; } f();",
"var z = function *(p1, p2) { var a; }; function f() { return 25; } f();",
"var z = () => { var a; }; function f() { return 25; } f();",
"var z = (p1, p2) => { var a; }; function f() { return 25; } f();",
}; };
// Insert a syntax error inside the lazy function. // Insert a syntax error inside the lazy function.
const char* bad_code[] = { const char* bad_code[] = {
"function this_is_lazy() { if ( } function foo() { return 25; } foo();", "function z() { if ( } function f() { return 25; } f();",
"var this_is_lazy = () => { if ( }; var foo = () => 25; foo();", "var z = function () { if ( }; function f() { return 25; } f();",
"function *z() { if ( } function f() { return 25; } f();",
"var z = function *() { if ( }; function f() { return 25; } f();",
"function z(p1, p2) { if ( } function f() { return 25; } f();",
"var z = function (p1, p2) { if ( }; function f() { return 25; } f();",
"function *z(p1, p2) { if ( } function f() { return 25; } f();",
"var z = function *(p1, p2) { if ( }; function f() { return 25; } f();",
"var z = () => { if ( }; function f() { return 25; } f();",
"var z = (p1, p2) => { if ( }; function f() { return 25; } f();",
}; };
for (unsigned i = 0; i < arraysize(good_code); i++) { for (unsigned i = 0; i < arraysize(good_code); i++) {
...@@ -488,17 +504,16 @@ TEST(Regress928) { ...@@ -488,17 +504,16 @@ TEST(Regress928) {
int first_function = int first_function =
static_cast<int>(strstr(program, "function") - program); static_cast<int>(strstr(program, "function") - program);
int first_lbrace = first_function + i::StrLength("function () "); int first_lparen = first_function + i::StrLength("function ");
CHECK_EQ('{', program[first_lbrace]); CHECK_EQ('(', program[first_lparen]);
i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace); i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lparen);
CHECK(!entry1.is_valid()); CHECK(!entry1.is_valid());
int second_function = int second_function =
static_cast<int>(strstr(program + first_lbrace, "function") - program); static_cast<int>(strstr(program + first_lparen, "function") - program);
int second_lbrace = int second_lparen = second_function + i::StrLength("function ");
second_function + i::StrLength("function () "); CHECK_EQ('(', program[second_lparen]);
CHECK_EQ('{', program[second_lbrace]); i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lparen);
i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
CHECK(entry2.is_valid()); CHECK(entry2.is_valid());
CHECK_EQ('}', program[entry2.end_pos() - 1]); CHECK_EQ('}', program[entry2.end_pos() - 1]);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment