Commit f22ef120 authored by jochen's avatar jochen Committed by Commit bot

Add parser finalization step

BUG=v8:5215
R=vogelheim@chromium.org,marja@chromium.org

Review-Url: https://codereview.chromium.org/2193813002
Cr-Commit-Position: refs/heads/master@{#38203}
parent 1acc2f53
...@@ -33,6 +33,8 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, ...@@ -33,6 +33,8 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
CompilerDispatcherJob::~CompilerDispatcherJob() { CompilerDispatcherJob::~CompilerDispatcherJob() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status_ == CompileJobStatus::kInitial ||
status_ == CompileJobStatus::kDone);
i::GlobalHandles::Destroy(Handle<Object>::cast(function_).location()); i::GlobalHandles::Destroy(Handle<Object>::cast(function_).location());
} }
...@@ -46,19 +48,20 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() { ...@@ -46,19 +48,20 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() {
Handle<Script> script(Script::cast(shared->script()), isolate_); Handle<Script> script(Script::cast(shared->script()), isolate_);
Handle<String> source(String::cast(script->source()), isolate_); Handle<String> source(String::cast(script->source()), isolate_);
if (source->IsExternalTwoByteString()) { if (source->IsExternalTwoByteString()) {
can_parse_on_background_thread_ = true;
character_stream_.reset(new ExternalTwoByteStringUtf16CharacterStream( character_stream_.reset(new ExternalTwoByteStringUtf16CharacterStream(
Handle<ExternalTwoByteString>::cast(source), shared->start_position(), Handle<ExternalTwoByteString>::cast(source), shared->start_position(),
shared->end_position())); shared->end_position()));
} else if (source->IsExternalOneByteString()) { } else if (source->IsExternalOneByteString()) {
can_parse_on_background_thread_ = true;
character_stream_.reset(new ExternalOneByteStringUtf16CharacterStream( character_stream_.reset(new ExternalOneByteStringUtf16CharacterStream(
Handle<ExternalOneByteString>::cast(source), shared->start_position(), Handle<ExternalOneByteString>::cast(source), shared->start_position(),
shared->end_position())); shared->end_position()));
} else { } else {
can_parse_on_background_thread_ = false; source = String::Flatten(source);
// Have to globalize the reference here, so it survives between function
// calls.
source_ = Handle<String>::cast(isolate_->global_handles()->Create(*source));
character_stream_.reset(new GenericStringUtf16CharacterStream( character_stream_.reset(new GenericStringUtf16CharacterStream(
source, shared->start_position(), shared->end_position())); source_, shared->start_position(), shared->end_position()));
} }
parse_info_.reset(new ParseInfo(zone_.get())); parse_info_.reset(new ParseInfo(zone_.get()));
parse_info_->set_isolate(isolate_); parse_info_->set_isolate(isolate_);
...@@ -76,7 +79,12 @@ void CompilerDispatcherJob::Parse() { ...@@ -76,7 +79,12 @@ void CompilerDispatcherJob::Parse() {
DisallowHeapAllocation no_allocation; DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles; DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref; std::unique_ptr<DisallowHandleDereference> no_deref;
// If we can't parse on a background thread, we need to be able to deref the
// source string.
if (can_parse_on_background_thread_) {
no_deref.reset(new DisallowHandleDereference());
}
// Nullify the Isolate temporarily so that the parser doesn't accidentally // Nullify the Isolate temporarily so that the parser doesn't accidentally
// use it. // use it.
...@@ -93,5 +101,75 @@ void CompilerDispatcherJob::Parse() { ...@@ -93,5 +101,75 @@ void CompilerDispatcherJob::Parse() {
status_ = CompileJobStatus::kParsed; status_ = CompileJobStatus::kParsed;
} }
void CompilerDispatcherJob::FinalizeParsingOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kParsed);
if (!source_.is_null()) {
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location());
source_ = Handle<String>::null();
}
if (parse_info_->literal() == nullptr) {
status_ = CompileJobStatus::kFailed;
return;
}
InternalizeParsingResult();
status_ = CompileJobStatus::kReadyToCompile;
}
void CompilerDispatcherJob::ReportErrorsOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kFailed);
// Internalizing the parsing result will throw the error.
InternalizeParsingResult();
status_ = CompileJobStatus::kDone;
}
void CompilerDispatcherJob::ResetOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
parser_.reset();
unicode_cache_.reset();
character_stream_.reset();
parse_info_.reset();
zone_.reset();
if (!source_.is_null()) {
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location());
source_ = Handle<String>::null();
}
status_ = CompileJobStatus::kInitial;
}
void CompilerDispatcherJob::InternalizeParsingResult() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kParsed ||
status() == CompileJobStatus::kFailed);
HandleScope scope(isolate_);
Handle<SharedFunctionInfo> shared(function_->shared(), isolate_);
Handle<Script> script(Script::cast(shared->script()), isolate_);
parse_info_->set_script(script);
parse_info_->set_context(handle(function_->context(), isolate_));
// Do the parsing tasks which need to be done on the main thread. This will
// also handle parse errors.
parser_->Internalize(isolate_, script, parse_info_->literal() == nullptr);
parser_->HandleSourceURLComments(isolate_, script);
parse_info_->set_character_stream(nullptr);
parse_info_->set_unicode_cache(nullptr);
parser_.reset();
unicode_cache_.reset();
character_stream_.reset();
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -18,6 +18,7 @@ class Isolate; ...@@ -18,6 +18,7 @@ class Isolate;
class JSFunction; class JSFunction;
class ParseInfo; class ParseInfo;
class Parser; class Parser;
class String;
class UnicodeCache; class UnicodeCache;
class Utf16CharacterStream; class Utf16CharacterStream;
class Zone; class Zone;
...@@ -26,6 +27,9 @@ enum class CompileJobStatus { ...@@ -26,6 +27,9 @@ enum class CompileJobStatus {
kInitial, kInitial,
kReadyToParse, kReadyToParse,
kParsed, kParsed,
kReadyToCompile,
kFailed,
kDone,
}; };
class CompilerDispatcherJob { class CompilerDispatcherJob {
...@@ -45,10 +49,22 @@ class CompilerDispatcherJob { ...@@ -45,10 +49,22 @@ class CompilerDispatcherJob {
// Transition from kReadyToParse to kParsed. // Transition from kReadyToParse to kParsed.
void Parse(); void Parse();
// Transition from kParsed to kReadyToCompile (or kFailed).
void FinalizeParsingOnMainThread();
// Transition from kFailed to kDone.
void ReportErrorsOnMainThread();
// Transition from any state to kInitial and free all resources.
void ResetOnMainThread();
private: private:
void InternalizeParsingResult();
CompileJobStatus status_ = CompileJobStatus::kInitial; CompileJobStatus status_ = CompileJobStatus::kInitial;
Isolate* isolate_; Isolate* isolate_;
Handle<JSFunction> function_; // Global handle. Handle<JSFunction> function_; // Global handle.
Handle<String> source_; // Global handle.
size_t max_stack_size_; size_t max_stack_size_;
// Members required for parsing. // Members required for parsing.
......
...@@ -49,6 +49,7 @@ Handle<JSFunction> CreateFunction( ...@@ -49,6 +49,7 @@ Handle<JSFunction> CreateFunction(
isolate->factory()->NewStringFromStaticChars("f"), MaybeHandle<Code>(), isolate->factory()->NewStringFromStaticChars("f"), MaybeHandle<Code>(),
false); false);
SharedFunctionInfo::SetScript(shared, script); SharedFunctionInfo::SetScript(shared, script);
shared->set_end_position(source->length() - 1);
Handle<JSFunction> function = Handle<JSFunction> function =
isolate->factory()->NewFunctionFromSharedFunctionInfo( isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared, handle(isolate->context(), isolate)); shared, handle(isolate->context(), isolate));
...@@ -58,36 +59,53 @@ Handle<JSFunction> CreateFunction( ...@@ -58,36 +59,53 @@ Handle<JSFunction> CreateFunction(
} // namespace } // namespace
TEST_F(CompilerDispatcherJobTest, Construct) { TEST_F(CompilerDispatcherJobTest, Construct) {
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate());
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate, CreateFunction(i_isolate, nullptr), FLAG_stack_size)); i_isolate(), CreateFunction(i_isolate(), nullptr), FLAG_stack_size));
} }
TEST_F(CompilerDispatcherJobTest, CanParseOnBackgroundThread) { TEST_F(CompilerDispatcherJobTest, CanParseOnBackgroundThread) {
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate());
{ {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate, CreateFunction(i_isolate, nullptr), FLAG_stack_size)); i_isolate(), CreateFunction(i_isolate(), nullptr), FLAG_stack_size));
ASSERT_FALSE(job->can_parse_on_background_thread()); ASSERT_FALSE(job->can_parse_on_background_thread());
} }
{ {
ScriptResource script("script", strlen("script")); ScriptResource script("script", strlen("script"));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate, CreateFunction(i_isolate, &script), FLAG_stack_size)); i_isolate(), CreateFunction(i_isolate(), &script), FLAG_stack_size));
ASSERT_TRUE(job->can_parse_on_background_thread()); ASSERT_TRUE(job->can_parse_on_background_thread());
} }
} }
TEST_F(CompilerDispatcherJobTest, StateTransitions) { TEST_F(CompilerDispatcherJobTest, StateTransitions) {
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate());
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate, CreateFunction(i_isolate, nullptr), FLAG_stack_size)); i_isolate(), CreateFunction(i_isolate(), nullptr), FLAG_stack_size));
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial); ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
job->PrepareToParseOnMainThread(); job->PrepareToParseOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToParse); ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToParse);
job->Parse(); job->Parse();
ASSERT_TRUE(job->status() == CompileJobStatus::kParsed); ASSERT_TRUE(job->status() == CompileJobStatus::kParsed);
job->FinalizeParsingOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile);
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
TEST_F(CompilerDispatcherJobTest, SyntaxError) {
ScriptResource script("^^^", strlen("^^^"));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), &script), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
job->FinalizeParsingOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kFailed);
ASSERT_FALSE(i_isolate()->has_pending_exception());
job->ReportErrorsOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
ASSERT_TRUE(i_isolate()->has_pending_exception());
} }
} // namespace internal } // namespace internal
......
...@@ -43,6 +43,10 @@ class TestWithContext : public virtual TestWithIsolate { ...@@ -43,6 +43,10 @@ class TestWithContext : public virtual TestWithIsolate {
const Local<Context>& context() const { return context_; } const Local<Context>& context() const { return context_; }
v8::internal::Isolate* i_isolate() const {
return reinterpret_cast<v8::internal::Isolate*>(isolate());
}
private: private:
Local<Context> context_; Local<Context> context_;
Context::Scope context_scope_; Context::Scope context_scope_;
......
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