| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index 9d37c88bf4aad9fbb03830440c58453c77f6402f..b6f7812f0c638540ee25c6e9f343f1245db9de22 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -35,6 +35,7 @@
|
| #include "compiler.h"
|
| #include "messages.h"
|
| #include "parser.h"
|
| +#include "parser-thread.h"
|
| #include "platform.h"
|
| #include "preparser.h"
|
| #include "runtime.h"
|
| @@ -45,6 +46,27 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| +namespace {
|
| +
|
| +// Returns NULL if the string is not external. Caller takes ownership of the
|
| +// returned stream.
|
| +Utf16CharacterStream* ExternalCharacterStreamFromString(Handle<String> string) {
|
| + if (string->IsExternalAsciiString()) {
|
| + return new ExternalOneByteStringUtf16CharacterStream(
|
| + Handle<ExternalAsciiString>::cast(string)->GetChars(), 0,
|
| + string->length());
|
| + }
|
| + if (string->IsExternalTwoByteString()) {
|
| + return new ExternalTwoByteStringUtf16CharacterStream(
|
| + Handle<ExternalTwoByteString>::cast(string)->GetTwoByteData(0), 0,
|
| + string->length());
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| RegExpBuilder::RegExpBuilder(Zone* zone)
|
| : zone_(zone),
|
| pending_empty_(false),
|
| @@ -839,6 +861,7 @@ Parser::Parser(CompilationInfo* info)
|
| info->isolate()->stack_guard()->real_climit(),
|
| info->extension(),
|
| NULL,
|
| + NULL,
|
| info->zone(),
|
| this),
|
| isolate_(info->isolate()),
|
| @@ -875,22 +898,25 @@ FunctionLiteral* Parser::ParseProgram() {
|
| }
|
| fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
|
|
|
| - // Initialize parser state.
|
| CompleteParserRecorder recorder;
|
| +
|
| if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
|
| + ASSERT(allow_lazy());
|
| log_ = &recorder;
|
| } else if (cached_data_mode_ == CONSUME_CACHED_DATA) {
|
| (*cached_data_)->Initialize();
|
| }
|
| -
|
| source = String::Flatten(source);
|
| + StartFastParserTaskIfPossible(source);
|
| +
|
| FunctionLiteral* result;
|
| if (source->IsExternalTwoByteString()) {
|
| // Notice that the stream is destroyed at the end of the branch block.
|
| // The last line of the blocks can't be moved outside, even though they're
|
| // identical calls.
|
| ExternalTwoByteStringUtf16CharacterStream stream(
|
| - Handle<ExternalTwoByteString>::cast(source), 0, source->length());
|
| + Handle<ExternalTwoByteString>::cast(source)->GetTwoByteData(0), 0,
|
| + source->length());
|
| scanner_.Initialize(&stream);
|
| result = DoParseProgram(info(), source);
|
| } else {
|
| @@ -917,6 +943,7 @@ FunctionLiteral* Parser::ParseProgram() {
|
| *cached_data_ = new ScriptData(store);
|
| log_ = NULL;
|
| }
|
| + FinishFastParserTask();
|
| return result;
|
| }
|
|
|
| @@ -1026,7 +1053,7 @@ FunctionLiteral* Parser::ParseLazy() {
|
| FunctionLiteral* result;
|
| if (source->IsExternalTwoByteString()) {
|
| ExternalTwoByteStringUtf16CharacterStream stream(
|
| - Handle<ExternalTwoByteString>::cast(source),
|
| + Handle<ExternalTwoByteString>::cast(source)->GetTwoByteData(0),
|
| shared_info->start_position(),
|
| shared_info->end_position());
|
| result = ParseLazy(&stream);
|
| @@ -3386,8 +3413,24 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| parenthesized_function_ = false; // The bit was set for this function only.
|
|
|
| if (is_lazily_parsed) {
|
| - SkipLazyFunctionBody(function_name, &materialized_literal_count,
|
| - &expected_property_count, CHECK_OK);
|
| + int function_block_pos = position();
|
| + StrictMode strict_mode;
|
| + SkipLazyFunctionBody(
|
| + function_name, function_block_pos, &materialized_literal_count,
|
| + &expected_property_count, &strict_mode, CHECK_OK);
|
| + scope_->SetStrictMode(strict_mode);
|
| + Expect(Token::RBRACE, CHECK_OK);
|
| + // Position right after terminal '}'.
|
| + int body_end = scanner()->location().end_pos;
|
| + scope_->set_end_position(body_end);
|
| + isolate()->counters()->total_preparse_skipped()->Increment(
|
| + body_end - function_block_pos);
|
| + if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
|
| + ASSERT(log_);
|
| + log_->LogFunction(function_block_pos, body_end,
|
| + materialized_literal_count, expected_property_count,
|
| + strict_mode);
|
| + }
|
| } else {
|
| body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
|
| is_generator, CHECK_OK);
|
| @@ -3465,10 +3508,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|
|
|
|
| void Parser::SkipLazyFunctionBody(Handle<String> function_name,
|
| + int function_block_pos,
|
| int* materialized_literal_count,
|
| int* expected_property_count,
|
| + StrictMode* strict_mode,
|
| 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.
|
| @@ -3478,71 +3522,67 @@ void Parser::SkipLazyFunctionBody(Handle<String> function_name,
|
| 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);
|
| + scanner()->SeekForward(entry.end_pos() - 1);
|
| *materialized_literal_count = entry.literal_count();
|
| *expected_property_count = entry.property_count();
|
| - scope_->SetStrictMode(entry.strict_mode());
|
| + *strict_mode = 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 if (thread_) {
|
| + int start, end;
|
| + // This will wait until the background thread has found the lazy function.
|
| + thread_->Consume(&start, &end, materialized_literal_count,
|
| + expected_property_count, strict_mode);
|
| + if (start == function_block_pos) {
|
| + scanner()->SeekForward(end - 1);
|
| + } else {
|
| + ProcessErrorFromRecorder(thread_->result(), thread_->recorder(), ok);
|
| + // If there is no error, the thread produced data for a lazy function
|
| + // which was not the function we expected. That should never happen.
|
| + ASSERT(!*ok);
|
| + *ok = false;
|
| + FinishFastParserTask();
|
| + }
|
| } else {
|
| // With no cached data, we partially parse the function, without building an
|
| - // AST. This gathers the data needed to build a lazy function.
|
| + // AST. This gathers the data needed to build a lazy function. The PreParser
|
| + // uses the same scanner, so it will be automatically positioned in the
|
| + // right position without additional seeking.
|
| 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);
|
| + ProcessErrorFromRecorder(result, &logger, 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());
|
| + *strict_mode = logger.strict_mode();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Parser::ProcessErrorFromRecorder(PreParser::PreParseResult result,
|
| + const SingletonLogger* logger, bool* ok) {
|
| + if (result == PreParser::kPreParseStackOverflow) {
|
| + set_stack_overflow();
|
| + *ok = false;
|
| + } else 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;
|
| }
|
| }
|
|
|
| @@ -3613,7 +3653,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
|
|
|
| if (reusable_preparser_ == NULL) {
|
| intptr_t stack_limit = isolate()->stack_guard()->real_climit();
|
| - reusable_preparser_ = new PreParser(&scanner_, NULL, stack_limit);
|
| + reusable_preparser_ = new PreParser(&scanner_, NULL, stack_limit, NULL);
|
| reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping());
|
| reusable_preparser_->set_allow_modules(allow_modules());
|
| reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax());
|
| @@ -3623,14 +3663,36 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
|
| reusable_preparser_->set_allow_harmony_numeric_literals(
|
| allow_harmony_numeric_literals());
|
| }
|
| - PreParser::PreParseResult result =
|
| - reusable_preparser_->PreParseLazyFunction(strict_mode(),
|
| - is_generator(),
|
| - logger);
|
| + PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
|
| + strict_mode(), is_generator(), logger);
|
| return result;
|
| }
|
|
|
|
|
| +void Parser::StartFastParserTaskIfPossible(Handle<String> source) {
|
| + if (cached_data_mode_ == PRODUCE_CACHED_DATA && FLAG_parallel_parse &&
|
| + source->length() >= FLAG_min_parallel_parse_length) {
|
| + Utf16CharacterStream* stream = ExternalCharacterStreamFromString(source);
|
| + if (stream) {
|
| + ASSERT(isolate()->fast_parser_thread());
|
| + thread_ = isolate()->fast_parser_thread();
|
| + thread_->StartBackgroundParsing(stream, allow_harmony_scoping(),
|
| + allow_modules(), allow_natives_syntax(),
|
| + allow_generators(), allow_for_of(),
|
| + allow_harmony_numeric_literals());
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void Parser::FinishFastParserTask() {
|
| + if (thread_) {
|
| + thread_->FinishBackgroundParsing();
|
| + thread_ = NULL;
|
| + }
|
| +}
|
| +
|
| +
|
| Expression* Parser::ParseV8Intrinsic(bool* ok) {
|
| // CallRuntime ::
|
| // '%' Identifier Arguments
|
|
|