Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 18d0ebbe90bb48af93c668c0fa9650b7583ca5b4..9d37c88bf4aad9fbb03830440c58453c77f6402f 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -3258,9 +3258,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ |
? FunctionLiteral::kIsParenthesized |
: FunctionLiteral::kNotParenthesized; |
- FunctionLiteral::IsGeneratorFlag generator = is_generator |
- ? FunctionLiteral::kIsGenerator |
- : FunctionLiteral::kNotGenerator; |
DeferredFeedbackSlotProcessor* slot_processor; |
AstProperties ast_properties; |
BailoutReason dont_optimize_reason = kNoReason; |
@@ -3389,132 +3386,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
parenthesized_function_ = false; // The bit was set for this function only. |
if (is_lazily_parsed) { |
- int function_block_pos = position(); |
- FunctionEntry entry; |
- 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. |
- 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()); |
- } |
- |
+ SkipLazyFunctionBody(function_name, &materialized_literal_count, |
+ &expected_property_count, CHECK_OK); |
+ } else { |
+ body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op, |
+ is_generator, CHECK_OK); |
materialized_literal_count = function_state.materialized_literal_count(); |
expected_property_count = function_state.expected_property_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, |
@@ -3558,6 +3437,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
CheckConflictingVarDeclarations(scope, CHECK_OK); |
} |
+ FunctionLiteral::IsGeneratorFlag generator = is_generator |
+ ? FunctionLiteral::kIsGenerator |
+ : FunctionLiteral::kNotGenerator; |
FunctionLiteral* function_literal = |
factory()->NewFunctionLiteral(function_name, |
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) { |
HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse()); |
ASSERT_EQ(Token::LBRACE, scanner()->current_token()); |