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