Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index c1e6815b002af688d7be6266384c1e561f3df94f..6db2b0d71c43a376f082819fd6d0dfa9b8907ae2 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -251,13 +251,13 @@ int ParseData::FunctionsSize() { |
} |
-void Parser::SetCachedData() { |
- if (compile_options() == ScriptCompiler::kNoCompileOptions) { |
+void Parser::SetCachedData(CompilationInfo* info) { |
+ if (compile_options_ == ScriptCompiler::kNoCompileOptions) { |
cached_parse_data_ = NULL; |
} else { |
- DCHECK(info_->cached_data() != NULL); |
- if (compile_options() == ScriptCompiler::kConsumeParserCache) { |
- cached_parse_data_ = ParseData::FromCachedData(*info_->cached_data()); |
+ DCHECK(info->cached_data() != NULL); |
+ if (compile_options_ == ScriptCompiler::kConsumeParserCache) { |
+ cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); |
} |
} |
} |
@@ -790,23 +790,27 @@ ClassLiteral* ParserTraits::ParseClassLiteral( |
Parser::Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed, |
UnicodeCache* unicode_cache) |
- : ParserBase<ParserTraits>(info->isolate(), info->zone(), &scanner_, |
- stack_limit, info->extension(), |
- info->ast_value_factory(), NULL, this), |
+ : ParserBase<ParserTraits>(info->zone(), &scanner_, stack_limit, |
+ info->extension(), info->ast_value_factory(), |
+ NULL, this), |
scanner_(unicode_cache), |
reusable_preparser_(NULL), |
original_scope_(NULL), |
target_stack_(NULL), |
+ compile_options_(info->compile_options()), |
cached_parse_data_(NULL), |
- info_(info), |
parsing_lazy_arrow_parameters_(false), |
has_pending_error_(false), |
pending_error_message_(NULL), |
pending_error_arg_(NULL), |
pending_error_char_arg_(NULL), |
total_preparse_skipped_(0), |
- pre_parse_timer_(NULL) { |
- DCHECK(!script().is_null() || info->source_stream() != NULL); |
+ pre_parse_timer_(NULL), |
+ parsing_on_main_thread_(true) { |
+ // Even though we were passed CompilationInfo, we should not store it in |
+ // Parser - this makes sure that Isolate is not accidentally accessed via |
+ // CompilationInfo during background parsing. |
+ DCHECK(!info->script().is_null() || info->source_stream() != NULL); |
set_allow_lazy(false); // Must be explicitly enabled. |
set_allow_natives(FLAG_allow_natives_syntax || info->is_native()); |
set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping); |
@@ -834,15 +838,18 @@ Parser::Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed, |
} |
-FunctionLiteral* Parser::ParseProgram() { |
+FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) { |
// TODO(bmeurer): We temporarily need to pass allow_nesting = true here, |
// 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); |
- Handle<String> source(String::cast(script()->source())); |
- isolate()->counters()->total_parse_size()->Increment(source->length()); |
+ // It's OK to use the Isolate & counters here, since this function is only |
+ // called in the main thread. |
+ DCHECK(parsing_on_main_thread_); |
+ |
+ Isolate* isolate = info->isolate(); |
+ HistogramTimerScope timer_scope(isolate->counters()->parse(), true); |
+ Handle<String> source(String::cast(info->script()->source())); |
+ isolate->counters()->total_parse_size()->Increment(source->length()); |
base::ElapsedTimer timer; |
if (FLAG_trace_parse) { |
timer.Start(); |
@@ -870,24 +877,24 @@ FunctionLiteral* Parser::ParseProgram() { |
ExternalTwoByteStringUtf16CharacterStream stream( |
Handle<ExternalTwoByteString>::cast(source), 0, source->length()); |
scanner_.Initialize(&stream); |
- result = DoParseProgram(info(), &top_scope, &eval_scope); |
+ result = DoParseProgram(info, &top_scope, &eval_scope); |
} else { |
GenericStringUtf16CharacterStream stream(source, 0, source->length()); |
scanner_.Initialize(&stream); |
- result = DoParseProgram(info(), &top_scope, &eval_scope); |
+ result = DoParseProgram(info, &top_scope, &eval_scope); |
} |
top_scope->set_end_position(source->length()); |
if (eval_scope != NULL) { |
eval_scope->set_end_position(source->length()); |
} |
- HandleSourceURLComments(); |
+ HandleSourceURLComments(info); |
if (FLAG_trace_parse && result != NULL) { |
double ms = timer.Elapsed().InMillisecondsF(); |
- if (info()->is_eval()) { |
+ if (info->is_eval()) { |
PrintF("[parsing eval"); |
- } else if (info()->script()->name()->IsString()) { |
- String* name = String::cast(info()->script()->name()); |
+ } else if (info->script()->name()->IsString()) { |
+ String* name = String::cast(info->script()->name()); |
SmartArrayPointer<char> name_chars = name->ToCString(); |
PrintF("[parsing script: %s", name_chars.get()); |
} else { |
@@ -896,7 +903,7 @@ FunctionLiteral* Parser::ParseProgram() { |
PrintF(" - took %0.3f ms]\n", ms); |
} |
if (produce_cached_parse_data()) { |
- if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); |
+ if (result != NULL) *info->cached_data() = recorder.GetScriptData(); |
log_ = NULL; |
} |
return result; |
@@ -905,6 +912,9 @@ FunctionLiteral* Parser::ParseProgram() { |
FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, |
Scope** eval_scope) { |
+ // Note that this function can be called from the main thread or from a |
+ // background thread. We should not access anything Isolate / heap dependent |
+ // via CompilationInfo, and also not pass it forward. |
DCHECK(scope_ == NULL); |
DCHECK(target_stack_ == NULL); |
@@ -918,8 +928,9 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, |
// The Scope is backed up by ScopeInfo (which is in the V8 heap); this |
// means the Parser cannot operate independent of the V8 heap. Tell the |
// string table to internalize strings and values right after they're |
- // created. |
- ast_value_factory()->Internalize(isolate()); |
+ // created. This kind of parsing can only be done in the main thread. |
+ DCHECK(parsing_on_main_thread_); |
+ ast_value_factory()->Internalize(info->isolate()); |
} |
original_scope_ = *scope; |
if (info->is_eval()) { |
@@ -996,17 +1007,18 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, |
} |
-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()); |
- Handle<String> source(String::cast(script()->source())); |
- isolate()->counters()->total_parse_size()->Increment(source->length()); |
+FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) { |
+ // It's OK to use the Isolate & counters here, since this function is only |
+ // called in the main thread. |
+ DCHECK(parsing_on_main_thread_); |
+ HistogramTimerScope timer_scope(info->isolate()->counters()->parse_lazy()); |
+ Handle<String> source(String::cast(info->script()->source())); |
+ info->isolate()->counters()->total_parse_size()->Increment(source->length()); |
base::ElapsedTimer timer; |
if (FLAG_trace_parse) { |
timer.Start(); |
} |
- Handle<SharedFunctionInfo> shared_info = info()->shared_info(); |
+ Handle<SharedFunctionInfo> shared_info = info->shared_info(); |
// Initialize parser state. |
source = String::Flatten(source); |
@@ -1016,12 +1028,12 @@ FunctionLiteral* Parser::ParseLazy() { |
Handle<ExternalTwoByteString>::cast(source), |
shared_info->start_position(), |
shared_info->end_position()); |
- result = ParseLazy(&stream); |
+ result = ParseLazy(info, &stream); |
} else { |
GenericStringUtf16CharacterStream stream(source, |
shared_info->start_position(), |
shared_info->end_position()); |
- result = ParseLazy(&stream); |
+ result = ParseLazy(info, &stream); |
} |
if (FLAG_trace_parse && result != NULL) { |
@@ -1033,8 +1045,9 @@ FunctionLiteral* Parser::ParseLazy() { |
} |
-FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { |
- Handle<SharedFunctionInfo> shared_info = info()->shared_info(); |
+FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, |
+ Utf16CharacterStream* source) { |
+ Handle<SharedFunctionInfo> shared_info = info->shared_info(); |
scanner_.Initialize(source); |
DCHECK(scope_ == NULL); |
DCHECK(target_stack_ == NULL); |
@@ -1053,18 +1066,21 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { |
{ |
// Parse the function literal. |
Scope* scope = NewScope(scope_, SCRIPT_SCOPE); |
- info()->SetScriptScope(scope); |
- if (!info()->closure().is_null()) { |
- scope = Scope::DeserializeScopeChain(isolate(), zone(), |
- info()->closure()->context(), scope); |
+ info->SetScriptScope(scope); |
+ if (!info->closure().is_null()) { |
+ // Ok to use Isolate here, since lazy function parsing is only done in the |
+ // main thread. |
+ DCHECK(parsing_on_main_thread_); |
+ scope = Scope::DeserializeScopeChain(info->isolate(), zone(), |
+ info->closure()->context(), scope); |
} |
original_scope_ = scope; |
AstNodeFactory function_factory(ast_value_factory()); |
FunctionState function_state(&function_state_, &scope_, scope, |
shared_info->kind(), &function_factory); |
DCHECK(is_sloppy(scope->language_mode()) || |
- is_strict(info()->language_mode())); |
- DCHECK(info()->language_mode() == shared_info->language_mode()); |
+ is_strict(info->language_mode())); |
+ DCHECK(info->language_mode() == shared_info->language_mode()); |
scope->SetLanguageMode(shared_info->language_mode()); |
FunctionLiteral::FunctionType function_type = shared_info->is_expression() |
? (shared_info->is_anonymous() |
@@ -4009,8 +4025,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( |
DCHECK_EQ(Token::LBRACE, scanner()->current_token()); |
if (reusable_preparser_ == NULL) { |
- reusable_preparser_ = new PreParser( |
- isolate(), zone(), &scanner_, ast_value_factory(), NULL, stack_limit_); |
+ reusable_preparser_ = new PreParser(zone(), &scanner_, ast_value_factory(), |
+ NULL, stack_limit_); |
reusable_preparser_->set_allow_lazy(true); |
reusable_preparser_->set_allow_natives(allow_natives()); |
reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping()); |
@@ -4250,25 +4266,26 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, |
} |
-void Parser::HandleSourceURLComments() { |
+void Parser::HandleSourceURLComments(CompilationInfo* info) { |
if (scanner_.source_url()->length() > 0) { |
- Handle<String> source_url = scanner_.source_url()->Internalize(isolate()); |
- info_->script()->set_source_url(*source_url); |
+ Handle<String> source_url = |
+ scanner_.source_url()->Internalize(info->isolate()); |
+ info->script()->set_source_url(*source_url); |
} |
if (scanner_.source_mapping_url()->length() > 0) { |
Handle<String> source_mapping_url = |
- scanner_.source_mapping_url()->Internalize(isolate()); |
- info_->script()->set_source_mapping_url(*source_mapping_url); |
+ scanner_.source_mapping_url()->Internalize(info->isolate()); |
+ info->script()->set_source_mapping_url(*source_mapping_url); |
} |
} |
-void Parser::ThrowPendingError() { |
+void Parser::ThrowPendingError(Isolate* isolate, Handle<Script> script) { |
DCHECK(ast_value_factory()->IsInternalized()); |
if (has_pending_error_) { |
- MessageLocation location(script(), pending_error_location_.beg_pos, |
+ MessageLocation location(script, pending_error_location_.beg_pos, |
pending_error_location_.end_pos); |
- Factory* factory = isolate()->factory(); |
+ Factory* factory = isolate->factory(); |
bool has_arg = |
pending_error_arg_ != NULL || pending_error_char_arg_ != NULL; |
Handle<FixedArray> elements = factory->NewFixedArray(has_arg ? 1 : 0); |
@@ -4281,7 +4298,7 @@ void Parser::ThrowPendingError() { |
.ToHandleChecked(); |
elements->set(0, *arg_string); |
} |
- isolate()->debug()->OnCompileError(script()); |
+ isolate->debug()->OnCompileError(script); |
Handle<JSArray> array = factory->NewJSArrayWithElements(elements); |
Handle<Object> error; |
@@ -4294,35 +4311,34 @@ void Parser::ThrowPendingError() { |
Handle<JSObject> jserror = Handle<JSObject>::cast(error); |
Handle<Name> key_start_pos = factory->error_start_pos_symbol(); |
- JSObject::SetProperty( |
- jserror, key_start_pos, |
- handle(Smi::FromInt(location.start_pos()), isolate()), |
- SLOPPY).Check(); |
+ JSObject::SetProperty(jserror, key_start_pos, |
+ handle(Smi::FromInt(location.start_pos()), isolate), |
+ SLOPPY).Check(); |
Handle<Name> key_end_pos = factory->error_end_pos_symbol(); |
JSObject::SetProperty(jserror, key_end_pos, |
- handle(Smi::FromInt(location.end_pos()), isolate()), |
+ handle(Smi::FromInt(location.end_pos()), isolate), |
SLOPPY).Check(); |
Handle<Name> key_script = factory->error_script_symbol(); |
- JSObject::SetProperty(jserror, key_script, script(), SLOPPY).Check(); |
+ JSObject::SetProperty(jserror, key_script, script, SLOPPY).Check(); |
- isolate()->Throw(*error, &location); |
+ isolate->Throw(*error, &location); |
} |
} |
} |
-void Parser::Internalize() { |
+void Parser::Internalize(CompilationInfo* info) { |
// Internalize strings. |
- ast_value_factory()->Internalize(isolate()); |
+ ast_value_factory()->Internalize(info->isolate()); |
// Error processing. |
- if (info()->function() == NULL) { |
+ if (info->function() == NULL) { |
if (stack_overflow()) { |
- isolate()->StackOverflow(); |
+ info->isolate()->StackOverflow(); |
} else { |
- ThrowPendingError(); |
+ ThrowPendingError(info->isolate(), info->script()); |
} |
} |
@@ -4330,10 +4346,10 @@ void Parser::Internalize() { |
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; |
++feature) { |
for (int i = 0; i < use_counts_[feature]; ++i) { |
- isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature)); |
+ info->isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature)); |
} |
} |
- isolate()->counters()->total_preparse_skipped()->Increment( |
+ info->isolate()->counters()->total_preparse_skipped()->Increment( |
total_preparse_skipped_); |
} |
@@ -5251,12 +5267,12 @@ bool RegExpParser::ParseRegExp(Isolate* isolate, Zone* zone, |
} |
-bool Parser::Parse(CompilationInfo* info, bool allow_lazy) { |
+bool Parser::ParseStatic(CompilationInfo* info, bool allow_lazy) { |
Parser parser(info, info->isolate()->stack_guard()->real_climit(), |
info->isolate()->heap()->HashSeed(), |
info->isolate()->unicode_cache()); |
parser.set_allow_lazy(allow_lazy); |
- if (parser.Parse()) { |
+ if (parser.Parse(info)) { |
info->SetLanguageMode(info->function()->language_mode()); |
return true; |
} |
@@ -5264,49 +5280,54 @@ bool Parser::Parse(CompilationInfo* info, bool allow_lazy) { |
} |
-bool Parser::Parse() { |
- DCHECK(info()->function() == NULL); |
+bool Parser::Parse(CompilationInfo* info) { |
+ DCHECK(info->function() == NULL); |
FunctionLiteral* result = NULL; |
- pre_parse_timer_ = isolate()->counters()->pre_parse(); |
+ // Ok to use Isolate here; this function is only called in the main thread. |
+ DCHECK(parsing_on_main_thread_); |
+ Isolate* isolate = info->isolate(); |
+ pre_parse_timer_ = isolate->counters()->pre_parse(); |
if (FLAG_trace_parse || allow_natives() || extension_ != NULL) { |
// If intrinsics are allowed, the Parser cannot operate independent of the |
// V8 heap because of Runtime. Tell the string table to internalize strings |
// and values right after they're created. |
- ast_value_factory()->Internalize(isolate()); |
+ ast_value_factory()->Internalize(isolate); |
} |
- if (info()->is_lazy()) { |
- DCHECK(!info()->is_eval()); |
- if (info()->shared_info()->is_function()) { |
- result = ParseLazy(); |
+ if (info->is_lazy()) { |
+ DCHECK(!info->is_eval()); |
+ if (info->shared_info()->is_function()) { |
+ result = ParseLazy(info); |
} else { |
- result = ParseProgram(); |
+ result = ParseProgram(info); |
} |
} else { |
- SetCachedData(); |
- result = ParseProgram(); |
+ SetCachedData(info); |
+ result = ParseProgram(info); |
} |
- info()->SetFunction(result); |
+ info->SetFunction(result); |
- Internalize(); |
+ Internalize(info); |
DCHECK(ast_value_factory()->IsInternalized()); |
return (result != NULL); |
} |
-void Parser::ParseOnBackground() { |
- DCHECK(info()->function() == NULL); |
+void Parser::ParseOnBackground(CompilationInfo* info) { |
+ parsing_on_main_thread_ = false; |
+ |
+ DCHECK(info->function() == NULL); |
FunctionLiteral* result = NULL; |
fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); |
CompleteParserRecorder recorder; |
if (produce_cached_parse_data()) log_ = &recorder; |
- DCHECK(info()->source_stream() != NULL); |
- ExternalStreamingStream stream(info()->source_stream(), |
- info()->source_stream_encoding()); |
+ DCHECK(info->source_stream() != NULL); |
+ ExternalStreamingStream stream(info->source_stream(), |
+ info->source_stream_encoding()); |
scanner_.Initialize(&stream); |
- DCHECK(info()->context().is_null() || info()->context()->IsNativeContext()); |
+ DCHECK(info->context().is_null() || info->context()->IsNativeContext()); |
// When streaming, we don't know the length of the source until we have parsed |
// it. The raw data can be UTF-8, so we wouldn't know the source length until |
@@ -5316,20 +5337,20 @@ void Parser::ParseOnBackground() { |
// scopes) and set their end position after we know the script length. |
Scope* top_scope = NULL; |
Scope* eval_scope = NULL; |
- result = DoParseProgram(info(), &top_scope, &eval_scope); |
+ result = DoParseProgram(info, &top_scope, &eval_scope); |
top_scope->set_end_position(scanner()->location().end_pos); |
if (eval_scope != NULL) { |
eval_scope->set_end_position(scanner()->location().end_pos); |
} |
- info()->SetFunction(result); |
+ info->SetFunction(result); |
// We cannot internalize on a background thread; a foreground task will take |
// care of calling Parser::Internalize just before compilation. |
if (produce_cached_parse_data()) { |
- if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); |
+ if (result != NULL) *info->cached_data() = recorder.GetScriptData(); |
log_ = NULL; |
} |
} |