Commit 6d42c450 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[complier] Enable parallel eager inner function compilation with compiler dispatcher.

Enable enqueueing of eager inner function compilation onto the compiler
dispatcher. This enables these tasks to be performed in parallel to
compilation of the outer functio (only for Ignition functions).
We currently synchronize to ensure all inner function compilations
 are complete before executing the outer function - future work will
allow outer function execution to happenin parallel to inner function
compilation.

BUG=v8:5203,v8:5215

Review-Url: https://codereview.chromium.org/2611313002
Cr-Commit-Position: refs/heads/master@{#42667}
parent 76e31da4
...@@ -66,7 +66,8 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, ...@@ -66,7 +66,8 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
CompilerDispatcherTracer* tracer, CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared, Handle<SharedFunctionInfo> shared,
size_t max_stack_size) size_t max_stack_size)
: isolate_(isolate), : status_(CompileJobStatus::kInitial),
isolate_(isolate),
tracer_(tracer), tracer_(tracer),
shared_(Handle<SharedFunctionInfo>::cast( shared_(Handle<SharedFunctionInfo>::cast(
isolate_->global_handles()->Create(*shared))), isolate_->global_handles()->Create(*shared))),
...@@ -79,7 +80,35 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, ...@@ -79,7 +80,35 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
if (trace_compiler_dispatcher_jobs_) { if (trace_compiler_dispatcher_jobs_) {
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this)); PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
shared_->ShortPrint(); shared_->ShortPrint();
PrintF("\n"); PrintF(" in initial state.\n");
}
}
CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared,
FunctionLiteral* literal,
size_t max_stack_size)
: status_(CompileJobStatus::kAnalyzed),
isolate_(isolate),
tracer_(tracer),
shared_(Handle<SharedFunctionInfo>::cast(
isolate_->global_handles()->Create(*shared))),
max_stack_size_(max_stack_size),
zone_(new Zone(isolate->allocator(), ZONE_NAME)),
parse_info_(new ParseInfo(
zone_.get(), Handle<Script>(Script::cast(shared->script())))),
compile_info_(
new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null())),
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
parse_info_->set_literal(literal);
parse_info_->set_shared_info(shared);
parse_info_->set_function_literal_id(shared->function_literal_id());
parse_info_->set_language_mode(literal->scope()->language_mode());
if (trace_compiler_dispatcher_jobs_) {
PrintF("CompilerDispatcherJob[%p] created for ", static_cast<void*>(this));
shared_->ShortPrint();
PrintF(" in Analyzed state.\n");
} }
} }
...@@ -252,7 +281,7 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { ...@@ -252,7 +281,7 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
if (parse_info_->literal() == nullptr) { if (parse_info_->literal() == nullptr) {
status_ = CompileJobStatus::kFailed; status_ = CompileJobStatus::kFailed;
} else { } else {
status_ = CompileJobStatus::kReadyToAnalyse; status_ = CompileJobStatus::kReadyToAnalyze;
} }
DeferredHandleScope scope(isolate_); DeferredHandleScope scope(isolate_);
...@@ -283,25 +312,38 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { ...@@ -283,25 +312,38 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
return status_ != CompileJobStatus::kFailed; return status_ != CompileJobStatus::kFailed;
} }
bool CompilerDispatcherJob::PrepareToCompileOnMainThread() { bool CompilerDispatcherJob::AnalyzeOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id())); DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kReadyToAnalyse); DCHECK(status() == CompileJobStatus::kReadyToAnalyze);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile); COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kAnalyze);
if (trace_compiler_dispatcher_jobs_) { if (trace_compiler_dispatcher_jobs_) {
PrintF("CompilerDispatcherJob[%p]: Preparing to compile\n", PrintF("CompilerDispatcherJob[%p]: Analyzing\n", static_cast<void*>(this));
static_cast<void*>(this));
} }
compile_info_.reset( compile_info_.reset(
new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null())); new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null()));
DeferredHandleScope scope(isolate_); DeferredHandleScope scope(isolate_);
if (Compiler::Analyze(parse_info_.get())) { {
compile_job_.reset( if (Compiler::Analyze(parse_info_.get())) {
Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get())); status_ = CompileJobStatus::kAnalyzed;
} else {
status_ = CompileJobStatus::kFailed;
if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
}
} }
compile_info_->set_deferred_handles(scope.Detach()); compile_info_->set_deferred_handles(scope.Detach());
return status_ != CompileJobStatus::kFailed;
}
bool CompilerDispatcherJob::PrepareToCompileOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kAnalyzed);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile);
compile_job_.reset(
Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get()));
if (!compile_job_.get()) { if (!compile_job_.get()) {
if (!isolate_->has_pending_exception()) isolate_->StackOverflow(); if (!isolate_->has_pending_exception()) isolate_->StackOverflow();
status_ = CompileJobStatus::kFailed; status_ = CompileJobStatus::kFailed;
...@@ -401,7 +443,10 @@ double CompilerDispatcherJob::EstimateRuntimeOfNextStepInMs() const { ...@@ -401,7 +443,10 @@ double CompilerDispatcherJob::EstimateRuntimeOfNextStepInMs() const {
case CompileJobStatus::kParsed: case CompileJobStatus::kParsed:
return tracer_->EstimateFinalizeParsingInMs(); return tracer_->EstimateFinalizeParsingInMs();
case CompileJobStatus::kReadyToAnalyse: case CompileJobStatus::kReadyToAnalyze:
return tracer_->EstimateAnalyzeInMs();
case CompileJobStatus::kAnalyzed:
return tracer_->EstimatePrepareToCompileInMs(); return tracer_->EstimatePrepareToCompileInMs();
case CompileJobStatus::kReadyToCompile: case CompileJobStatus::kReadyToCompile:
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class AstValueFactory;
class CompilerDispatcherTracer; class CompilerDispatcherTracer;
class CompilationInfo; class CompilationInfo;
class CompilationJob; class CompilationJob;
class FunctionLiteral;
class Isolate; class Isolate;
class ParseInfo; class ParseInfo;
class Parser; class Parser;
...@@ -32,7 +34,8 @@ enum class CompileJobStatus { ...@@ -32,7 +34,8 @@ enum class CompileJobStatus {
kInitial, kInitial,
kReadyToParse, kReadyToParse,
kParsed, kParsed,
kReadyToAnalyse, kReadyToAnalyze,
kAnalyzed,
kReadyToCompile, kReadyToCompile,
kCompiled, kCompiled,
kFailed, kFailed,
...@@ -41,9 +44,14 @@ enum class CompileJobStatus { ...@@ -41,9 +44,14 @@ enum class CompileJobStatus {
class V8_EXPORT_PRIVATE CompilerDispatcherJob { class V8_EXPORT_PRIVATE CompilerDispatcherJob {
public: public:
// Creates a CompilerDispatcherJob in the initial state.
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer, CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared, Handle<SharedFunctionInfo> shared,
size_t max_stack_size); size_t max_stack_size);
// Creates a CompilerDispatcherJob in the analyzed state.
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared,
FunctionLiteral* literal, size_t max_stack_size);
~CompilerDispatcherJob(); ~CompilerDispatcherJob();
CompileJobStatus status() const { return status_; } CompileJobStatus status() const { return status_; }
...@@ -58,11 +66,15 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob { ...@@ -58,11 +66,15 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
// Transition from kReadyToParse to kParsed. // Transition from kReadyToParse to kParsed.
void Parse(); void Parse();
// Transition from kParsed to kReadyToAnalyse (or kFailed). Returns false // Transition from kParsed to kReadyToAnalyze (or kFailed). Returns false
// when transitioning to kFailed. In that case, an exception is pending. // when transitioning to kFailed. In that case, an exception is pending.
bool FinalizeParsingOnMainThread(); bool FinalizeParsingOnMainThread();
// Transition from kReadyToAnalyse to kReadyToCompile (or kFailed). Returns // Transition from kReadyToAnalyze to kAnalyzed (or kFailed). Returns
// false when transitioning to kFailed. In that case, an exception is pending.
bool AnalyzeOnMainThread();
// Transition from kAnalyzed to kReadyToCompile (or kFailed). Returns
// false when transitioning to kFailed. In that case, an exception is pending. // false when transitioning to kFailed. In that case, an exception is pending.
bool PrepareToCompileOnMainThread(); bool PrepareToCompileOnMainThread();
...@@ -86,7 +98,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob { ...@@ -86,7 +98,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
private: private:
FRIEND_TEST(CompilerDispatcherJobTest, ScopeChain); FRIEND_TEST(CompilerDispatcherJobTest, ScopeChain);
CompileJobStatus status_ = CompileJobStatus::kInitial; CompileJobStatus status_;
Isolate* isolate_; Isolate* isolate_;
CompilerDispatcherTracer* tracer_; CompilerDispatcherTracer* tracer_;
Handle<SharedFunctionInfo> shared_; // Global handle. Handle<SharedFunctionInfo> shared_; // Global handle.
......
...@@ -39,6 +39,9 @@ CompilerDispatcherTracer::Scope::~Scope() { ...@@ -39,6 +39,9 @@ CompilerDispatcherTracer::Scope::~Scope() {
case ScopeID::kFinalizeParsing: case ScopeID::kFinalizeParsing:
tracer_->RecordFinalizeParsing(elapsed); tracer_->RecordFinalizeParsing(elapsed);
break; break;
case ScopeID::kAnalyze:
tracer_->RecordAnalyze(elapsed);
break;
case ScopeID::kPrepareToCompile: case ScopeID::kPrepareToCompile:
tracer_->RecordPrepareToCompile(elapsed); tracer_->RecordPrepareToCompile(elapsed);
break; break;
...@@ -60,6 +63,8 @@ const char* CompilerDispatcherTracer::Scope::Name(ScopeID scope_id) { ...@@ -60,6 +63,8 @@ const char* CompilerDispatcherTracer::Scope::Name(ScopeID scope_id) {
return "V8.BackgroundCompile_Parse"; return "V8.BackgroundCompile_Parse";
case ScopeID::kFinalizeParsing: case ScopeID::kFinalizeParsing:
return "V8.BackgroundCompile_FinalizeParsing"; return "V8.BackgroundCompile_FinalizeParsing";
case ScopeID::kAnalyze:
return "V8.BackgroundCompile_Analyze";
case ScopeID::kPrepareToCompile: case ScopeID::kPrepareToCompile:
return "V8.BackgroundCompile_PrepareToCompile"; return "V8.BackgroundCompile_PrepareToCompile";
case ScopeID::kCompile: case ScopeID::kCompile:
...@@ -97,6 +102,11 @@ void CompilerDispatcherTracer::RecordFinalizeParsing(double duration_ms) { ...@@ -97,6 +102,11 @@ void CompilerDispatcherTracer::RecordFinalizeParsing(double duration_ms) {
finalize_parsing_events_.Push(duration_ms); finalize_parsing_events_.Push(duration_ms);
} }
void CompilerDispatcherTracer::RecordAnalyze(double duration_ms) {
base::LockGuard<base::Mutex> lock(&mutex_);
analyze_events_.Push(duration_ms);
}
void CompilerDispatcherTracer::RecordPrepareToCompile(double duration_ms) { void CompilerDispatcherTracer::RecordPrepareToCompile(double duration_ms) {
base::LockGuard<base::Mutex> lock(&mutex_); base::LockGuard<base::Mutex> lock(&mutex_);
prepare_compile_events_.Push(duration_ms); prepare_compile_events_.Push(duration_ms);
...@@ -128,6 +138,11 @@ double CompilerDispatcherTracer::EstimateFinalizeParsingInMs() const { ...@@ -128,6 +138,11 @@ double CompilerDispatcherTracer::EstimateFinalizeParsingInMs() const {
return Average(finalize_parsing_events_); return Average(finalize_parsing_events_);
} }
double CompilerDispatcherTracer::EstimateAnalyzeInMs() const {
base::LockGuard<base::Mutex> lock(&mutex_);
return Average(analyze_events_);
}
double CompilerDispatcherTracer::EstimatePrepareToCompileInMs() const { double CompilerDispatcherTracer::EstimatePrepareToCompileInMs() const {
base::LockGuard<base::Mutex> lock(&mutex_); base::LockGuard<base::Mutex> lock(&mutex_);
return Average(prepare_compile_events_); return Average(prepare_compile_events_);
...@@ -148,11 +163,12 @@ void CompilerDispatcherTracer::DumpStatistics() const { ...@@ -148,11 +163,12 @@ void CompilerDispatcherTracer::DumpStatistics() const {
PrintF( PrintF(
"CompilerDispatcherTracer: " "CompilerDispatcherTracer: "
"prepare_parsing=%.2lfms parsing=%.2lfms/kb finalize_parsing=%.2lfms " "prepare_parsing=%.2lfms parsing=%.2lfms/kb finalize_parsing=%.2lfms "
"prepare_compiling=%.2lfms compiling=%.2lfms/kb " "analyze=%.2lfms prepare_compiling=%.2lfms compiling=%.2lfms/kb "
"finalize_compilig=%.2lfms\n", "finalize_compiling=%.2lfms\n",
EstimatePrepareToParseInMs(), EstimateParseInMs(1 * KB), EstimatePrepareToParseInMs(), EstimateParseInMs(1 * KB),
EstimateFinalizeParsingInMs(), EstimatePrepareToCompileInMs(), EstimateFinalizeParsingInMs(), EstimateAnalyzeInMs(),
EstimateCompileInMs(1 * KB), EstimateFinalizeCompilingInMs()); EstimatePrepareToCompileInMs(), EstimateCompileInMs(1 * KB),
EstimateFinalizeCompilingInMs());
} }
double CompilerDispatcherTracer::Average( double CompilerDispatcherTracer::Average(
......
...@@ -35,6 +35,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer { ...@@ -35,6 +35,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer {
kPrepareToParse, kPrepareToParse,
kParse, kParse,
kFinalizeParsing, kFinalizeParsing,
kAnalyze,
kPrepareToCompile, kPrepareToCompile,
kCompile, kCompile,
kFinalizeCompiling kFinalizeCompiling
...@@ -62,6 +63,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer { ...@@ -62,6 +63,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer {
void RecordPrepareToParse(double duration_ms); void RecordPrepareToParse(double duration_ms);
void RecordParse(double duration_ms, size_t source_length); void RecordParse(double duration_ms, size_t source_length);
void RecordFinalizeParsing(double duration_ms); void RecordFinalizeParsing(double duration_ms);
void RecordAnalyze(double duration_ms);
void RecordPrepareToCompile(double duration_ms); void RecordPrepareToCompile(double duration_ms);
void RecordCompile(double duration_ms, size_t ast_size_in_bytes); void RecordCompile(double duration_ms, size_t ast_size_in_bytes);
void RecordFinalizeCompiling(double duration_ms); void RecordFinalizeCompiling(double duration_ms);
...@@ -69,6 +71,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer { ...@@ -69,6 +71,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer {
double EstimatePrepareToParseInMs() const; double EstimatePrepareToParseInMs() const;
double EstimateParseInMs(size_t source_length) const; double EstimateParseInMs(size_t source_length) const;
double EstimateFinalizeParsingInMs() const; double EstimateFinalizeParsingInMs() const;
double EstimateAnalyzeInMs() const;
double EstimatePrepareToCompileInMs() const; double EstimatePrepareToCompileInMs() const;
double EstimateCompileInMs(size_t ast_size_in_bytes) const; double EstimateCompileInMs(size_t ast_size_in_bytes) const;
double EstimateFinalizeCompilingInMs() const; double EstimateFinalizeCompilingInMs() const;
...@@ -84,6 +87,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer { ...@@ -84,6 +87,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer {
base::RingBuffer<double> prepare_parse_events_; base::RingBuffer<double> prepare_parse_events_;
base::RingBuffer<std::pair<size_t, double>> parse_events_; base::RingBuffer<std::pair<size_t, double>> parse_events_;
base::RingBuffer<double> finalize_parsing_events_; base::RingBuffer<double> finalize_parsing_events_;
base::RingBuffer<double> analyze_events_;
base::RingBuffer<double> prepare_compile_events_; base::RingBuffer<double> prepare_compile_events_;
base::RingBuffer<std::pair<size_t, double>> compile_events_; base::RingBuffer<std::pair<size_t, double>> compile_events_;
base::RingBuffer<double> finalize_compiling_events_; base::RingBuffer<double> finalize_compiling_events_;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "include/v8.h" #include "include/v8.h"
#include "src/base/platform/time.h" #include "src/base/platform/time.h"
#include "src/cancelable-task.h" #include "src/cancelable-task.h"
#include "src/compilation-info.h"
#include "src/compiler-dispatcher/compiler-dispatcher-job.h" #include "src/compiler-dispatcher/compiler-dispatcher-job.h"
#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
#include "src/flags.h" #include "src/flags.h"
...@@ -36,7 +37,11 @@ bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job, ...@@ -36,7 +37,11 @@ bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job,
job->FinalizeParsingOnMainThread(); job->FinalizeParsingOnMainThread();
break; break;
case CompileJobStatus::kReadyToAnalyse: case CompileJobStatus::kReadyToAnalyze:
job->AnalyzeOnMainThread();
break;
case CompileJobStatus::kAnalyzed:
job->PrepareToCompileOnMainThread(); job->PrepareToCompileOnMainThread();
break; break;
...@@ -224,7 +229,7 @@ CompilerDispatcher::~CompilerDispatcher() { ...@@ -224,7 +229,7 @@ CompilerDispatcher::~CompilerDispatcher() {
task_manager_->CancelAndWait(); task_manager_->CancelAndWait();
} }
bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { bool CompilerDispatcher::CanEnqueue(Handle<SharedFunctionInfo> function) {
if (!IsEnabled()) return false; if (!IsEnabled()) return false;
DCHECK(FLAG_ignition); DCHECK(FLAG_ignition);
...@@ -245,12 +250,17 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { ...@@ -245,12 +250,17 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
return false; return false;
} }
return true;
}
bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
if (!CanEnqueue(function)) return false;
if (IsEnqueued(function)) return true; if (IsEnqueued(function)) return true;
if (trace_compiler_dispatcher_) { if (trace_compiler_dispatcher_) {
PrintF("CompilerDispatcher: enqueuing "); PrintF("CompilerDispatcher: enqueuing ");
function->ShortPrint(); function->ShortPrint();
PrintF("\n"); PrintF(" for parse and compile\n");
} }
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
...@@ -277,11 +287,44 @@ bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) { ...@@ -277,11 +287,44 @@ bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) {
return true; return true;
} }
bool CompilerDispatcher::IsEnabled() const { bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function,
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); FunctionLiteral* literal) {
return FLAG_compiler_dispatcher && platform_->IdleTasksEnabled(v8_isolate); if (!CanEnqueue(function)) return false;
if (IsEnqueued(function)) return true;
if (trace_compiler_dispatcher_) {
PrintF("CompilerDispatcher: enqueuing ");
function->ShortPrint();
PrintF(" for compile\n");
}
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
isolate_, tracer_.get(), function, literal, max_stack_size_));
std::pair<int, int> key(Script::cast(function->script())->id(),
function->function_literal_id());
jobs_.insert(std::make_pair(key, std::move(job)));
ScheduleIdleTaskIfNeeded();
return true;
}
bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function,
FunctionLiteral* literal) {
if (!Enqueue(function, literal)) return false;
if (trace_compiler_dispatcher_) {
PrintF("CompilerDispatcher: stepping ");
function->ShortPrint();
PrintF("\n");
}
JobMap::const_iterator job = GetJobFor(function);
DoNextStepOnMainThread(isolate_, job->second.get(),
ExceptionHandling::kSwallow);
ConsiderJobForBackgroundProcessing(job->second.get());
return true;
} }
bool CompilerDispatcher::IsEnabled() const { return FLAG_compiler_dispatcher; }
bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const { bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const {
return GetJobFor(function) != jobs_.end(); return GetJobFor(function) != jobs_.end();
} }
...@@ -302,6 +345,16 @@ void CompilerDispatcher::WaitForJobIfRunningOnBackground( ...@@ -302,6 +345,16 @@ void CompilerDispatcher::WaitForJobIfRunningOnBackground(
DCHECK(running_background_jobs_.find(job) == running_background_jobs_.end()); DCHECK(running_background_jobs_.find(job) == running_background_jobs_.end());
} }
bool CompilerDispatcher::FinishNow(CompilerDispatcherJob* job) {
WaitForJobIfRunningOnBackground(job);
while (!IsFinished(job)) {
DoNextStepOnMainThread(isolate_, job, ExceptionHandling::kThrow);
}
bool result = job->status() != CompileJobStatus::kFailed;
job->ResetOnMainThread();
return result;
}
bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
JobMap::const_iterator job = GetJobFor(function); JobMap::const_iterator job = GetJobFor(function);
CHECK(job != jobs_.end()); CHECK(job != jobs_.end());
...@@ -312,12 +365,7 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { ...@@ -312,12 +365,7 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
PrintF(" now\n"); PrintF(" now\n");
} }
WaitForJobIfRunningOnBackground(job->second.get()); bool result = FinishNow(job->second.get());
while (!IsFinished(job->second.get())) {
DoNextStepOnMainThread(isolate_, job->second.get(),
ExceptionHandling::kThrow);
}
bool result = job->second->status() != CompileJobStatus::kFailed;
if (trace_compiler_dispatcher_) { if (trace_compiler_dispatcher_) {
PrintF("CompilerDispatcher: finished working on "); PrintF("CompilerDispatcher: finished working on ");
...@@ -326,7 +374,6 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { ...@@ -326,7 +374,6 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
tracer_->DumpStatistics(); tracer_->DumpStatistics();
} }
job->second->ResetOnMainThread();
jobs_.erase(job); jobs_.erase(job);
if (jobs_.empty()) { if (jobs_.empty()) {
base::LockGuard<base::Mutex> lock(&mutex_); base::LockGuard<base::Mutex> lock(&mutex_);
...@@ -335,6 +382,30 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { ...@@ -335,6 +382,30 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
return result; return result;
} }
bool CompilerDispatcher::FinishAllNow() {
if (trace_compiler_dispatcher_) {
PrintF("CompilerDispatcher: finishing all jobs now\n");
}
bool result = true;
for (auto& it : jobs_) {
result &= FinishNow(it.second.get());
}
if (trace_compiler_dispatcher_) {
PrintF("CompilerDispatcher: finished all jobs\n");
}
jobs_.clear();
{
base::LockGuard<base::Mutex> lock(&mutex_);
DCHECK(pending_background_jobs_.empty());
DCHECK(running_background_jobs_.empty());
abort_ = false;
}
return result;
}
void CompilerDispatcher::AbortAll(BlockingBehavior blocking) { void CompilerDispatcher::AbortAll(BlockingBehavior blocking) {
bool background_tasks_running = bool background_tasks_running =
task_manager_->TryAbortAll() == CancelableTaskManager::kTaskRunning; task_manager_->TryAbortAll() == CancelableTaskManager::kTaskRunning;
......
...@@ -28,6 +28,7 @@ namespace internal { ...@@ -28,6 +28,7 @@ namespace internal {
class CancelableTaskManager; class CancelableTaskManager;
class CompilerDispatcherJob; class CompilerDispatcherJob;
class CompilerDispatcherTracer; class CompilerDispatcherTracer;
class FunctionLiteral;
class Isolate; class Isolate;
class SharedFunctionInfo; class SharedFunctionInfo;
...@@ -68,7 +69,10 @@ class V8_EXPORT_PRIVATE CompilerDispatcher { ...@@ -68,7 +69,10 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
size_t max_stack_size); size_t max_stack_size);
~CompilerDispatcher(); ~CompilerDispatcher();
// Returns true if a job was enqueued. // Returns true if the compiler dispatcher is enabled.
bool IsEnabled() const;
// Enqueue a job for parse and compile. Returns true if a job was enqueued.
bool Enqueue(Handle<SharedFunctionInfo> function); bool Enqueue(Handle<SharedFunctionInfo> function);
// Like Enqueue, but also advances the job so that it can potentially // Like Enqueue, but also advances the job so that it can potentially
...@@ -76,13 +80,27 @@ class V8_EXPORT_PRIVATE CompilerDispatcher { ...@@ -76,13 +80,27 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
// true if the job was enqueued. // true if the job was enqueued.
bool EnqueueAndStep(Handle<SharedFunctionInfo> function); bool EnqueueAndStep(Handle<SharedFunctionInfo> function);
// Enqueue a job for compilation. Function must have already been parsed and
// analyzed and be ready for compilation. Returns true if a job was enqueued.
bool Enqueue(Handle<SharedFunctionInfo> function, FunctionLiteral* literal);
// Like Enqueue, but also advances the job so that it can potentially
// continue running on a background thread (if at all possible). Returns
// true if the job was enqueued.
bool EnqueueAndStep(Handle<SharedFunctionInfo> function,
FunctionLiteral* literal);
// Returns true if there is a pending job for the given function. // Returns true if there is a pending job for the given function.
bool IsEnqueued(Handle<SharedFunctionInfo> function) const; bool IsEnqueued(Handle<SharedFunctionInfo> function) const;
// Blocks until the given function is compiled (and does so as fast as // Blocks until the given function is compiled (and does so as fast as
// possible). Returns true if the compile job was succesful. // possible). Returns true if the compile job was successful.
bool FinishNow(Handle<SharedFunctionInfo> function); bool FinishNow(Handle<SharedFunctionInfo> function);
// Blocks until all enqueued jobs have finished. Returns true if all the
// compile jobs were successful.
bool FinishAllNow();
// Aborts a given job. Blocks if requested. // Aborts a given job. Blocks if requested.
void Abort(Handle<SharedFunctionInfo> function, BlockingBehavior blocking); void Abort(Handle<SharedFunctionInfo> function, BlockingBehavior blocking);
...@@ -95,6 +113,8 @@ class V8_EXPORT_PRIVATE CompilerDispatcher { ...@@ -95,6 +113,8 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
private: private:
FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStep); FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStep);
FRIEND_TEST(CompilerDispatcherTest, EnqueueParsed);
FRIEND_TEST(CompilerDispatcherTest, EnqueueAndStepParsed);
FRIEND_TEST(CompilerDispatcherTest, IdleTaskSmallIdleTime); FRIEND_TEST(CompilerDispatcherTest, IdleTaskSmallIdleTime);
FRIEND_TEST(CompilerDispatcherTest, CompileOnBackgroundThread); FRIEND_TEST(CompilerDispatcherTest, CompileOnBackgroundThread);
FRIEND_TEST(CompilerDispatcherTest, FinishNowWithBackgroundTask); FRIEND_TEST(CompilerDispatcherTest, FinishNowWithBackgroundTask);
...@@ -110,9 +130,10 @@ class V8_EXPORT_PRIVATE CompilerDispatcher { ...@@ -110,9 +130,10 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
class IdleTask; class IdleTask;
void WaitForJobIfRunningOnBackground(CompilerDispatcherJob* job); void WaitForJobIfRunningOnBackground(CompilerDispatcherJob* job);
bool IsEnabled() const;
void AbortInactiveJobs(); void AbortInactiveJobs();
bool CanEnqueue(Handle<SharedFunctionInfo> function);
JobMap::const_iterator GetJobFor(Handle<SharedFunctionInfo> shared) const; JobMap::const_iterator GetJobFor(Handle<SharedFunctionInfo> shared) const;
bool FinishNow(CompilerDispatcherJob* job);
void ConsiderJobForBackgroundProcessing(CompilerDispatcherJob* job); void ConsiderJobForBackgroundProcessing(CompilerDispatcherJob* job);
void ScheduleMoreBackgroundTasksIfNeeded(); void ScheduleMoreBackgroundTasksIfNeeded();
void ScheduleIdleTaskFromAnyThread(); void ScheduleIdleTaskFromAnyThread();
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
#include "src/codegen.h" #include "src/codegen.h"
#include "src/compilation-cache.h" #include "src/compilation-cache.h"
#include "src/compiler-dispatcher/compiler-dispatcher.h"
#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
#include "src/compiler/pipeline.h" #include "src/compiler/pipeline.h"
#include "src/crankshaft/hydrogen.h" #include "src/crankshaft/hydrogen.h"
...@@ -375,6 +376,20 @@ bool ShouldUseIgnition(CompilationInfo* info) { ...@@ -375,6 +376,20 @@ bool ShouldUseIgnition(CompilationInfo* info) {
return shared->PassesFilter(FLAG_ignition_filter); return shared->PassesFilter(FLAG_ignition_filter);
} }
bool UseAsmWasm(DeclarationScope* scope, Handle<SharedFunctionInfo> shared_info,
bool is_debug) {
return FLAG_validate_asm && scope->asm_module() &&
!shared_info->is_asm_wasm_broken() && !is_debug;
}
bool UseCompilerDispatcher(CompilerDispatcher* dispatcher,
DeclarationScope* scope,
Handle<SharedFunctionInfo> shared_info,
bool is_debug, bool will_serialize) {
return dispatcher->IsEnabled() && !is_debug && !will_serialize &&
!UseAsmWasm(scope, shared_info, is_debug);
}
CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) {
// Function should have been parsed and analyzed before creating a compilation // Function should have been parsed and analyzed before creating a compilation
// job. // job.
...@@ -427,8 +442,14 @@ void InstallUnoptimizedCode(CompilationInfo* info) { ...@@ -427,8 +442,14 @@ void InstallUnoptimizedCode(CompilationInfo* info) {
CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) { CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) {
CompilationJob::Status status = job->FinalizeJob(); CompilationJob::Status status = job->FinalizeJob();
if (status == CompilationJob::SUCCEEDED) { if (status == CompilationJob::SUCCEEDED) {
EnsureFeedbackMetadata(job->info()); CompilationInfo* info = job->info();
InstallUnoptimizedCode(job->info()); EnsureFeedbackMetadata(info);
DCHECK(!info->code().is_null());
if (info->parse_info()->literal()->should_be_used_once_hint()) {
info->code()->MarkToBeExecutedOnce(info->isolate());
}
InstallUnoptimizedCode(info);
RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, info);
job->RecordUnoptimizedCompilationStats(); job->RecordUnoptimizedCompilationStats();
} }
return status; return status;
...@@ -462,8 +483,7 @@ bool Renumber(ParseInfo* parse_info, ...@@ -462,8 +483,7 @@ bool Renumber(ParseInfo* parse_info,
} }
bool GenerateUnoptimizedCode(CompilationInfo* info) { bool GenerateUnoptimizedCode(CompilationInfo* info) {
if (FLAG_validate_asm && info->scope()->asm_module() && if (UseAsmWasm(info->scope(), info->shared_info(), info->is_debug())) {
!info->shared_info()->is_asm_wasm_broken() && !info->is_debug()) {
EnsureFeedbackMetadata(info); EnsureFeedbackMetadata(info);
MaybeHandle<FixedArray> wasm_data; MaybeHandle<FixedArray> wasm_data;
wasm_data = AsmJs::CompileAsmViaWasm(info); wasm_data = AsmJs::CompileAsmViaWasm(info);
...@@ -486,10 +506,12 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) { ...@@ -486,10 +506,12 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) {
} }
bool CompileUnoptimizedInnerFunctions( bool CompileUnoptimizedInnerFunctions(
ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>* literals, Compiler::EagerInnerFunctionLiterals* literals,
CompilationInfo* outer_info) { CompilationInfo* outer_info) {
Isolate* isolate = outer_info->isolate(); Isolate* isolate = outer_info->isolate();
Handle<Script> script = outer_info->script(); Handle<Script> script = outer_info->script();
bool is_debug = outer_info->is_debug();
bool will_serialize = outer_info->will_serialize();
RuntimeCallTimerScope runtimeTimer(isolate, RuntimeCallTimerScope runtimeTimer(isolate,
&RuntimeCallStats::CompileInnerFunction); &RuntimeCallStats::CompileInnerFunction);
...@@ -503,29 +525,35 @@ bool CompileUnoptimizedInnerFunctions( ...@@ -503,29 +525,35 @@ bool CompileUnoptimizedInnerFunctions(
// eagerly compiled function literals. // eagerly compiled function literals.
SetSharedFunctionFlagsFromLiteral(literal, shared); SetSharedFunctionFlagsFromLiteral(literal, shared);
Zone zone(isolate->allocator(), ZONE_NAME); // Try to enqueue the eager function on the compiler dispatcher.
ParseInfo parse_info(&zone, script); CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
parse_info.set_literal(literal); if (UseCompilerDispatcher(dispatcher, literal->scope(), shared, is_debug,
parse_info.set_shared_info(shared); will_serialize) &&
parse_info.set_function_literal_id(shared->function_literal_id()); dispatcher->EnqueueAndStep(shared, literal)) {
parse_info.set_language_mode(literal->scope()->language_mode()); // If we have successfully queued up the function for compilation on the
parse_info.set_ast_value_factory( // compiler dispatcher then we are done.
outer_info->parse_info()->ast_value_factory()); continue;
parse_info.set_ast_value_factory_owned(false); } else {
// Otherwise generate unoptimized code now.
CompilationInfo info(&parse_info, Handle<JSFunction>::null()); Zone zone(isolate->allocator(), ZONE_NAME);
if (outer_info->will_serialize()) info.PrepareForSerializing(); ParseInfo parse_info(&zone, script);
if (outer_info->is_debug()) info.MarkAsDebug(); CompilationInfo info(&parse_info, Handle<JSFunction>::null());
if (!GenerateUnoptimizedCode(&info)) { parse_info.set_literal(literal);
if (!isolate->has_pending_exception()) isolate->StackOverflow(); parse_info.set_shared_info(shared);
return false; parse_info.set_function_literal_id(shared->function_literal_id());
} parse_info.set_language_mode(literal->scope()->language_mode());
parse_info.set_ast_value_factory(
DCHECK(!info.code().is_null()); outer_info->parse_info()->ast_value_factory());
RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info); parse_info.set_ast_value_factory_owned(false);
if (literal->should_be_used_once_hint()) {
info.code()->MarkToBeExecutedOnce(isolate); if (will_serialize) info.PrepareForSerializing();
if (is_debug) info.MarkAsDebug();
if (!GenerateUnoptimizedCode(&info)) {
if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
}
} }
} }
return true; return true;
...@@ -543,6 +571,17 @@ bool CompileUnoptimizedCode(CompilationInfo* info) { ...@@ -543,6 +571,17 @@ bool CompileUnoptimizedCode(CompilationInfo* info) {
return false; return false;
} }
// TODO(rmcilroy): Remove this once the enqueued tasks can keep the parsed
// zone and handles alive and replace with a check in CompileLazy to finish
// the task itself.
RuntimeCallTimerScope runtimeTimer(
isolate, &RuntimeCallStats::CompileWaitForDispatcher);
if (isolate->compiler_dispatcher()->IsEnabled() &&
!isolate->compiler_dispatcher()->FinishAllNow()) {
if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
}
return true; return true;
} }
...@@ -1122,7 +1161,9 @@ bool Compiler::Analyze(ParseInfo* info, ...@@ -1122,7 +1161,9 @@ bool Compiler::Analyze(ParseInfo* info,
&RuntimeCallStats::CompileAnalyse); &RuntimeCallStats::CompileAnalyse);
if (!Rewriter::Rewrite(info)) return false; if (!Rewriter::Rewrite(info)) return false;
DeclarationScope::Analyze(info, AnalyzeMode::kRegular); DeclarationScope::Analyze(info, AnalyzeMode::kRegular);
if (!Renumber(info, eager_literals)) return false; if (!Renumber(info, eager_literals)) {
return false;
}
DCHECK_NOT_NULL(info->scope()); DCHECK_NOT_NULL(info->scope());
return true; return true;
} }
...@@ -1730,13 +1771,8 @@ bool Compiler::FinalizeCompilationJob(CompilationJob* raw_job) { ...@@ -1730,13 +1771,8 @@ bool Compiler::FinalizeCompilationJob(CompilationJob* raw_job) {
return FinalizeOptimizedCompilationJob(job.get()) == return FinalizeOptimizedCompilationJob(job.get()) ==
CompilationJob::SUCCEEDED; CompilationJob::SUCCEEDED;
} else { } else {
if (FinalizeUnoptimizedCompilationJob(job.get()) == return FinalizeUnoptimizedCompilationJob(job.get()) ==
CompilationJob::SUCCEEDED) { CompilationJob::SUCCEEDED;
RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG,
job->info());
return true;
}
return false;
} }
} }
......
...@@ -37,7 +37,7 @@ class ThreadedListZoneEntry; ...@@ -37,7 +37,7 @@ class ThreadedListZoneEntry;
// parameters which then can be executed. If the source code contains other // parameters which then can be executed. If the source code contains other
// functions, they might be compiled and allocated as part of the compilation // functions, they might be compiled and allocated as part of the compilation
// of the source code or deferred for lazy compilation at a later point. // of the source code or deferred for lazy compilation at a later point.
class Compiler : public AllStatic { class V8_EXPORT_PRIVATE Compiler : public AllStatic {
public: public:
enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION }; enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };
enum ConcurrencyMode { NOT_CONCURRENT, CONCURRENT }; enum ConcurrencyMode { NOT_CONCURRENT, CONCURRENT };
......
...@@ -702,7 +702,7 @@ class RuntimeCallTimer final { ...@@ -702,7 +702,7 @@ class RuntimeCallTimer final {
V(CompileScopeAnalysis) \ V(CompileScopeAnalysis) \
V(CompileScript) \ V(CompileScript) \
V(CompileSerialize) \ V(CompileSerialize) \
V(CompilerDispatcher) \ V(CompileWaitForDispatcher) \
V(DeoptimizeCode) \ V(DeoptimizeCode) \
V(FunctionCallback) \ V(FunctionCallback) \
V(GC) \ V(GC) \
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --ignition-filter=f
// This test tests that full code compiled without debug break slots // This test tests that full code compiled without debug break slots
// is recompiled with debug break slots when debugging is started. // is recompiled with debug break slots when debugging is started.
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --ignition-filter=f
var Debug = debug.Debug; var Debug = debug.Debug;
var break_count = 0; var break_count = 0;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --ignition-filter=f
// Flags: --no-turbo // Flags: --no-turbo
// TODO(yangguo): fix for turbofan // TODO(yangguo): fix for turbofan
...@@ -16,6 +15,6 @@ function f(x) { ...@@ -16,6 +15,6 @@ function f(x) {
var stack_lines = f(2).split("\n"); var stack_lines = f(2).split("\n");
assertTrue(/at f \(.*?:12:12\)/.test(stack_lines[1])); assertTrue(/at f \(.*?:11:12\)/.test(stack_lines[1]));
assertTrue(/at f \(.*?:14:10\)/.test(stack_lines[2])); assertTrue(/at f \(.*?:13:10\)/.test(stack_lines[2]));
assertTrue(/at f \(.*?:14:10\)/.test(stack_lines[3])); assertTrue(/at f \(.*?:13:10\)/.test(stack_lines[3]));
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --ignition --ignition-filter=-foo // Flags: --ignition
function* foo() { yield 42 } function* foo() { yield 42 }
function* goo() { yield 42 } function* goo() { yield 42 }
......
...@@ -112,7 +112,9 @@ TEST_F(CompilerDispatcherJobTest, StateTransitions) { ...@@ -112,7 +112,9 @@ TEST_F(CompilerDispatcherJobTest, StateTransitions) {
job->Parse(); job->Parse();
ASSERT_TRUE(job->status() == CompileJobStatus::kParsed); ASSERT_TRUE(job->status() == CompileJobStatus::kParsed);
ASSERT_TRUE(job->FinalizeParsingOnMainThread()); ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToAnalyse); ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToAnalyze);
ASSERT_TRUE(job->AnalyzeOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kAnalyzed);
ASSERT_TRUE(job->PrepareToCompileOnMainThread()); ASSERT_TRUE(job->PrepareToCompileOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile); ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile);
job->Compile(); job->Compile();
...@@ -153,6 +155,7 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) { ...@@ -153,6 +155,7 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
job->PrepareToParseOnMainThread(); job->PrepareToParseOnMainThread();
job->Parse(); job->Parse();
ASSERT_TRUE(job->FinalizeParsingOnMainThread()); ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->AnalyzeOnMainThread());
ASSERT_TRUE(job->PrepareToCompileOnMainThread()); ASSERT_TRUE(job->PrepareToCompileOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile); ASSERT_TRUE(job->status() == CompileJobStatus::kReadyToCompile);
...@@ -189,6 +192,7 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) { ...@@ -189,6 +192,7 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
job->PrepareToParseOnMainThread(); job->PrepareToParseOnMainThread();
job->Parse(); job->Parse();
job->FinalizeParsingOnMainThread(); job->FinalizeParsingOnMainThread();
job->AnalyzeOnMainThread();
job->PrepareToCompileOnMainThread(); job->PrepareToCompileOnMainThread();
job->Compile(); job->Compile();
ASSERT_TRUE(job->FinalizeCompilingOnMainThread()); ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
...@@ -201,7 +205,7 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) { ...@@ -201,7 +205,7 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial); ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
} }
TEST_F(CompilerDispatcherJobTest, CompileFailureToPrepare) { TEST_F(CompilerDispatcherJobTest, CompileFailureToAnalyse) {
std::string raw_script("() { var a = "); std::string raw_script("() { var a = ");
for (int i = 0; i < 100000; i++) { for (int i = 0; i < 100000; i++) {
raw_script += "'x' + "; raw_script += "'x' + ";
...@@ -215,7 +219,7 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToPrepare) { ...@@ -215,7 +219,7 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToPrepare) {
job->PrepareToParseOnMainThread(); job->PrepareToParseOnMainThread();
job->Parse(); job->Parse();
job->FinalizeParsingOnMainThread(); job->FinalizeParsingOnMainThread();
ASSERT_FALSE(job->PrepareToCompileOnMainThread()); ASSERT_FALSE(job->AnalyzeOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kFailed); ASSERT_TRUE(job->status() == CompileJobStatus::kFailed);
ASSERT_TRUE(i_isolate()->has_pending_exception()); ASSERT_TRUE(i_isolate()->has_pending_exception());
...@@ -238,6 +242,7 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) { ...@@ -238,6 +242,7 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) {
job->PrepareToParseOnMainThread(); job->PrepareToParseOnMainThread();
job->Parse(); job->Parse();
job->FinalizeParsingOnMainThread(); job->FinalizeParsingOnMainThread();
job->AnalyzeOnMainThread();
job->PrepareToCompileOnMainThread(); job->PrepareToCompileOnMainThread();
job->Compile(); job->Compile();
ASSERT_FALSE(job->FinalizeCompilingOnMainThread()); ASSERT_FALSE(job->FinalizeCompilingOnMainThread());
...@@ -282,6 +287,7 @@ TEST_F(CompilerDispatcherJobTest, CompileOnBackgroundThread) { ...@@ -282,6 +287,7 @@ TEST_F(CompilerDispatcherJobTest, CompileOnBackgroundThread) {
job->PrepareToParseOnMainThread(); job->PrepareToParseOnMainThread();
job->Parse(); job->Parse();
job->FinalizeParsingOnMainThread(); job->FinalizeParsingOnMainThread();
job->AnalyzeOnMainThread();
job->PrepareToCompileOnMainThread(); job->PrepareToCompileOnMainThread();
base::Semaphore semaphore(0); base::Semaphore semaphore(0);
...@@ -314,6 +320,7 @@ TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) { ...@@ -314,6 +320,7 @@ TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
job->PrepareToParseOnMainThread(); job->PrepareToParseOnMainThread();
job->Parse(); job->Parse();
ASSERT_TRUE(job->FinalizeParsingOnMainThread()); ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->AnalyzeOnMainThread());
ASSERT_TRUE(job->PrepareToCompileOnMainThread()); ASSERT_TRUE(job->PrepareToCompileOnMainThread());
job->Compile(); job->Compile();
ASSERT_TRUE(job->FinalizeCompilingOnMainThread()); ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
......
...@@ -8,10 +8,13 @@ ...@@ -8,10 +8,13 @@
#include "src/base/platform/semaphore.h" #include "src/base/platform/semaphore.h"
#include "src/compiler-dispatcher/compiler-dispatcher-job.h" #include "src/compiler-dispatcher/compiler-dispatcher-job.h"
#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
#include "src/compiler.h"
#include "src/flags.h" #include "src/flags.h"
#include "src/handles.h" #include "src/handles.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/v8.h" #include "src/v8.h"
#include "src/zone/zone.h"
#include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h" #include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h"
#include "test/unittests/test-utils.h" #include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -802,5 +805,97 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStep) { ...@@ -802,5 +805,97 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStep) {
platform.ClearBackgroundTasks(); platform.ClearBackgroundTasks();
} }
TEST_F(CompilerDispatcherTest, EnqueueParsed) {
MockPlatform platform;
CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
const char script[] =
"function g() { var y = 1; function f17(x) { return x * y }; return f17; "
"} g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
Zone zone(i_isolate()->allocator(), ZONE_NAME);
ParseInfo parse_info(&zone, shared);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
ASSERT_FALSE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.Enqueue(shared, parse_info.literal()));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kAnalyzed);
ASSERT_TRUE(platform.IdleTaskPending());
platform.ClearIdleTask();
ASSERT_FALSE(platform.BackgroundTasksPending());
}
TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) {
MockPlatform platform;
CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
const char script[] =
"function g() { var y = 1; function f18(x) { return x * y }; return f18; "
"} g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
Zone zone(i_isolate()->allocator(), ZONE_NAME);
ParseInfo parse_info(&zone, shared);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
ASSERT_FALSE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared, parse_info.literal()));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
CompileJobStatus::kReadyToCompile);
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_TRUE(platform.BackgroundTasksPending());
platform.ClearIdleTask();
platform.ClearBackgroundTasks();
}
TEST_F(CompilerDispatcherTest, FinishAllNow) {
MockPlatform platform;
CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
const char script1[] =
"function g() { var y = 1; function f19(x) { return x + y }; return f19; "
"} g();";
Handle<JSFunction> f1 = Handle<JSFunction>::cast(RunJS(isolate(), script1));
Handle<SharedFunctionInfo> shared1(f1->shared(), i_isolate());
const char script2[] =
"function g() { var y = 1; function f20(x) { return x * y }; return f20; "
"} g();";
Handle<JSFunction> f2 = Handle<JSFunction>::cast(RunJS(isolate(), script2));
Handle<SharedFunctionInfo> shared2(f2->shared(), i_isolate());
ASSERT_FALSE(shared1->is_compiled());
ASSERT_FALSE(shared2->is_compiled());
// Enqueue shared1 as already parsed.
Zone zone(i_isolate()->allocator(), ZONE_NAME);
ParseInfo parse_info(&zone, shared1);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
ASSERT_TRUE(dispatcher.Enqueue(shared1, parse_info.literal()));
// Enqueue shared2 for parsing and compiling
ASSERT_TRUE(dispatcher.Enqueue(shared2));
ASSERT_TRUE(dispatcher.FinishAllNow());
// Finishing removes the SFI from the queue.
ASSERT_FALSE(dispatcher.IsEnqueued(shared1));
ASSERT_FALSE(dispatcher.IsEnqueued(shared2));
ASSERT_TRUE(shared1->is_compiled());
ASSERT_TRUE(shared2->is_compiled());
ASSERT_TRUE(platform.IdleTaskPending());
platform.ClearIdleTask();
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
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