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