Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index e19af1cd5cd3dd265633660544b675246588c17b..50f3a7a3257a39e67c6054dee482e861704cf621 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -586,24 +586,27 @@ Parser::FunctionState::~FunctionState() { |
// Implementation of Parser |
Parser::Parser(Handle<Script> script, |
- bool allow_natives_syntax, |
+ int parser_flags, |
v8::Extension* extension, |
ScriptDataImpl* pre_data) |
: isolate_(script->GetIsolate()), |
symbol_cache_(pre_data ? pre_data->symbol_count() : 0), |
script_(script), |
scanner_(isolate_->unicode_cache()), |
+ reusable_preparser_(NULL), |
top_scope_(NULL), |
current_function_state_(NULL), |
target_stack_(NULL), |
extension_(extension), |
pre_data_(pre_data), |
fni_(NULL), |
- allow_natives_syntax_(allow_natives_syntax), |
+ allow_natives_syntax_((parser_flags & kAllowNativesSyntax) != 0), |
+ allow_lazy_((parser_flags & kAllowLazy) != 0), |
stack_overflow_(false), |
parenthesized_function_(false), |
- harmony_scoping_(false) { |
+ harmony_scoping_((parser_flags & kHarmonyScoping) != 0) { |
AstNode::ResetIds(); |
+ if (harmony_scoping_) scanner().SetHarmonyScoping(true); |
} |
@@ -641,7 +644,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, |
if (pre_data_ != NULL) pre_data_->Initialize(); |
// Compute the parsing mode. |
- mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY; |
+ mode_ = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY; |
if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY; |
Handle<String> no_name = isolate()->factory()->empty_symbol(); |
@@ -3909,6 +3912,98 @@ ZoneList<Expression*>* Parser::ParseArguments(bool* ok) { |
} |
+class SingletonLogger : public ParserRecorder { |
+ public: |
+ SingletonLogger() : has_error_(false), start_(-1), end_(-1) { } |
+ ~SingletonLogger() { } |
+ |
+ void Reset() { has_error_ = false; } |
+ |
+ virtual void LogFunction(int start, |
+ int end, |
+ int literals, |
+ int properties, |
+ StrictModeFlag strict_mode) { |
+ ASSERT(!has_error_); |
+ start_ = start; |
+ end_ = end; |
+ literals_ = literals; |
+ properties_ = properties; |
+ strict_mode_ = strict_mode; |
+ }; |
+ |
+ // Logs a symbol creation of a literal or identifier. |
+ virtual void LogAsciiSymbol(int start, Vector<const char> literal) { } |
+ virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { } |
+ |
+ // Logs an error message and marks the log as containing an error. |
+ // Further logging will be ignored, and ExtractData will return a vector |
+ // representing the error only. |
+ virtual void LogMessage(int start, |
+ int end, |
+ const char* message, |
+ const char* argument_opt) { |
+ has_error_ = true; |
+ start_ = start; |
+ end_ = end; |
+ message_ = message; |
+ argument_opt_ = argument_opt; |
+ } |
+ |
+ virtual int function_position() { return 0; } |
+ |
+ virtual int symbol_position() { return 0; } |
+ |
+ virtual int symbol_ids() { return -1; } |
+ |
+ virtual Vector<unsigned> ExtractData() { |
+ UNREACHABLE(); |
+ return Vector<unsigned>(); |
+ } |
+ |
+ virtual void PauseRecording() { } |
+ |
+ virtual void ResumeRecording() { } |
+ |
+ bool has_error() { return has_error_; } |
+ |
+ int start() { return start_; } |
+ int end() { return end_; } |
+ int literals() { |
+ ASSERT(!has_error_); |
+ return literals_; |
+ } |
+ int properties() { |
+ ASSERT(!has_error_); |
+ return properties_; |
+ } |
+ StrictModeFlag strict_mode() { |
+ ASSERT(!has_error_); |
+ return strict_mode_; |
+ } |
+ const char* message() { |
+ ASSERT(has_error_); |
+ return message_; |
+ } |
+ const char* argument_opt() { |
+ ASSERT(has_error_); |
+ return argument_opt_; |
+ } |
+ |
+ private: |
+ bool has_error_; |
+ int start_; |
+ int end_; |
+ // For function entries. |
+ int literals_; |
+ int properties_; |
+ StrictModeFlag strict_mode_; |
+ // For error messages. |
+ const char* message_; |
+ const char* argument_opt_; |
+}; |
+ |
+ |
FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, |
bool name_is_strict_reserved, |
int function_token_position, |
@@ -3935,8 +4030,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, |
? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE) |
: NewScope(top_scope_, FUNCTION_SCOPE); |
ZoneList<Statement*>* body = NULL; |
- int materialized_literal_count; |
- int expected_property_count; |
+ int materialized_literal_count = -1; |
+ int expected_property_count = -1; |
int handler_count = 0; |
bool only_simple_this_property_assignments; |
Handle<FixedArray> this_property_assignments; |
@@ -4012,33 +4107,66 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, |
bool is_lazily_compiled = (mode() == PARSE_LAZILY && |
top_scope_->outer_scope()->is_global_scope() && |
top_scope_->HasTrivialOuterContext() && |
- !parenthesized_function_ && |
- pre_data() != NULL); |
+ !parenthesized_function_); |
parenthesized_function_ = false; // The bit was set for this function only. |
if (is_lazily_compiled) { |
int function_block_pos = scanner().location().beg_pos; |
- FunctionEntry entry = pre_data()->GetFunctionEntry(function_block_pos); |
- if (!entry.is_valid()) { |
- // There is no preparser data for the function, we will not lazily |
- // compile after all. |
- is_lazily_compiled = false; |
+ FunctionEntry entry; |
+ if (pre_data_ != NULL) { |
+ entry = pre_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. |
+ ReportInvalidPreparseData(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(); |
+ top_scope_->SetStrictModeFlag(entry.strict_mode_flag()); |
+ only_simple_this_property_assignments = false; |
+ this_property_assignments = isolate()->factory()->empty_fixed_array(); |
+ } else { |
+ is_lazily_compiled = false; |
+ } |
} else { |
- scope->set_end_position(entry.end_pos()); |
- if (scope->end_position() <= function_block_pos) { |
- // End position greater than end of stream is safe, and hard to check. |
- ReportInvalidPreparseData(function_name, CHECK_OK); |
+ // No preparser data, so partially parse the function now, without |
+ // building an AST. |
+ SingletonLogger logger; |
+ preparser::PreParser::PreParseResult result = |
+ LazyParseFunctionLiteral(&logger); |
+ if (result == preparser::PreParser::kPreParseStackOverflow) { |
+ // Propagate stack overflow. |
+ stack_overflow_ = true; |
+ *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); |
+ } |
+ ReportMessageAt(Scanner::Location(logger.start(), logger.end()), |
+ logger.message(), args); |
+ *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); |
- // Seek to position just before terminal '}'. |
- scanner().SeekForward(scope->end_position() - 1); |
- materialized_literal_count = entry.literal_count(); |
- expected_property_count = entry.property_count(); |
- top_scope_->SetStrictModeFlag(entry.strict_mode_flag()); |
+ materialized_literal_count = logger.literals(); |
+ expected_property_count = logger.properties(); |
+ top_scope_->SetStrictModeFlag(logger.strict_mode()); |
only_simple_this_property_assignments = false; |
this_property_assignments = isolate()->factory()->empty_fixed_array(); |
- Expect(Token::RBRACE, CHECK_OK); |
} |
} |
@@ -4139,6 +4267,30 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, |
} |
+preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral( |
+ SingletonLogger* logger) { |
+ HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse()); |
+ ASSERT_EQ(Token::LBRACE, scanner().current_token()); |
+ int flags = kAllowLazy; |
+ if (allow_natives_syntax_) flags |= kAllowNativesSyntax; |
+ if (scanner_.HarmonyScoping()) flags |= kHarmonyScoping; |
+ |
+ if (reusable_preparser_ == NULL) { |
+ intptr_t stack_limit = isolate()->stack_guard()->real_climit(); |
+ bool allow_lazy = true; |
+ reusable_preparser_ = new preparser::PreParser(&scanner_, |
+ NULL, |
+ stack_limit, |
+ allow_lazy, |
+ allow_natives_syntax_); |
+ } |
+ preparser::PreParser::PreParseResult result = |
+ reusable_preparser_->PreParseLazyFunction(top_scope_->is_strict_mode(), |
+ logger); |
+ return result; |
+} |
+ |
+ |
Expression* Parser::ParseV8Intrinsic(bool* ok) { |
// CallRuntime :: |
// '%' Identifier Arguments |
@@ -5357,10 +5509,12 @@ static ScriptDataImpl* DoPreParse(UC16CharacterStream* source, |
scanner.SetHarmonyScoping((flags & kHarmonyScoping) != 0); |
scanner.Initialize(source); |
intptr_t stack_limit = isolate->stack_guard()->real_climit(); |
- if (!preparser::PreParser::PreParseProgram(&scanner, |
- recorder, |
- flags, |
- stack_limit)) { |
+ preparser::PreParser::PreParseResult result = |
+ preparser::PreParser::PreParseProgram(&scanner, |
+ recorder, |
+ flags, |
+ stack_limit); |
+ if (result == preparser::PreParser::kPreParseStackOverflow) { |
isolate->StackOverflow(); |
return NULL; |
} |
@@ -5423,29 +5577,25 @@ bool RegExpParser::ParseRegExp(FlatStringReader* input, |
} |
-bool ParserApi::Parse(CompilationInfo* info) { |
+bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) { |
ASSERT(info->function() == NULL); |
FunctionLiteral* result = NULL; |
Handle<Script> script = info->script(); |
- bool harmony_scoping = !info->is_native() && FLAG_harmony_scoping; |
+ if (!info->is_native() && FLAG_harmony_scoping) { |
+ // Harmony scoping is requested. |
+ parsing_flags |= kHarmonyScoping; |
+ } |
+ if (FLAG_allow_natives_syntax || info->is_native()) { |
+ // We requre %identifier(..) syntax. |
+ parsing_flags |= kAllowNativesSyntax; |
+ } |
if (info->is_lazy()) { |
ASSERT(!info->is_eval()); |
- bool allow_natives_syntax = |
- FLAG_allow_natives_syntax || |
- info->is_native(); |
- Parser parser(script, allow_natives_syntax, NULL, NULL); |
- parser.SetHarmonyScoping(harmony_scoping); |
+ Parser parser(script, parsing_flags, NULL, NULL); |
result = parser.ParseLazy(info); |
} else { |
- // Whether we allow %identifier(..) syntax. |
- bool allow_natives_syntax = |
- info->is_native() || FLAG_allow_natives_syntax; |
ScriptDataImpl* pre_data = info->pre_parse_data(); |
- Parser parser(script, |
- allow_natives_syntax, |
- info->extension(), |
- pre_data); |
- parser.SetHarmonyScoping(harmony_scoping); |
+ Parser parser(script, parsing_flags, info->extension(), pre_data); |
if (pre_data != NULL && pre_data->has_error()) { |
Scanner::Location loc = pre_data->MessageLocation(); |
const char* message = pre_data->BuildMessage(); |