[compiler-dispatcher] Move stepping logic to job

Instead of having the "next step" state machine logic in the compiler
dispatcher, move it to the compiler dispatcher job. This is a
prerequisite to having more generic jobs with slightly different state
sets, such as an optimizing compile job.

Bug: v8:6537
Change-Id: Ib7319222f26dbc0e2afc95573b06d813825afde3
Reviewed-on: https://chromium-review.googlesource.com/554751
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46396}
This commit is contained in:
Leszek Swirski 2017-07-04 09:55:45 +01:00 committed by Commit Bot
parent aa5852a294
commit ff3b948c6b
5 changed files with 312 additions and 240 deletions

View File

@ -179,6 +179,50 @@ bool CompilerDispatcherJob::IsAssociatedWith(
return *shared_ == *shared;
}
void CompilerDispatcherJob::StepNextOnMainThread() {
switch (status()) {
case CompileJobStatus::kInitial:
return PrepareToParseOnMainThread();
case CompileJobStatus::kReadyToParse:
return Parse();
case CompileJobStatus::kParsed:
return FinalizeParsingOnMainThread();
case CompileJobStatus::kReadyToAnalyze:
return AnalyzeOnMainThread();
case CompileJobStatus::kAnalyzed:
return PrepareToCompileOnMainThread();
case CompileJobStatus::kReadyToCompile:
return Compile();
case CompileJobStatus::kCompiled:
return FinalizeCompilingOnMainThread();
case CompileJobStatus::kFailed:
case CompileJobStatus::kDone:
return;
}
UNREACHABLE();
}
void CompilerDispatcherJob::StepNextOnBackgroundThread() {
DCHECK(CanStepNextOnAnyThread());
switch (status()) {
case CompileJobStatus::kReadyToParse:
return Parse();
case CompileJobStatus::kReadyToCompile:
return Compile();
default:
UNREACHABLE();
}
}
void CompilerDispatcherJob::PrepareToParseOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kInitial);
@ -315,7 +359,7 @@ void CompilerDispatcherJob::Parse() {
}
}
bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
void CompilerDispatcherJob::FinalizeParsingOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kParsed);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing);
@ -367,11 +411,9 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
character_stream_.reset();
}
parse_info_->set_deferred_handles(scope.Detach());
return status_ != CompileJobStatus::kFailed;
}
bool CompilerDispatcherJob::AnalyzeOnMainThread() {
void CompilerDispatcherJob::AnalyzeOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kReadyToAnalyze);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kAnalyze);
@ -393,11 +435,9 @@ bool CompilerDispatcherJob::AnalyzeOnMainThread() {
}
}
compile_info_->set_deferred_handles(scope.Detach());
return status_ != CompileJobStatus::kFailed;
}
bool CompilerDispatcherJob::PrepareToCompileOnMainThread() {
void CompilerDispatcherJob::PrepareToCompileOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kAnalyzed);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile);
@ -407,12 +447,11 @@ bool CompilerDispatcherJob::PrepareToCompileOnMainThread() {
if (!compile_job_.get()) {
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
status_ = CompileJobStatus::kFailed;
return false;
return;
}
CHECK(compile_job_->can_execute_on_background_thread());
status_ = CompileJobStatus::kReadyToCompile;
return true;
}
void CompilerDispatcherJob::Compile() {
@ -437,7 +476,7 @@ void CompilerDispatcherJob::Compile() {
status_ = CompileJobStatus::kCompiled;
}
bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
void CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kCompiled);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeCompiling);
@ -452,7 +491,7 @@ bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
!Compiler::FinalizeCompilationJob(compile_job_.release())) {
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
status_ = CompileJobStatus::kFailed;
return false;
return;
}
}
@ -462,7 +501,6 @@ bool CompilerDispatcherJob::FinalizeCompilingOnMainThread() {
parse_info_.reset();
status_ = CompileJobStatus::kDone;
return true;
}
void CompilerDispatcherJob::ResetOnMainThread() {

View File

@ -76,8 +76,6 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
size_t max_stack_size);
~CompilerDispatcherJob();
CompileJobStatus status() const { return status_; }
bool has_context() const { return !context_.is_null(); }
Context* context() { return *context_; }
@ -87,31 +85,26 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
// function.
bool IsAssociatedWith(Handle<SharedFunctionInfo> shared) const;
// Transition from kInitial to kReadyToParse.
void PrepareToParseOnMainThread();
bool IsFinished() {
return status() == CompileJobStatus::kDone ||
status() == CompileJobStatus::kFailed;
}
// Transition from kReadyToParse to kParsed (or kDone if there is
// finish_callback).
void Parse();
bool IsFailed() { return status() == CompileJobStatus::kFailed; }
// Transition from kParsed to kReadyToAnalyze (or kFailed). Returns false
// when transitioning to kFailed. In that case, an exception is pending.
bool FinalizeParsingOnMainThread();
// Return true if the next step can be run on any thread, that is when both
// StepNextOnMainThread and StepNextOnBackgroundThread could be used for the
// next step.
bool CanStepNextOnAnyThread() {
return status() == CompileJobStatus::kReadyToParse ||
status() == CompileJobStatus::kReadyToCompile;
}
// Transition from kReadyToAnalyze to kAnalyzed (or kFailed). Returns
// false when transitioning to kFailed. In that case, an exception is pending.
bool AnalyzeOnMainThread();
// Step the job forward by one state on the main thread.
void StepNextOnMainThread();
// Transition from kAnalyzed to kReadyToCompile (or kFailed). Returns
// false when transitioning to kFailed. In that case, an exception is pending.
bool PrepareToCompileOnMainThread();
// Transition from kReadyToCompile to kCompiled.
void Compile();
// Transition from kCompiled to kDone (or kFailed). Returns false when
// transitioning to kFailed. In that case, an exception is pending.
bool FinalizeCompilingOnMainThread();
// Step the job forward by one state on a background thread.
void StepNextOnBackgroundThread();
// Transition from any state to kInitial and free all resources.
void ResetOnMainThread();
@ -124,7 +117,10 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
void ShortPrint();
private:
FRIEND_TEST(CompilerDispatcherJobTest, ScopeChain);
friend class CompilerDispatcherTest;
friend class CompilerDispatcherJobTest;
CompileJobStatus status() const { return status_; }
CompileJobStatus status_;
Isolate* isolate_;
@ -152,6 +148,28 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
bool trace_compiler_dispatcher_jobs_;
// Transition from kInitial to kReadyToParse.
void PrepareToParseOnMainThread();
// Transition from kReadyToParse to kParsed (or kDone if there is
// finish_callback).
void Parse();
// Transition from kParsed to kReadyToAnalyze (or kFailed).
void FinalizeParsingOnMainThread();
// Transition from kReadyToAnalyze to kAnalyzed (or kFailed).
void AnalyzeOnMainThread();
// Transition from kAnalyzed to kReadyToCompile (or kFailed).
void PrepareToCompileOnMainThread();
// Transition from kReadyToCompile to kCompiled.
void Compile();
// Transition from kCompiled to kDone (or kFailed).
void FinalizeCompilingOnMainThread();
DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherJob);
};

View File

@ -21,16 +21,6 @@ namespace {
enum class ExceptionHandling { kSwallow, kThrow };
bool IsFinished(CompilerDispatcherJob* job) {
return job->status() == CompileJobStatus::kDone ||
job->status() == CompileJobStatus::kFailed;
}
bool CanRunOnAnyThread(CompilerDispatcherJob* job) {
return job->status() == CompileJobStatus::kReadyToParse ||
job->status() == CompileJobStatus::kReadyToCompile;
}
bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job,
ExceptionHandling exception_handling) {
DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
@ -42,69 +32,23 @@ bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job,
if (job->has_context()) {
isolate->set_context(job->context());
} else {
DCHECK(CanRunOnAnyThread(job));
DCHECK(job->CanStepNextOnAnyThread());
}
switch (job->status()) {
case CompileJobStatus::kInitial:
job->PrepareToParseOnMainThread();
break;
job->StepNextOnMainThread();
case CompileJobStatus::kReadyToParse:
job->Parse();
break;
case CompileJobStatus::kParsed:
job->FinalizeParsingOnMainThread();
break;
case CompileJobStatus::kReadyToAnalyze:
job->AnalyzeOnMainThread();
break;
case CompileJobStatus::kAnalyzed:
job->PrepareToCompileOnMainThread();
break;
case CompileJobStatus::kReadyToCompile:
job->Compile();
break;
case CompileJobStatus::kCompiled:
job->FinalizeCompilingOnMainThread();
break;
case CompileJobStatus::kFailed:
case CompileJobStatus::kDone:
break;
}
DCHECK_EQ(job->status() == CompileJobStatus::kFailed,
isolate->has_pending_exception());
if (job->status() == CompileJobStatus::kFailed &&
exception_handling == ExceptionHandling::kSwallow) {
DCHECK_EQ(job->IsFailed(), isolate->has_pending_exception());
if (job->IsFailed() && exception_handling == ExceptionHandling::kSwallow) {
isolate->clear_pending_exception();
}
return job->status() != CompileJobStatus::kFailed;
return job->IsFailed();
}
void DoNextStepOnBackgroundThread(CompilerDispatcherJob* job) {
DCHECK(CanRunOnAnyThread(job));
DCHECK(job->CanStepNextOnAnyThread());
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompilerDispatcherBackgroundStep");
switch (job->status()) {
case CompileJobStatus::kReadyToParse:
job->Parse();
break;
case CompileJobStatus::kReadyToCompile:
job->Compile();
break;
default:
UNREACHABLE();
}
job->StepNextOnBackgroundThread();
}
// Theoretically we get 50ms of idle time max, however it's unlikely that
@ -277,7 +221,7 @@ bool CompilerDispatcher::CanEnqueue(Handle<SharedFunctionInfo> function) {
CompilerDispatcher::JobId CompilerDispatcher::Enqueue(
std::unique_ptr<CompilerDispatcherJob> job) {
DCHECK(!IsFinished(job.get()));
DCHECK(!job->IsFinished());
bool added;
JobMap::const_iterator it;
std::tie(it, added) =
@ -293,7 +237,7 @@ CompilerDispatcher::JobId CompilerDispatcher::Enqueue(
CompilerDispatcher::JobId CompilerDispatcher::EnqueueAndStep(
std::unique_ptr<CompilerDispatcherJob> job) {
DCHECK(!IsFinished(job.get()));
DCHECK(!job->IsFinished());
bool added;
JobMap::const_iterator it;
std::tie(it, added) =
@ -461,10 +405,10 @@ bool CompilerDispatcher::FinishNow(CompilerDispatcherJob* job) {
PrintF(" now\n");
}
WaitForJobIfRunningOnBackground(job);
while (!IsFinished(job)) {
while (!job->IsFinished()) {
DoNextStepOnMainThread(isolate_, job, ExceptionHandling::kThrow);
}
return job->status() != CompileJobStatus::kFailed;
return !job->IsFailed();
}
bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
@ -489,7 +433,7 @@ void CompilerDispatcher::FinishAllNow() {
pending_background_jobs_.erase(job);
}
if (!is_running_in_background) {
while (!IsFinished(job)) {
while (!job->IsFinished()) {
DoNextStepOnMainThread(isolate_, job, ExceptionHandling::kThrow);
}
it = RemoveIfFinished(it);
@ -638,7 +582,7 @@ void CompilerDispatcher::ScheduleAbortTask() {
void CompilerDispatcher::ConsiderJobForBackgroundProcessing(
CompilerDispatcherJob* job) {
if (!CanRunOnAnyThread(job)) return;
if (!job->CanStepNextOnAnyThread()) return;
{
base::LockGuard<base::Mutex> lock(&mutex_);
pending_background_jobs_.insert(job);
@ -773,7 +717,7 @@ void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
ConsiderJobForBackgroundProcessing(job->second.get());
}
++job;
} else if (IsFinished(job->second.get())) {
} else if (job->second->IsFinished()) {
DCHECK(it == pending_background_jobs_.end());
lock.reset();
job = RemoveJob(job);
@ -794,12 +738,12 @@ void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::RemoveIfFinished(
JobMap::const_iterator job) {
if (!IsFinished(job->second.get())) {
if (!job->second->IsFinished()) {
return job;
}
if (trace_compiler_dispatcher_) {
bool result = job->second->status() != CompileJobStatus::kFailed;
bool result = !job->second->IsFailed();
PrintF("CompilerDispatcher: finished working on ");
job->second->ShortPrint();
PrintF(": %s\n", result ? "success" : "failure");

View File

@ -43,6 +43,22 @@ class CompilerDispatcherJobTest : public TestWithContext {
save_flags_ = nullptr;
}
static CompileJobStatus GetStatus(CompilerDispatcherJob* job) {
return job->status();
}
static CompileJobStatus GetStatus(
const std::unique_ptr<CompilerDispatcherJob>& job) {
return GetStatus(job.get());
}
static Variable* LookupVariableByName(CompilerDispatcherJob* job,
const char* name) {
const AstRawString* name_raw_string =
job->parse_info_->ast_value_factory()->GetOneByteString(name);
return job->parse_info_->literal()->scope()->Lookup(name_raw_string);
}
private:
CompilerDispatcherTracer tracer_;
static SaveFlags* save_flags_;
@ -58,6 +74,8 @@ const char test_script[] = "(x) { x*x; }";
} // namespace
#define ASSERT_JOB_STATUS(STATUS, JOB) ASSERT_EQ(STATUS, GetStatus(JOB))
TEST_F(CompilerDispatcherJobTest, Construct) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), tracer(),
@ -82,23 +100,30 @@ TEST_F(CompilerDispatcherJobTest, StateTransitions) {
i_isolate(), tracer(),
test::CreateSharedFunctionInfo(i_isolate(), nullptr), FLAG_stack_size));
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
job->PrepareToParseOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToParse);
job->Parse();
ASSERT_TRUE(job->status() == CompileJobStatus::kParsed);
ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToAnalyze);
ASSERT_TRUE(job->AnalyzeOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kAnalyzed);
ASSERT_TRUE(job->PrepareToCompileOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile);
job->Compile();
ASSERT_TRUE(job->status() == CompileJobStatus::kCompiled);
ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToParse, job);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kParsed, job);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToAnalyze, job);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kAnalyzed, job);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToCompile, job);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kCompiled, job);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
}
TEST_F(CompilerDispatcherJobTest, StateTransitionsParseWithCallback) {
@ -112,11 +137,12 @@ TEST_F(CompilerDispatcherJobTest, StateTransitionsParseWithCallback) {
i_isolate()->heap()->HashSeed(), i_isolate()->allocator(),
ScriptCompiler::kNoCompileOptions, i_isolate()->ast_string_constants(),
callback.get()));
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToParse);
job->Parse();
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToParse, job);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
ASSERT_TRUE(callback->result() != nullptr);
}
@ -126,16 +152,19 @@ TEST_F(CompilerDispatcherJobTest, SyntaxError) {
i_isolate(), tracer(),
test::CreateSharedFunctionInfo(i_isolate(), &script), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
ASSERT_FALSE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kFailed);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_TRUE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kFailed, job);
ASSERT_TRUE(i_isolate()->has_pending_exception());
i_isolate()->clear_pending_exception();
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
}
TEST_F(CompilerDispatcherJobTest, ScopeChain) {
@ -148,27 +177,28 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->AnalyzeOnMainThread());
ASSERT_TRUE(job->PrepareToCompileOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToCompile, job);
const AstRawString* var_x =
job->parse_info_->ast_value_factory()->GetOneByteString("x");
Variable* var = job->parse_info_->literal()->scope()->Lookup(var_x);
Variable* var = LookupVariableByName(job.get(), "x");
ASSERT_TRUE(var);
ASSERT_TRUE(var->IsParameter());
const AstRawString* var_y =
job->parse_info_->ast_value_factory()->GetOneByteString("y");
var = job->parse_info_->literal()->scope()->Lookup(var_y);
var = LookupVariableByName(job.get(), "y");
ASSERT_TRUE(var);
ASSERT_TRUE(var->IsContextSlot());
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
}
TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
@ -186,20 +216,27 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
job->FinalizeParsingOnMainThread();
job->AnalyzeOnMainThread();
job->PrepareToCompileOnMainThread();
job->Compile();
ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
Smi* value = Smi::cast(*test::RunJS(isolate(), "f(100);"));
ASSERT_TRUE(value == Smi::FromInt(160));
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
}
TEST_F(CompilerDispatcherJobTest, CompileFailureToAnalyse) {
@ -213,16 +250,20 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToAnalyse) {
i_isolate(), tracer(),
test::CreateSharedFunctionInfo(i_isolate(), &script), 100));
job->PrepareToParseOnMainThread();
job->Parse();
job->FinalizeParsingOnMainThread();
ASSERT_FALSE(job->AnalyzeOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kFailed);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_TRUE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kFailed, job);
ASSERT_TRUE(i_isolate()->has_pending_exception());
i_isolate()->clear_pending_exception();
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
}
TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) {
@ -236,19 +277,26 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) {
i_isolate(), tracer(),
test::CreateSharedFunctionInfo(i_isolate(), &script), 50));
job->PrepareToParseOnMainThread();
job->Parse();
job->FinalizeParsingOnMainThread();
job->AnalyzeOnMainThread();
job->PrepareToCompileOnMainThread();
job->Compile();
ASSERT_FALSE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kFailed);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_TRUE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kFailed, job);
ASSERT_TRUE(i_isolate()->has_pending_exception());
i_isolate()->clear_pending_exception();
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
}
class CompileTask : public Task {
@ -258,7 +306,8 @@ class CompileTask : public Task {
~CompileTask() override {}
void Run() override {
job_->Compile();
job_->StepNextOnBackgroundThread();
ASSERT_FALSE(job_->IsFailed());
semaphore_->Signal();
}
@ -281,22 +330,29 @@ TEST_F(CompilerDispatcherJobTest, CompileOnBackgroundThread) {
i_isolate(), tracer(),
test::CreateSharedFunctionInfo(i_isolate(), &script), 100));
job->PrepareToParseOnMainThread();
job->Parse();
job->FinalizeParsingOnMainThread();
job->AnalyzeOnMainThread();
job->PrepareToCompileOnMainThread();
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
base::Semaphore semaphore(0);
CompileTask* background_task = new CompileTask(job.get(), &semaphore);
ASSERT_JOB_STATUS(CompileJobStatus::kReadyToCompile, job);
V8::GetCurrentPlatform()->CallOnBackgroundThread(background_task,
Platform::kShortRunningTask);
semaphore.Wait();
ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
}
TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
@ -315,14 +371,21 @@ TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->AnalyzeOnMainThread());
ASSERT_TRUE(job->PrepareToCompileOnMainThread());
job->Compile();
ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread();
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(CompileJobStatus::kDone, job);
Handle<JSFunction> e =
Handle<JSFunction>::cast(test::RunJS(isolate(), "f();"));
@ -330,7 +393,7 @@ TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
ASSERT_FALSE(e->shared()->HasBaselineCode());
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
ASSERT_JOB_STATUS(CompileJobStatus::kInitial, job);
}
} // namespace internal

View File

@ -76,6 +76,15 @@ class CompilerDispatcherTest : public TestWithContext {
CompilerDispatcherTestFlags::RestoreFlags();
}
static CompileJobStatus GetJobStatus(const CompilerDispatcherJob* job) {
return job->status();
}
static CompileJobStatus GetJobStatus(
const std::unique_ptr<CompilerDispatcherJob>& job) {
return GetJobStatus(job.get());
}
private:
DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherTest);
};
@ -395,8 +404,8 @@ TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) {
// The job should be scheduled for the main thread.
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kInitial);
ASSERT_EQ(CompileJobStatus::kInitial,
GetJobStatus(dispatcher.jobs_.begin()->second));
// Only grant a little idle time and have time advance beyond it in one step.
platform.RunIdleTask(2.0, 1.0);
@ -408,8 +417,8 @@ TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) {
// The job should be still scheduled for the main thread, but ready for
// parsing.
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToParse);
ASSERT_EQ(CompileJobStatus::kReadyToParse,
GetJobStatus(dispatcher.jobs_.begin()->second));
// Now grant a lot of idle time and freeze time.
platform.RunIdleTask(1000.0, 0.0);
@ -460,15 +469,15 @@ TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kInitial);
ASSERT_EQ(CompileJobStatus::kInitial,
GetJobStatus(dispatcher.jobs_.begin()->second));
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_FALSE(shared->is_compiled());
@ -479,8 +488,8 @@ TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_FALSE(platform.BackgroundTasksPending());
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kCompiled);
ASSERT_EQ(CompileJobStatus::kCompiled,
GetJobStatus(dispatcher.jobs_.begin()->second));
// Now grant a lot of idle time and freeze time.
platform.RunIdleTask(1000.0, 0.0);
@ -504,15 +513,15 @@ TEST_F(CompilerDispatcherTest, FinishNowWithBackgroundTask) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kInitial);
ASSERT_EQ(CompileJobStatus::kInitial,
GetJobStatus(dispatcher.jobs_.begin()->second));
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_FALSE(shared->is_compiled());
@ -601,15 +610,15 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllPendingBackgroundTask) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kInitial);
ASSERT_EQ(CompileJobStatus::kInitial,
GetJobStatus(dispatcher.jobs_.begin()->second));
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_FALSE(shared->is_compiled());
@ -649,15 +658,15 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllRunningBackgroundTask) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kInitial);
ASSERT_EQ(CompileJobStatus::kInitial,
GetJobStatus(dispatcher.jobs_.begin()->second));
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(dispatcher.IsEnqueued(shared1));
ASSERT_FALSE(shared1->is_compiled());
@ -726,15 +735,15 @@ TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_EQ(dispatcher.jobs_.size(), 1u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kInitial);
ASSERT_EQ(CompileJobStatus::kInitial,
GetJobStatus(dispatcher.jobs_.begin()->second));
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_FALSE(shared->is_compiled());
@ -905,8 +914,8 @@ TEST_F(CompilerDispatcherTest, EnqueueWithoutSFI) {
1, false, false, false, 0, callback.get(),
nullptr));
ASSERT_TRUE(!dispatcher.jobs_.empty());
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToParse);
ASSERT_EQ(CompileJobStatus::kReadyToParse,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(dispatcher.shared_to_job_id_.empty());
ASSERT_TRUE(callback->result() == nullptr);
@ -929,8 +938,8 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStep) {
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToParse);
ASSERT_EQ(CompileJobStatus::kReadyToParse,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(platform.IdleTaskPending());
platform.ClearIdleTask();
@ -957,8 +966,8 @@ TEST_F(CompilerDispatcherTest, EnqueueParsed) {
parse_info.zone_shared(), handles, handles));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kAnalyzed);
ASSERT_EQ(CompileJobStatus::kAnalyzed,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(platform.IdleTaskPending());
platform.ClearIdleTask();
@ -985,8 +994,8 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) {
handles));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_TRUE(platform.BackgroundTasksPending());
@ -1175,8 +1184,8 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepTwice) {
handles));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
// EnqueueAndStep of the same function again (either already parsed or for
// compile and parse) shouldn't step the job.
@ -1184,11 +1193,11 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepTwice) {
parse_info.zone_shared(), handles,
handles));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_TRUE(platform.BackgroundTasksPending());
@ -1215,20 +1224,20 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_EQ(dispatcher.jobs_.size(), 2u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kInitial);
ASSERT_TRUE((++dispatcher.jobs_.begin())->second->status() ==
CompileJobStatus::kInitial);
ASSERT_EQ(CompileJobStatus::kInitial,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_EQ(CompileJobStatus::kInitial,
GetJobStatus((++dispatcher.jobs_.begin())->second));
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_EQ(dispatcher.jobs_.size(), 2u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_TRUE((++dispatcher.jobs_.begin())->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_EQ(CompileJobStatus::kReadyToCompile,
GetJobStatus((++dispatcher.jobs_.begin())->second));
ASSERT_TRUE(dispatcher.IsEnqueued(shared1));
ASSERT_TRUE(dispatcher.IsEnqueued(shared2));
@ -1242,10 +1251,10 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_FALSE(platform.BackgroundTasksPending());
ASSERT_EQ(dispatcher.jobs_.size(), 2u);
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kCompiled);
ASSERT_TRUE((++dispatcher.jobs_.begin())->second->status() ==
CompileJobStatus::kCompiled);
ASSERT_EQ(CompileJobStatus::kCompiled,
GetJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_EQ(CompileJobStatus::kCompiled,
GetJobStatus((++dispatcher.jobs_.begin())->second));
// Now grant a lot of idle time and freeze time.
platform.RunIdleTask(1000.0, 0.0);