Refactor ParseFunctionLiteral.
It was a pretty monstrous 500 line function. R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/237243003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20752 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a50aca97a2
commit
a43a63b110
278
src/parser.cc
278
src/parser.cc
@ -3258,9 +3258,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
|
FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
|
||||||
? FunctionLiteral::kIsParenthesized
|
? FunctionLiteral::kIsParenthesized
|
||||||
: FunctionLiteral::kNotParenthesized;
|
: FunctionLiteral::kNotParenthesized;
|
||||||
FunctionLiteral::IsGeneratorFlag generator = is_generator
|
|
||||||
? FunctionLiteral::kIsGenerator
|
|
||||||
: FunctionLiteral::kNotGenerator;
|
|
||||||
DeferredFeedbackSlotProcessor* slot_processor;
|
DeferredFeedbackSlotProcessor* slot_processor;
|
||||||
AstProperties ast_properties;
|
AstProperties ast_properties;
|
||||||
BailoutReason dont_optimize_reason = kNoReason;
|
BailoutReason dont_optimize_reason = kNoReason;
|
||||||
@ -3389,132 +3386,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
parenthesized_function_ = false; // The bit was set for this function only.
|
parenthesized_function_ = false; // The bit was set for this function only.
|
||||||
|
|
||||||
if (is_lazily_parsed) {
|
if (is_lazily_parsed) {
|
||||||
int function_block_pos = position();
|
SkipLazyFunctionBody(function_name, &materialized_literal_count,
|
||||||
FunctionEntry entry;
|
&expected_property_count, CHECK_OK);
|
||||||
if (cached_data_mode_ == CONSUME_CACHED_DATA) {
|
} else {
|
||||||
// If we have cached data, we use it to skip parsing the function body.
|
body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
|
||||||
// The data contains the information we need to construct the lazy
|
is_generator, CHECK_OK);
|
||||||
// function.
|
|
||||||
entry = (*cached_data())->GetFunctionEntry(function_block_pos);
|
|
||||||
if (entry.is_valid()) {
|
|
||||||
if (entry.end_pos() <= function_block_pos) {
|
|
||||||
// End position greater than end of stream is safe, and hard
|
|
||||||
// to check.
|
|
||||||
ReportInvalidCachedData(function_name, CHECK_OK);
|
|
||||||
}
|
|
||||||
scanner()->SeekForward(entry.end_pos() - 1);
|
|
||||||
|
|
||||||
scope->set_end_position(entry.end_pos());
|
|
||||||
Expect(Token::RBRACE, CHECK_OK);
|
|
||||||
isolate()->counters()->total_preparse_skipped()->Increment(
|
|
||||||
scope->end_position() - function_block_pos);
|
|
||||||
materialized_literal_count = entry.literal_count();
|
|
||||||
expected_property_count = entry.property_count();
|
|
||||||
scope_->SetStrictMode(entry.strict_mode());
|
|
||||||
} else {
|
|
||||||
// This case happens when we have preparse data but it doesn't contain
|
|
||||||
// an entry for the function. Fail the compilation.
|
|
||||||
ReportInvalidCachedData(function_name, CHECK_OK);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// With no cached data, we partially parse the function, without
|
|
||||||
// building an AST. This gathers the data needed to build a lazy
|
|
||||||
// function.
|
|
||||||
SingletonLogger logger;
|
|
||||||
PreParser::PreParseResult result = LazyParseFunctionLiteral(&logger);
|
|
||||||
if (result == PreParser::kPreParseStackOverflow) {
|
|
||||||
// Propagate stack overflow.
|
|
||||||
set_stack_overflow();
|
|
||||||
*ok = false;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (logger.has_error()) {
|
|
||||||
const char* arg = logger.argument_opt();
|
|
||||||
Vector<const char*> args;
|
|
||||||
if (arg != NULL) {
|
|
||||||
args = Vector<const char*>(&arg, 1);
|
|
||||||
}
|
|
||||||
ParserTraits::ReportMessageAt(
|
|
||||||
Scanner::Location(logger.start(), logger.end()),
|
|
||||||
logger.message(), args, logger.is_reference_error());
|
|
||||||
*ok = false;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
scope->set_end_position(logger.end());
|
|
||||||
Expect(Token::RBRACE, CHECK_OK);
|
|
||||||
isolate()->counters()->total_preparse_skipped()->Increment(
|
|
||||||
scope->end_position() - function_block_pos);
|
|
||||||
materialized_literal_count = logger.literals();
|
|
||||||
expected_property_count = logger.properties();
|
|
||||||
scope_->SetStrictMode(logger.strict_mode());
|
|
||||||
if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
|
|
||||||
ASSERT(log_);
|
|
||||||
// Position right after terminal '}'.
|
|
||||||
int body_end = scanner()->location().end_pos;
|
|
||||||
log_->LogFunction(function_block_pos, body_end,
|
|
||||||
materialized_literal_count,
|
|
||||||
expected_property_count,
|
|
||||||
scope_->strict_mode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_lazily_parsed) {
|
|
||||||
// Everything inside an eagerly parsed function will be parsed eagerly
|
|
||||||
// (see comment above).
|
|
||||||
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
|
|
||||||
body = new(zone()) ZoneList<Statement*>(8, zone());
|
|
||||||
if (fvar != NULL) {
|
|
||||||
VariableProxy* fproxy = scope_->NewUnresolved(
|
|
||||||
factory(), function_name, Interface::NewConst());
|
|
||||||
fproxy->BindTo(fvar);
|
|
||||||
body->Add(factory()->NewExpressionStatement(
|
|
||||||
factory()->NewAssignment(fvar_init_op,
|
|
||||||
fproxy,
|
|
||||||
factory()->NewThisFunction(pos),
|
|
||||||
RelocInfo::kNoPosition),
|
|
||||||
RelocInfo::kNoPosition), zone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// For generators, allocate and yield an iterator on function entry.
|
|
||||||
if (is_generator) {
|
|
||||||
ZoneList<Expression*>* arguments =
|
|
||||||
new(zone()) ZoneList<Expression*>(0, zone());
|
|
||||||
CallRuntime* allocation = factory()->NewCallRuntime(
|
|
||||||
isolate()->factory()->empty_string(),
|
|
||||||
Runtime::FunctionForId(Runtime::kHiddenCreateJSGeneratorObject),
|
|
||||||
arguments, pos);
|
|
||||||
VariableProxy* init_proxy = factory()->NewVariableProxy(
|
|
||||||
function_state_->generator_object_variable());
|
|
||||||
Assignment* assignment = factory()->NewAssignment(
|
|
||||||
Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition);
|
|
||||||
VariableProxy* get_proxy = factory()->NewVariableProxy(
|
|
||||||
function_state_->generator_object_variable());
|
|
||||||
Yield* yield = factory()->NewYield(
|
|
||||||
get_proxy, assignment, Yield::INITIAL, RelocInfo::kNoPosition);
|
|
||||||
body->Add(factory()->NewExpressionStatement(
|
|
||||||
yield, RelocInfo::kNoPosition), zone());
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK);
|
|
||||||
|
|
||||||
if (is_generator) {
|
|
||||||
VariableProxy* get_proxy = factory()->NewVariableProxy(
|
|
||||||
function_state_->generator_object_variable());
|
|
||||||
Expression *undefined = factory()->NewLiteral(
|
|
||||||
isolate()->factory()->undefined_value(), RelocInfo::kNoPosition);
|
|
||||||
Yield* yield = factory()->NewYield(
|
|
||||||
get_proxy, undefined, Yield::FINAL, RelocInfo::kNoPosition);
|
|
||||||
body->Add(factory()->NewExpressionStatement(
|
|
||||||
yield, RelocInfo::kNoPosition), zone());
|
|
||||||
}
|
|
||||||
|
|
||||||
materialized_literal_count = function_state.materialized_literal_count();
|
materialized_literal_count = function_state.materialized_literal_count();
|
||||||
expected_property_count = function_state.expected_property_count();
|
expected_property_count = function_state.expected_property_count();
|
||||||
handler_count = function_state.handler_count();
|
handler_count = function_state.handler_count();
|
||||||
|
|
||||||
Expect(Token::RBRACE, CHECK_OK);
|
|
||||||
scope->set_end_position(scanner()->location().end_pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate strict mode. We can do this only after parsing the function,
|
// Validate strict mode. We can do this only after parsing the function,
|
||||||
@ -3558,6 +3437,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
CheckConflictingVarDeclarations(scope, CHECK_OK);
|
CheckConflictingVarDeclarations(scope, CHECK_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FunctionLiteral::IsGeneratorFlag generator = is_generator
|
||||||
|
? FunctionLiteral::kIsGenerator
|
||||||
|
: FunctionLiteral::kNotGenerator;
|
||||||
FunctionLiteral* function_literal =
|
FunctionLiteral* function_literal =
|
||||||
factory()->NewFunctionLiteral(function_name,
|
factory()->NewFunctionLiteral(function_name,
|
||||||
scope,
|
scope,
|
||||||
@ -3582,7 +3464,149 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
|
void Parser::SkipLazyFunctionBody(Handle<String> function_name,
|
||||||
|
int* materialized_literal_count,
|
||||||
|
int* expected_property_count,
|
||||||
|
bool* ok) {
|
||||||
|
int function_block_pos = position();
|
||||||
|
if (cached_data_mode_ == CONSUME_CACHED_DATA) {
|
||||||
|
// If we have cached data, we use it to skip parsing the function body. The
|
||||||
|
// data contains the information we need to construct the lazy function.
|
||||||
|
FunctionEntry entry =
|
||||||
|
(*cached_data())->GetFunctionEntry(function_block_pos);
|
||||||
|
if (entry.is_valid()) {
|
||||||
|
if (entry.end_pos() <= function_block_pos) {
|
||||||
|
// End position greater than end of stream is safe, and hard to check.
|
||||||
|
ReportInvalidCachedData(function_name, ok);
|
||||||
|
if (!*ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scanner()->SeekForward(entry.end_pos() - 1);
|
||||||
|
|
||||||
|
scope_->set_end_position(entry.end_pos());
|
||||||
|
Expect(Token::RBRACE, ok);
|
||||||
|
if (!*ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isolate()->counters()->total_preparse_skipped()->Increment(
|
||||||
|
scope_->end_position() - function_block_pos);
|
||||||
|
*materialized_literal_count = entry.literal_count();
|
||||||
|
*expected_property_count = entry.property_count();
|
||||||
|
scope_->SetStrictMode(entry.strict_mode());
|
||||||
|
} else {
|
||||||
|
// This case happens when we have preparse data but it doesn't contain an
|
||||||
|
// entry for the function. Fail the compilation.
|
||||||
|
ReportInvalidCachedData(function_name, ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// With no cached data, we partially parse the function, without building an
|
||||||
|
// AST. This gathers the data needed to build a lazy function.
|
||||||
|
SingletonLogger logger;
|
||||||
|
PreParser::PreParseResult result =
|
||||||
|
ParseLazyFunctionBodyWithPreParser(&logger);
|
||||||
|
if (result == PreParser::kPreParseStackOverflow) {
|
||||||
|
// Propagate stack overflow.
|
||||||
|
set_stack_overflow();
|
||||||
|
*ok = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (logger.has_error()) {
|
||||||
|
const char* arg = logger.argument_opt();
|
||||||
|
Vector<const char*> args;
|
||||||
|
if (arg != NULL) {
|
||||||
|
args = Vector<const char*>(&arg, 1);
|
||||||
|
}
|
||||||
|
ParserTraits::ReportMessageAt(
|
||||||
|
Scanner::Location(logger.start(), logger.end()),
|
||||||
|
logger.message(), args, logger.is_reference_error());
|
||||||
|
*ok = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scope_->set_end_position(logger.end());
|
||||||
|
Expect(Token::RBRACE, ok);
|
||||||
|
if (!*ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isolate()->counters()->total_preparse_skipped()->Increment(
|
||||||
|
scope_->end_position() - function_block_pos);
|
||||||
|
*materialized_literal_count = logger.literals();
|
||||||
|
*expected_property_count = logger.properties();
|
||||||
|
scope_->SetStrictMode(logger.strict_mode());
|
||||||
|
if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
|
||||||
|
ASSERT(log_);
|
||||||
|
// Position right after terminal '}'.
|
||||||
|
int body_end = scanner()->location().end_pos;
|
||||||
|
log_->LogFunction(function_block_pos, body_end,
|
||||||
|
*materialized_literal_count,
|
||||||
|
*expected_property_count,
|
||||||
|
scope_->strict_mode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
||||||
|
Handle<String> function_name, int pos, Variable* fvar,
|
||||||
|
Token::Value fvar_init_op, bool is_generator, bool* ok) {
|
||||||
|
// Everything inside an eagerly parsed function will be parsed eagerly
|
||||||
|
// (see comment above).
|
||||||
|
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
|
||||||
|
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8, zone());
|
||||||
|
if (fvar != NULL) {
|
||||||
|
VariableProxy* fproxy = scope_->NewUnresolved(
|
||||||
|
factory(), function_name, Interface::NewConst());
|
||||||
|
fproxy->BindTo(fvar);
|
||||||
|
body->Add(factory()->NewExpressionStatement(
|
||||||
|
factory()->NewAssignment(fvar_init_op,
|
||||||
|
fproxy,
|
||||||
|
factory()->NewThisFunction(pos),
|
||||||
|
RelocInfo::kNoPosition),
|
||||||
|
RelocInfo::kNoPosition), zone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// For generators, allocate and yield an iterator on function entry.
|
||||||
|
if (is_generator) {
|
||||||
|
ZoneList<Expression*>* arguments =
|
||||||
|
new(zone()) ZoneList<Expression*>(0, zone());
|
||||||
|
CallRuntime* allocation = factory()->NewCallRuntime(
|
||||||
|
isolate()->factory()->empty_string(),
|
||||||
|
Runtime::FunctionForId(Runtime::kHiddenCreateJSGeneratorObject),
|
||||||
|
arguments, pos);
|
||||||
|
VariableProxy* init_proxy = factory()->NewVariableProxy(
|
||||||
|
function_state_->generator_object_variable());
|
||||||
|
Assignment* assignment = factory()->NewAssignment(
|
||||||
|
Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition);
|
||||||
|
VariableProxy* get_proxy = factory()->NewVariableProxy(
|
||||||
|
function_state_->generator_object_variable());
|
||||||
|
Yield* yield = factory()->NewYield(
|
||||||
|
get_proxy, assignment, Yield::INITIAL, RelocInfo::kNoPosition);
|
||||||
|
body->Add(factory()->NewExpressionStatement(
|
||||||
|
yield, RelocInfo::kNoPosition), zone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK);
|
||||||
|
|
||||||
|
if (is_generator) {
|
||||||
|
VariableProxy* get_proxy = factory()->NewVariableProxy(
|
||||||
|
function_state_->generator_object_variable());
|
||||||
|
Expression *undefined = factory()->NewLiteral(
|
||||||
|
isolate()->factory()->undefined_value(), RelocInfo::kNoPosition);
|
||||||
|
Yield* yield = factory()->NewYield(
|
||||||
|
get_proxy, undefined, Yield::FINAL, RelocInfo::kNoPosition);
|
||||||
|
body->Add(factory()->NewExpressionStatement(
|
||||||
|
yield, RelocInfo::kNoPosition), zone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Expect(Token::RBRACE, CHECK_OK);
|
||||||
|
scope_->set_end_position(scanner()->location().end_pos);
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
|
||||||
SingletonLogger* logger) {
|
SingletonLogger* logger) {
|
||||||
HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse());
|
HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse());
|
||||||
ASSERT_EQ(Token::LBRACE, scanner()->current_token());
|
ASSERT_EQ(Token::LBRACE, scanner()->current_token());
|
||||||
|
19
src/parser.h
19
src/parser.h
@ -790,8 +790,23 @@ class Parser : public ParserBase<ParserTraits> {
|
|||||||
|
|
||||||
Handle<String> LookupCachedSymbol(int symbol_id);
|
Handle<String> LookupCachedSymbol(int symbol_id);
|
||||||
|
|
||||||
PreParser::PreParseResult LazyParseFunctionLiteral(
|
// Skip over a lazy function, either using cached data if we have it, or
|
||||||
SingletonLogger* logger);
|
// by parsing the function with PreParser. Consumes the ending }.
|
||||||
|
void SkipLazyFunctionBody(Handle<String> function_name,
|
||||||
|
int* materialized_literal_count,
|
||||||
|
int* expected_property_count,
|
||||||
|
bool* ok);
|
||||||
|
|
||||||
|
PreParser::PreParseResult ParseLazyFunctionBodyWithPreParser(
|
||||||
|
SingletonLogger* logger);
|
||||||
|
|
||||||
|
// Consumes the ending }.
|
||||||
|
ZoneList<Statement*>* ParseEagerFunctionBody(Handle<String> function_name,
|
||||||
|
int pos,
|
||||||
|
Variable* fvar,
|
||||||
|
Token::Value fvar_init_op,
|
||||||
|
bool is_generator,
|
||||||
|
bool* ok);
|
||||||
|
|
||||||
Isolate* isolate_;
|
Isolate* isolate_;
|
||||||
ZoneList<Handle<String> > symbol_cache_;
|
ZoneList<Handle<String> > symbol_cache_;
|
||||||
|
Loading…
Reference in New Issue
Block a user