Commit 7955937d authored by marja@chromium.org's avatar marja@chromium.org

Refactor Parser to make it usable on a background thread.

- Background Parsers cannot get the following data from Isolate (pass it to the
ctor instead): stack limit (background Parsers need a different stack limit),
UnicodeCache (background parsers need a separate UnicodeCache), hash seed
(Parser cannot access the Heap to get it). The Parser::Parse API won't change.

- Make the internalization phase (where Parser interacts with the heap) more
explicit. Previously, Parser was interacting with the heap here and there.

- Move HandleSourceURLComments out of DoParseProgram, so that background parsing
can use DoParseProgram too.

BUG=
R=rossberg@chromium.org

Review URL: https://codereview.chromium.org/527763002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23600 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2de08b49
...@@ -739,23 +739,25 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral( ...@@ -739,23 +739,25 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral(
} }
Parser::Parser(CompilationInfo* info) Parser::Parser(CompilationInfo* info, ParseInfo* parse_info)
: ParserBase<ParserTraits>( : ParserBase<ParserTraits>(&scanner_, parse_info->stack_limit,
&scanner_, info->isolate()->stack_guard()->real_climit(), info->extension(), NULL, info->zone(),
info->extension(), NULL, info->zone(), info->ast_node_id_gen(), this), info->ast_node_id_gen(), this),
isolate_(info->isolate()), isolate_(info->isolate()),
script_(info->script()), script_(info->script()),
scanner_(isolate_->unicode_cache()), scanner_(parse_info->unicode_cache),
reusable_preparser_(NULL), reusable_preparser_(NULL),
original_scope_(NULL), original_scope_(NULL),
target_stack_(NULL), target_stack_(NULL),
cached_parse_data_(NULL), cached_parse_data_(NULL),
ast_value_factory_(NULL), ast_value_factory_(info->ast_value_factory()),
info_(info), info_(info),
has_pending_error_(false), has_pending_error_(false),
pending_error_message_(NULL), pending_error_message_(NULL),
pending_error_arg_(NULL), pending_error_arg_(NULL),
pending_error_char_arg_(NULL) { pending_error_char_arg_(NULL),
total_preparse_skipped_(0),
pre_parse_timer_(NULL) {
DCHECK(!script_.is_null()); DCHECK(!script_.is_null());
set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping); set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping);
set_allow_modules(!info->is_native() && FLAG_harmony_modules); set_allow_modules(!info->is_native() && FLAG_harmony_modules);
...@@ -769,12 +771,18 @@ Parser::Parser(CompilationInfo* info) ...@@ -769,12 +771,18 @@ Parser::Parser(CompilationInfo* info)
++feature) { ++feature) {
use_counts_[feature] = 0; use_counts_[feature] = 0;
} }
if (ast_value_factory_ == NULL) {
ast_value_factory_ = new AstValueFactory(zone(), parse_info->hash_seed);
}
} }
FunctionLiteral* Parser::ParseProgram() { FunctionLiteral* Parser::ParseProgram() {
// TODO(bmeurer): We temporarily need to pass allow_nesting = true here, // TODO(bmeurer): We temporarily need to pass allow_nesting = true here,
// see comment for HistogramTimerScope class. // see comment for HistogramTimerScope class.
// It's OK to use the counters here, since this function is only called in
// the main thread.
HistogramTimerScope timer_scope(isolate()->counters()->parse(), true); HistogramTimerScope timer_scope(isolate()->counters()->parse(), true);
Handle<String> source(String::cast(script_->source())); Handle<String> source(String::cast(script_->source()));
isolate()->counters()->total_parse_size()->Increment(source->length()); isolate()->counters()->total_parse_size()->Increment(source->length());
...@@ -808,6 +816,7 @@ FunctionLiteral* Parser::ParseProgram() { ...@@ -808,6 +816,7 @@ FunctionLiteral* Parser::ParseProgram() {
scanner_.Initialize(&stream); scanner_.Initialize(&stream);
result = DoParseProgram(info(), source); result = DoParseProgram(info(), source);
} }
HandleSourceURLComments();
if (FLAG_trace_parse && result != NULL) { if (FLAG_trace_parse && result != NULL) {
double ms = timer.Elapsed().InMillisecondsF(); double ms = timer.Elapsed().InMillisecondsF();
...@@ -876,8 +885,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, ...@@ -876,8 +885,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
int beg_pos = scanner()->location().beg_pos; int beg_pos = scanner()->location().beg_pos;
ParseSourceElements(body, Token::EOS, info->is_eval(), true, &ok); ParseSourceElements(body, Token::EOS, info->is_eval(), true, &ok);
HandleSourceURLComments();
if (ok && strict_mode() == STRICT) { if (ok && strict_mode() == STRICT) {
CheckOctalLiteral(beg_pos, scanner()->location().end_pos, &ok); CheckOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
} }
...@@ -896,7 +903,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, ...@@ -896,7 +903,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
} }
} }
ast_value_factory_->Internalize(isolate());
if (ok) { if (ok) {
result = factory()->NewFunctionLiteral( result = factory()->NewFunctionLiteral(
ast_value_factory_->empty_string(), ast_value_factory_, scope_, body, ast_value_factory_->empty_string(), ast_value_factory_, scope_, body,
...@@ -910,10 +916,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, ...@@ -910,10 +916,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
result->set_ast_properties(factory()->visitor()->ast_properties()); result->set_ast_properties(factory()->visitor()->ast_properties());
result->set_dont_optimize_reason( result->set_dont_optimize_reason(
factory()->visitor()->dont_optimize_reason()); factory()->visitor()->dont_optimize_reason());
} else if (stack_overflow()) {
isolate()->StackOverflow();
} else {
ThrowPendingError();
} }
} }
...@@ -925,6 +927,8 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, ...@@ -925,6 +927,8 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
FunctionLiteral* Parser::ParseLazy() { FunctionLiteral* Parser::ParseLazy() {
// It's OK to use the counters here, since this function is only called in
// the main thread.
HistogramTimerScope timer_scope(isolate()->counters()->parse_lazy()); HistogramTimerScope timer_scope(isolate()->counters()->parse_lazy());
Handle<String> source(String::cast(script_->source())); Handle<String> source(String::cast(script_->source()));
isolate()->counters()->total_parse_size()->Increment(source->length()); isolate()->counters()->total_parse_size()->Increment(source->length());
...@@ -1017,14 +1021,7 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { ...@@ -1017,14 +1021,7 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
// Make sure the target stack is empty. // Make sure the target stack is empty.
DCHECK(target_stack_ == NULL); DCHECK(target_stack_ == NULL);
ast_value_factory_->Internalize(isolate()); if (result != NULL) {
if (result == NULL) {
if (stack_overflow()) {
isolate()->StackOverflow();
} else {
ThrowPendingError();
}
} else {
Handle<String> inferred_name(shared_info->inferred_name()); Handle<String> inferred_name(shared_info->inferred_name());
result->set_inferred_name(inferred_name); result->set_inferred_name(inferred_name);
} }
...@@ -3654,8 +3651,7 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name, ...@@ -3654,8 +3651,7 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
if (!*ok) { if (!*ok) {
return; return;
} }
isolate()->counters()->total_preparse_skipped()->Increment( total_preparse_skipped_ += scope_->end_position() - function_block_pos;
scope_->end_position() - function_block_pos);
*materialized_literal_count = entry.literal_count(); *materialized_literal_count = entry.literal_count();
*expected_property_count = entry.property_count(); *expected_property_count = entry.property_count();
scope_->SetStrictMode(entry.strict_mode()); scope_->SetStrictMode(entry.strict_mode());
...@@ -3683,8 +3679,7 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name, ...@@ -3683,8 +3679,7 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
if (!*ok) { if (!*ok) {
return; return;
} }
isolate()->counters()->total_preparse_skipped()->Increment( total_preparse_skipped_ += scope_->end_position() - function_block_pos;
scope_->end_position() - function_block_pos);
*materialized_literal_count = logger.literals(); *materialized_literal_count = logger.literals();
*expected_property_count = logger.properties(); *expected_property_count = logger.properties();
scope_->SetStrictMode(logger.strict_mode()); scope_->SetStrictMode(logger.strict_mode());
...@@ -3762,12 +3757,15 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( ...@@ -3762,12 +3757,15 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
SingletonLogger* logger) { SingletonLogger* logger) {
HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse()); // This function may be called on a background thread too; record only the
// main thread preparse times.
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Start();
}
DCHECK_EQ(Token::LBRACE, scanner()->current_token()); DCHECK_EQ(Token::LBRACE, scanner()->current_token());
if (reusable_preparser_ == NULL) { 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);
reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping()); reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping());
reusable_preparser_->set_allow_modules(allow_modules()); reusable_preparser_->set_allow_modules(allow_modules());
reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax()); reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax());
...@@ -3782,6 +3780,9 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( ...@@ -3782,6 +3780,9 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
reusable_preparser_->PreParseLazyFunction(strict_mode(), reusable_preparser_->PreParseLazyFunction(strict_mode(),
is_generator(), is_generator(),
logger); logger);
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Stop();
}
return result; return result;
} }
...@@ -3965,13 +3966,28 @@ void Parser::ThrowPendingError() { ...@@ -3965,13 +3966,28 @@ void Parser::ThrowPendingError() {
} }
void Parser::InternalizeUseCounts() { void Parser::Internalize() {
// Internalize strings.
ast_value_factory_->Internalize(isolate());
// Error processing.
if (info()->function() == NULL) {
if (stack_overflow()) {
isolate()->StackOverflow();
} else {
ThrowPendingError();
}
}
// Move statistics to Isolate.
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) { ++feature) {
for (int i = 0; i < use_counts_[feature]; ++i) { for (int i = 0; i < use_counts_[feature]; ++i) {
isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature)); isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature));
} }
} }
isolate()->counters()->total_preparse_skipped()->Increment(
total_preparse_skipped_);
} }
...@@ -4809,14 +4825,10 @@ bool RegExpParser::ParseRegExp(FlatStringReader* input, ...@@ -4809,14 +4825,10 @@ bool RegExpParser::ParseRegExp(FlatStringReader* input,
bool Parser::Parse() { bool Parser::Parse() {
DCHECK(info()->function() == NULL); DCHECK(info()->function() == NULL);
FunctionLiteral* result = NULL; FunctionLiteral* result = NULL;
ast_value_factory_ = info()->ast_value_factory(); pre_parse_timer_ = isolate()->counters()->pre_parse();
if (ast_value_factory_ == NULL) {
ast_value_factory_ =
new AstValueFactory(zone(), isolate()->heap()->HashSeed());
}
if (allow_natives_syntax() || extension_ != NULL) { if (allow_natives_syntax() || extension_ != NULL) {
// If intrinsics are allowed, the Parser cannot operate independent of the // If intrinsics are allowed, the Parser cannot operate independent of the
// V8 heap because of Rumtime. Tell the string table to internalize strings // V8 heap because of Runtime. Tell the string table to internalize strings
// and values right after they're created. // and values right after they're created.
ast_value_factory_->Internalize(isolate()); ast_value_factory_->Internalize(isolate());
} }
...@@ -4833,15 +4845,14 @@ bool Parser::Parse() { ...@@ -4833,15 +4845,14 @@ bool Parser::Parse() {
result = ParseProgram(); result = ParseProgram();
} }
info()->SetFunction(result); info()->SetFunction(result);
Internalize();
DCHECK(ast_value_factory_->IsInternalized()); DCHECK(ast_value_factory_->IsInternalized());
// info takes ownership of ast_value_factory_. // info takes ownership of ast_value_factory_.
if (info()->ast_value_factory() == NULL) { if (info()->ast_value_factory() == NULL) {
info()->SetAstValueFactory(ast_value_factory_); info()->SetAstValueFactory(ast_value_factory_);
} }
ast_value_factory_ = NULL; ast_value_factory_ = NULL;
InternalizeUseCounts();
return (result != NULL); return (result != NULL);
} }
......
...@@ -597,7 +597,16 @@ class ParserTraits { ...@@ -597,7 +597,16 @@ class ParserTraits {
class Parser : public ParserBase<ParserTraits> { class Parser : public ParserBase<ParserTraits> {
public: public:
explicit Parser(CompilationInfo* info); // Note that the hash seed in ParseInfo must be the hash seed from the
// Isolate's heap, otherwise the heap will be in an inconsistent state once
// the strings created by the Parser are internalized.
struct ParseInfo {
uintptr_t stack_limit;
uint32_t hash_seed;
UnicodeCache* unicode_cache;
};
Parser(CompilationInfo* info, ParseInfo* parse_info);
~Parser() { ~Parser() {
delete reusable_preparser_; delete reusable_preparser_;
reusable_preparser_ = NULL; reusable_preparser_ = NULL;
...@@ -610,7 +619,10 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -610,7 +619,10 @@ class Parser : public ParserBase<ParserTraits> {
// nodes) if parsing failed. // nodes) if parsing failed.
static bool Parse(CompilationInfo* info, static bool Parse(CompilationInfo* info,
bool allow_lazy = false) { bool allow_lazy = false) {
Parser parser(info); ParseInfo parse_info = {info->isolate()->stack_guard()->real_climit(),
info->isolate()->heap()->HashSeed(),
info->isolate()->unicode_cache()};
Parser parser(info, &parse_info);
parser.set_allow_lazy(allow_lazy); parser.set_allow_lazy(allow_lazy);
return parser.Parse(); return parser.Parse();
} }
...@@ -797,7 +809,9 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -797,7 +809,9 @@ class Parser : public ParserBase<ParserTraits> {
void ThrowPendingError(); void ThrowPendingError();
void InternalizeUseCounts(); // Handle errors detected during parsing, move statistics to Isolate,
// internalize strings (move them to the heap).
void Internalize();
Isolate* isolate_; Isolate* isolate_;
...@@ -819,7 +833,11 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -819,7 +833,11 @@ class Parser : public ParserBase<ParserTraits> {
const char* pending_error_char_arg_; const char* pending_error_char_arg_;
bool pending_error_is_reference_error_; bool pending_error_is_reference_error_;
// Other information which will be stored in Parser and moved to Isolate after
// parsing.
int use_counts_[v8::Isolate::kUseCounterFeatureCount]; int use_counts_[v8::Isolate::kUseCounterFeatureCount];
int total_preparse_skipped_;
HistogramTimer* pre_parse_timer_;
}; };
......
...@@ -78,8 +78,8 @@ class ParserBase : public Traits { ...@@ -78,8 +78,8 @@ class ParserBase : public Traits {
fni_(NULL), fni_(NULL),
log_(log), log_(log),
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
scanner_(scanner),
stack_limit_(stack_limit), stack_limit_(stack_limit),
scanner_(scanner),
stack_overflow_(false), stack_overflow_(false),
allow_lazy_(false), allow_lazy_(false),
allow_natives_syntax_(false), allow_natives_syntax_(false),
...@@ -569,10 +569,10 @@ class ParserBase : public Traits { ...@@ -569,10 +569,10 @@ class ParserBase : public Traits {
FuncNameInferrer* fni_; FuncNameInferrer* fni_;
ParserRecorder* log_; ParserRecorder* log_;
Mode mode_; Mode mode_;
uintptr_t stack_limit_;
private: private:
Scanner* scanner_; Scanner* scanner_;
uintptr_t stack_limit_;
bool stack_overflow_; bool stack_overflow_;
bool allow_lazy_; bool allow_lazy_;
......
...@@ -1128,7 +1128,10 @@ TEST(ScopePositions) { ...@@ -1128,7 +1128,10 @@ TEST(ScopePositions) {
CHECK_EQ(source->length(), kProgramSize); CHECK_EQ(source->length(), kProgramSize);
i::Handle<i::Script> script = factory->NewScript(source); i::Handle<i::Script> script = factory->NewScript(source);
i::CompilationInfoWithZone info(script); i::CompilationInfoWithZone info(script);
i::Parser parser(&info); i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
isolate->heap()->HashSeed(),
isolate->unicode_cache()};
i::Parser parser(&info, &parse_info);
parser.set_allow_lazy(true); parser.set_allow_lazy(true);
parser.set_allow_harmony_scoping(true); parser.set_allow_harmony_scoping(true);
parser.set_allow_arrow_functions(true); parser.set_allow_arrow_functions(true);
...@@ -1263,7 +1266,10 @@ void TestParserSyncWithFlags(i::Handle<i::String> source, ...@@ -1263,7 +1266,10 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
{ {
i::Handle<i::Script> script = factory->NewScript(source); i::Handle<i::Script> script = factory->NewScript(source);
i::CompilationInfoWithZone info(script); i::CompilationInfoWithZone info(script);
i::Parser parser(&info); i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
isolate->heap()->HashSeed(),
isolate->unicode_cache()};
i::Parser parser(&info, &parse_info);
SetParserFlags(&parser, flags); SetParserFlags(&parser, flags);
info.MarkAsGlobal(); info.MarkAsGlobal();
parser.Parse(); parser.Parse();
...@@ -3125,7 +3131,10 @@ TEST(InnerAssignment) { ...@@ -3125,7 +3131,10 @@ TEST(InnerAssignment) {
i::Handle<i::Script> script = factory->NewScript(source); i::Handle<i::Script> script = factory->NewScript(source);
i::CompilationInfoWithZone info(script); i::CompilationInfoWithZone info(script);
i::Parser parser(&info); i::Parser::ParseInfo parse_info = {
isolate->stack_guard()->real_climit(),
isolate->heap()->HashSeed(), isolate->unicode_cache()};
i::Parser parser(&info, &parse_info);
parser.set_allow_harmony_scoping(true); parser.set_allow_harmony_scoping(true);
CHECK(parser.Parse()); CHECK(parser.Parse());
CHECK(i::Rewriter::Rewrite(&info)); CHECK(i::Rewriter::Rewrite(&info));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment