Commit 8ff0ca1b authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Compiler] Simplify UnoptimizedCompileJob

Simplifies the unoptimized compile job to have only three steps, the
on-main-thread prepare step, the off-thread compile step and the
on-main-thread finalization step.

As part of this change, the compiler dispatcher no longer supports
functions with outer scopeinfo's, since these need to be analysed on the
main thread.

BUG=v8:5203

Change-Id: Ifb378ef81bd47b6f6d4037a3b8acf88660896c4e
Reviewed-on: https://chromium-review.googlesource.com/774558
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49413}
parent 473fb7d6
......@@ -30,26 +30,14 @@ CompilerDispatcherTracer::Scope::Scope(CompilerDispatcherTracer* tracer,
CompilerDispatcherTracer::Scope::~Scope() {
double elapsed = MonotonicallyIncreasingTimeInMs() - start_time_;
switch (scope_id_) {
case ScopeID::kPrepareToParse:
tracer_->RecordPrepareToParse(elapsed);
break;
case ScopeID::kParse:
tracer_->RecordParse(elapsed, num_);
break;
case ScopeID::kFinalizeParsing:
tracer_->RecordFinalizeParsing(elapsed);
break;
case ScopeID::kAnalyze:
tracer_->RecordAnalyze(elapsed);
break;
case ScopeID::kPrepareToCompile:
tracer_->RecordPrepareToCompile(elapsed);
case ScopeID::kPrepare:
tracer_->RecordPrepare(elapsed);
break;
case ScopeID::kCompile:
tracer_->RecordCompile(elapsed);
tracer_->RecordCompile(elapsed, num_);
break;
case ScopeID::kFinalizeCompiling:
tracer_->RecordFinalizeCompiling(elapsed);
case ScopeID::kFinalize:
tracer_->RecordFinalize(elapsed);
break;
}
}
......@@ -57,20 +45,12 @@ CompilerDispatcherTracer::Scope::~Scope() {
// static
const char* CompilerDispatcherTracer::Scope::Name(ScopeID scope_id) {
switch (scope_id) {
case ScopeID::kPrepareToParse:
return "V8.BackgroundCompile_PrepareToParse";
case ScopeID::kParse:
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::kPrepare:
return "V8.BackgroundCompile_Prepare";
case ScopeID::kCompile:
return "V8.BackgroundCompile_Compile";
case ScopeID::kFinalizeCompiling:
return "V8.BackgroundCompile_FinalizeCompiling";
case ScopeID::kFinalize:
return "V8.BackgroundCompile_Finalize";
}
UNREACHABLE();
}
......@@ -85,87 +65,44 @@ CompilerDispatcherTracer::CompilerDispatcherTracer(Isolate* isolate)
CompilerDispatcherTracer::~CompilerDispatcherTracer() {}
void CompilerDispatcherTracer::RecordPrepareToParse(double duration_ms) {
base::LockGuard<base::Mutex> lock(&mutex_);
prepare_parse_events_.Push(duration_ms);
}
void CompilerDispatcherTracer::RecordParse(double duration_ms,
size_t source_length) {
base::LockGuard<base::Mutex> lock(&mutex_);
parse_events_.Push(std::make_pair(source_length, duration_ms));
}
void CompilerDispatcherTracer::RecordFinalizeParsing(double duration_ms) {
base::LockGuard<base::Mutex> lock(&mutex_);
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);
}
void CompilerDispatcherTracer::RecordCompile(double duration_ms) {
base::LockGuard<base::Mutex> lock(&mutex_);
compile_events_.Push(duration_ms);
}
void CompilerDispatcherTracer::RecordFinalizeCompiling(double duration_ms) {
base::LockGuard<base::Mutex> lock(&mutex_);
finalize_compiling_events_.Push(duration_ms);
}
double CompilerDispatcherTracer::EstimatePrepareToParseInMs() const {
base::LockGuard<base::Mutex> lock(&mutex_);
return Average(prepare_parse_events_);
}
double CompilerDispatcherTracer::EstimateParseInMs(size_t source_length) const {
void CompilerDispatcherTracer::RecordPrepare(double duration_ms) {
base::LockGuard<base::Mutex> lock(&mutex_);
return Estimate(parse_events_, source_length);
prepare_events_.Push(duration_ms);
}
double CompilerDispatcherTracer::EstimateFinalizeParsingInMs() const {
void CompilerDispatcherTracer::RecordCompile(double duration_ms,
size_t source_length) {
base::LockGuard<base::Mutex> lock(&mutex_);
return Average(finalize_parsing_events_);
compile_events_.Push(std::make_pair(source_length, duration_ms));
}
double CompilerDispatcherTracer::EstimateAnalyzeInMs() const {
void CompilerDispatcherTracer::RecordFinalize(double duration_ms) {
base::LockGuard<base::Mutex> lock(&mutex_);
return Average(analyze_events_);
finalize_events_.Push(duration_ms);
}
double CompilerDispatcherTracer::EstimatePrepareToCompileInMs() const {
double CompilerDispatcherTracer::EstimatePrepareInMs() const {
base::LockGuard<base::Mutex> lock(&mutex_);
return Average(prepare_compile_events_);
return Average(prepare_events_);
}
double CompilerDispatcherTracer::EstimateCompileInMs() const {
double CompilerDispatcherTracer::EstimateCompileInMs(
size_t source_length) const {
base::LockGuard<base::Mutex> lock(&mutex_);
return Average(compile_events_);
return Estimate(compile_events_, source_length);
}
double CompilerDispatcherTracer::EstimateFinalizeCompilingInMs() const {
double CompilerDispatcherTracer::EstimateFinalizeInMs() const {
base::LockGuard<base::Mutex> lock(&mutex_);
return Average(finalize_compiling_events_);
return Average(finalize_events_);
}
void CompilerDispatcherTracer::DumpStatistics() const {
PrintF(
"CompilerDispatcherTracer: "
"prepare_parsing=%.2lfms parsing=%.2lfms/kb finalize_parsing=%.2lfms "
"analyze=%.2lfms prepare_compiling=%.2lfms compiling=%.2lfms/kb "
"finalize_compiling=%.2lfms\n",
EstimatePrepareToParseInMs(), EstimateParseInMs(1 * KB),
EstimateFinalizeParsingInMs(), EstimateAnalyzeInMs(),
EstimatePrepareToCompileInMs(), EstimateCompileInMs(),
EstimateFinalizeCompilingInMs());
"prepare=%.2lfms compiling=%.2lfms/kb finalize=%.2lfms\n",
EstimatePrepareInMs(), EstimateCompileInMs(1 * KB),
EstimateFinalizeInMs());
}
double CompilerDispatcherTracer::Average(
......
......@@ -31,15 +31,7 @@ class RuntimeCallStats;
class V8_EXPORT_PRIVATE CompilerDispatcherTracer {
public:
enum class ScopeID {
kPrepareToParse,
kParse,
kFinalizeParsing,
kAnalyze,
kPrepareToCompile,
kCompile,
kFinalizeCompiling
};
enum class ScopeID { kPrepare, kCompile, kFinalize };
class Scope {
public:
......@@ -60,21 +52,13 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer {
explicit CompilerDispatcherTracer(Isolate* isolate);
~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);
void RecordFinalizeCompiling(double duration_ms);
double EstimatePrepareToParseInMs() const;
double EstimateParseInMs(size_t source_length) const;
double EstimateFinalizeParsingInMs() const;
double EstimateAnalyzeInMs() const;
double EstimatePrepareToCompileInMs() const;
double EstimateCompileInMs() const;
double EstimateFinalizeCompilingInMs() const;
void RecordPrepare(double duration_ms);
void RecordCompile(double duration_ms, size_t source_length);
void RecordFinalize(double duration_ms);
double EstimatePrepareInMs() const;
double EstimateCompileInMs(size_t source_length) const;
double EstimateFinalizeInMs() const;
void DumpStatistics() const;
......@@ -84,13 +68,9 @@ class V8_EXPORT_PRIVATE CompilerDispatcherTracer {
const base::RingBuffer<std::pair<size_t, double>>& buffer, size_t num);
mutable base::Mutex mutex_;
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<double> compile_events_;
base::RingBuffer<double> finalize_compiling_events_;
base::RingBuffer<double> prepare_events_;
base::RingBuffer<std::pair<size_t, double>> compile_events_;
base::RingBuffer<double> finalize_events_;
RuntimeCallStats* runtime_call_stats_;
......
......@@ -70,11 +70,15 @@ UnoptimizedCompileJob::UnoptimizedCompileJob(Isolate* isolate,
: status_(Status::kInitial),
main_thread_id_(isolate->thread_id().ToInteger()),
tracer_(tracer),
allocator_(isolate->allocator()),
context_(isolate->global_handles()->Create(isolate->context())),
shared_(isolate->global_handles()->Create(*shared)),
max_stack_size_(max_stack_size),
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
DCHECK(!shared_->is_toplevel());
// TODO(rmcilroy): Handle functions with non-empty outer scope info.
DCHECK(shared_->outer_scope_info()->IsTheHole(isolate) ||
ScopeInfo::cast(shared_->outer_scope_info())->length() == 0);
HandleScope scope(isolate);
Handle<Script> script(Script::cast(shared_->script()), isolate);
Handle<String> source(String::cast(script->source()), isolate);
......@@ -118,25 +122,16 @@ void UnoptimizedCompileJob::StepNextOnMainThread(Isolate* isolate) {
switch (status()) {
case Status::kInitial:
return PrepareToParseOnMainThread(isolate);
case Status::kReadyToParse:
return Parse();
case Status::kParsed:
return FinalizeParsingOnMainThread(isolate);
case Status::kReadyToAnalyze:
return AnalyzeOnMainThread(isolate);
case Status::kAnalyzed:
return PrepareToCompileOnMainThread(isolate);
return PrepareOnMainThread(isolate);
case Status::kReadyToCompile:
return Compile();
return Compile(false);
case Status::kCompiled:
return FinalizeCompilingOnMainThread(isolate);
return FinalizeOnMainThread(isolate);
case Status::kReportErrors:
return ReportErrorsOnMainThread(isolate);
case Status::kFailed:
case Status::kDone:
......@@ -148,26 +143,25 @@ void UnoptimizedCompileJob::StepNextOnMainThread(Isolate* isolate) {
void UnoptimizedCompileJob::StepNextOnBackgroundThread() {
DCHECK(CanStepNextOnAnyThread());
switch (status()) {
case Status::kReadyToParse:
return Parse();
case Status::kReadyToCompile:
return Compile();
return Compile(true);
default:
UNREACHABLE();
}
}
void UnoptimizedCompileJob::PrepareToParseOnMainThread(Isolate* isolate) {
void UnoptimizedCompileJob::PrepareOnMainThread(Isolate* isolate) {
DCHECK_EQ(ThreadId::Current().ToInteger(), main_thread_id_);
DCHECK_EQ(isolate->thread_id().ToInteger(), main_thread_id_);
DCHECK_EQ(status(), Status::kInitial);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToParse);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepare);
if (trace_compiler_dispatcher_jobs_) {
PrintF("UnoptimizedCompileJob[%p]: Preparing to parse\n",
static_cast<void*>(this));
}
HandleScope scope(isolate);
unicode_cache_.reset(new UnicodeCache());
Handle<Script> script(Script::cast(shared_->script()), isolate);
......@@ -267,143 +261,76 @@ void UnoptimizedCompileJob::PrepareToParseOnMainThread(Isolate* isolate) {
Handle<String> name(shared_->name());
parse_info_->set_function_name(
parse_info_->ast_value_factory()->GetString(name));
status_ = Status::kReadyToParse;
status_ = Status::kReadyToCompile;
}
void UnoptimizedCompileJob::Parse() {
DCHECK_EQ(status(), Status::kReadyToParse);
void UnoptimizedCompileJob::Compile(bool on_background_thread) {
DCHECK_EQ(status(), Status::kReadyToCompile);
COMPILER_DISPATCHER_TRACE_SCOPE_WITH_NUM(
tracer_, kParse,
tracer_, kCompile,
parse_info_->end_position() - parse_info_->start_position());
if (trace_compiler_dispatcher_jobs_) {
PrintF("UnoptimizedCompileJob[%p]: Parsing\n", static_cast<void*>(this));
PrintF("UnoptimizedCompileJob[%p]: Compiling\n", static_cast<void*>(this));
}
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref;
parse_info_->set_on_background_thread(on_background_thread);
uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB;
parser_->set_stack_limit(stack_limit);
parse_info_->set_stack_limit(stack_limit);
parser_->ParseOnBackground(parse_info_.get());
status_ = Status::kParsed;
}
void UnoptimizedCompileJob::FinalizeParsingOnMainThread(Isolate* isolate) {
DCHECK_EQ(ThreadId::Current().ToInteger(), main_thread_id_);
DCHECK_EQ(isolate->thread_id().ToInteger(), main_thread_id_);
DCHECK_EQ(status(), Status::kParsed);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeParsing);
if (trace_compiler_dispatcher_jobs_) {
PrintF("UnoptimizedCompileJob[%p]: Finalizing parsing\n",
static_cast<void*>(this));
}
if (!source_.is_null()) {
i::GlobalHandles::Destroy(Handle<Object>::cast(source_).location());
source_ = Handle<String>::null();
}
if (!wrapper_.is_null()) {
i::GlobalHandles::Destroy(Handle<Object>::cast(wrapper_).location());
wrapper_ = Handle<String>::null();
}
Handle<Script> script(Script::cast(shared_->script()), isolate);
parse_info_->set_script(script);
if (!shared_->outer_scope_info()->IsTheHole(isolate) &&
ScopeInfo::cast(shared_->outer_scope_info())->length() > 0) {
Handle<ScopeInfo> outer_scope_info(
handle(ScopeInfo::cast(shared_->outer_scope_info())));
parse_info_->set_outer_scope_info(outer_scope_info);
}
if (parse_info_->literal() == nullptr) {
parse_info_->pending_error_handler()->ReportErrors(
isolate, script, parse_info_->ast_value_factory());
status_ = Status::kFailed;
} else {
parse_info_->literal()->scope()->AttachOuterScopeInfo(parse_info_.get(),
isolate);
status_ = Status::kReadyToAnalyze;
}
parser_->UpdateStatistics(isolate, script);
parse_info_->UpdateStatisticsAfterBackgroundParse(isolate);
parser_->HandleSourceURLComments(isolate, script);
parse_info_->set_unicode_cache(nullptr);
parser_.reset();
unicode_cache_.reset();
}
void UnoptimizedCompileJob::AnalyzeOnMainThread(Isolate* isolate) {
DCHECK_EQ(ThreadId::Current().ToInteger(), main_thread_id_);
DCHECK_EQ(isolate->thread_id().ToInteger(), main_thread_id_);
DCHECK_EQ(status(), Status::kReadyToAnalyze);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kAnalyze);
if (trace_compiler_dispatcher_jobs_) {
PrintF("UnoptimizedCompileJob[%p]: Analyzing\n", static_cast<void*>(this));
// Parser sets error in pending error handler.
status_ = Status::kReportErrors;
return;
}
if (Compiler::Analyze(parse_info_.get())) {
status_ = Status::kAnalyzed;
} else {
status_ = Status::kFailed;
if (!isolate->has_pending_exception()) isolate->StackOverflow();
if (!Compiler::Analyze(parse_info_.get())) {
parse_info_->pending_error_handler()->set_stack_overflow();
status_ = Status::kReportErrors;
return;
}
}
void UnoptimizedCompileJob::PrepareToCompileOnMainThread(Isolate* isolate) {
DCHECK_EQ(ThreadId::Current().ToInteger(), main_thread_id_);
DCHECK_EQ(isolate->thread_id().ToInteger(), main_thread_id_);
DCHECK_EQ(status(), Status::kAnalyzed);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kPrepareToCompile);
compilation_job_.reset(interpreter::Interpreter::NewCompilationJob(
parse_info_.get(), parse_info_->literal(), isolate->allocator()));
parse_info_.get(), parse_info_->literal(), allocator_));
if (!compilation_job_.get()) {
if (!isolate->has_pending_exception()) isolate->StackOverflow();
status_ = Status::kFailed;
parse_info_->pending_error_handler()->set_stack_overflow();
status_ = Status::kReportErrors;
return;
}
status_ = Status::kReadyToCompile;
}
void UnoptimizedCompileJob::Compile() {
DCHECK_EQ(status(), Status::kReadyToCompile);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kCompile);
if (trace_compiler_dispatcher_jobs_) {
PrintF("UnoptimizedCompileJob[%p]: Compiling\n", static_cast<void*>(this));
if (compilation_job_->ExecuteJob() != CompilationJob::SUCCEEDED) {
parse_info_->pending_error_handler()->set_stack_overflow();
status_ = Status::kReportErrors;
return;
}
// Disallowing of handle dereference and heap access dealt with in
// CompilationJob::ExecuteJob.
uintptr_t stack_limit = GetCurrentStackPosition() - max_stack_size_ * KB;
compilation_job_->set_stack_limit(stack_limit);
CompilationJob::Status status = compilation_job_->ExecuteJob();
USE(status);
// Always transition to kCompiled - errors will be reported by
// FinalizeCompilingOnMainThread.
status_ = Status::kCompiled;
}
void UnoptimizedCompileJob::FinalizeCompilingOnMainThread(Isolate* isolate) {
void UnoptimizedCompileJob::FinalizeOnMainThread(Isolate* isolate) {
DCHECK_EQ(ThreadId::Current().ToInteger(), main_thread_id_);
DCHECK_EQ(isolate->thread_id().ToInteger(), main_thread_id_);
DCHECK_EQ(status(), Status::kCompiled);
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalizeCompiling);
DCHECK_NOT_NULL(parse_info_->literal());
DCHECK_NOT_NULL(compilation_job_.get());
COMPILER_DISPATCHER_TRACE_SCOPE(tracer_, kFinalize);
if (trace_compiler_dispatcher_jobs_) {
PrintF("UnoptimizedCompileJob[%p]: Finalizing compiling\n",
static_cast<void*>(this));
}
Handle<Script> script(Script::cast(shared_->script()), isolate);
parse_info_->set_script(script);
parser_->UpdateStatistics(isolate, script);
parse_info_->UpdateStatisticsAfterBackgroundParse(isolate);
parser_->HandleSourceURLComments(isolate, script);
{
HandleScope scope(isolate);
// Internalize ast values onto the heap.
......@@ -421,17 +348,32 @@ void UnoptimizedCompileJob::FinalizeCompilingOnMainThread(Isolate* isolate) {
}
}
compilation_job_.reset();
parse_info_.reset();
ResetDataOnMainThread(isolate);
status_ = Status::kDone;
}
void UnoptimizedCompileJob::ResetOnMainThread(Isolate* isolate) {
void UnoptimizedCompileJob::ReportErrorsOnMainThread(Isolate* isolate) {
DCHECK_EQ(ThreadId::Current().ToInteger(), main_thread_id_);
DCHECK_EQ(isolate->thread_id().ToInteger(), main_thread_id_);
DCHECK_EQ(status(), Status::kReportErrors);
if (trace_compiler_dispatcher_jobs_) {
PrintF("UnoptimizedCompileJob[%p]: Resetting\n", static_cast<void*>(this));
PrintF("UnoptimizedCompileJob[%p]: Reporting Errors\n",
static_cast<void*>(this));
}
Handle<Script> script(Script::cast(shared_->script()), isolate);
parse_info_->pending_error_handler()->ReportErrors(
isolate, script, parse_info_->ast_value_factory());
ResetDataOnMainThread(isolate);
status_ = Status::kFailed;
}
void UnoptimizedCompileJob::ResetDataOnMainThread(Isolate* isolate) {
DCHECK_EQ(ThreadId::Current().ToInteger(), main_thread_id_);
DCHECK_EQ(isolate->thread_id().ToInteger(), main_thread_id_);
compilation_job_.reset();
parser_.reset();
unicode_cache_.reset();
......@@ -449,34 +391,28 @@ void UnoptimizedCompileJob::ResetOnMainThread(Isolate* isolate) {
i::GlobalHandles::Destroy(Handle<Object>::cast(wrapper_).location());
wrapper_ = Handle<String>::null();
}
}
void UnoptimizedCompileJob::ResetOnMainThread(Isolate* isolate) {
if (trace_compiler_dispatcher_jobs_) {
PrintF("UnoptimizedCompileJob[%p]: Resetting\n", static_cast<void*>(this));
}
ResetDataOnMainThread(isolate);
status_ = Status::kInitial;
}
double UnoptimizedCompileJob::EstimateRuntimeOfNextStepInMs() const {
switch (status()) {
case Status::kInitial:
return tracer_->EstimatePrepareToParseInMs();
case Status::kReadyToParse:
return tracer_->EstimateParseInMs(parse_info_->end_position() -
parse_info_->start_position());
case Status::kParsed:
return tracer_->EstimateFinalizeParsingInMs();
case Status::kReadyToAnalyze:
return tracer_->EstimateAnalyzeInMs();
case Status::kAnalyzed:
return tracer_->EstimatePrepareToCompileInMs();
return tracer_->EstimatePrepareInMs();
case Status::kReadyToCompile:
return tracer_->EstimateCompileInMs();
return tracer_->EstimateCompileInMs(parse_info_->end_position() -
parse_info_->start_position());
case Status::kCompiled:
return tracer_->EstimateFinalizeCompilingInMs();
return tracer_->EstimateFinalizeInMs();
case Status::kReportErrors:
case Status::kFailed:
case Status::kDone:
return 0.0;
......
......@@ -34,12 +34,9 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileJob : public CompilerDispatcherJob {
public:
enum class Status {
kInitial,
kReadyToParse,
kParsed,
kReadyToAnalyze,
kAnalyzed,
kReadyToCompile,
kCompiled,
kReportErrors,
kDone,
kFailed,
};
......@@ -68,8 +65,7 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileJob : public CompilerDispatcherJob {
// StepNextOnMainThread and StepNextOnBackgroundThread could be used for the
// next step.
bool CanStepNextOnAnyThread() override {
return status() == Status::kReadyToParse ||
status() == Status::kReadyToCompile;
return status() == Status::kReadyToCompile;
}
// Step the job forward by one state on the main thread.
......@@ -98,6 +94,7 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileJob : public CompilerDispatcherJob {
Status status_;
int main_thread_id_;
CompilerDispatcherTracer* tracer_;
AccountingAllocator* allocator_;
Handle<Context> context_; // Global handle.
Handle<SharedFunctionInfo> shared_; // Global handle.
Handle<String> source_; // Global handle.
......@@ -115,26 +112,20 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileJob : public CompilerDispatcherJob {
bool trace_compiler_dispatcher_jobs_;
// Transition from kInitial to kReadyToParse.
void PrepareToParseOnMainThread(Isolate* isolate);
// Transition from kInitial to kReadyToCompile
void PrepareOnMainThread(Isolate* isolate);
// Transition from kReadyToParse to kParsed.
void Parse();
// Transition from kReadyToCompile to kCompiled (or kReportErrors).
void Compile(bool on_background_thread);
// Transition from kParsed to kReadyToAnalyze (or kFailed).
void FinalizeParsingOnMainThread(Isolate* isolate);
// Transition from kReadyToAnalyze to kAnalyzed (or kFailed).
void AnalyzeOnMainThread(Isolate* isolate);
// Transition from kAnalyzed to kReadyToCompile (or kFailed).
void PrepareToCompileOnMainThread(Isolate* isolate);
// Transition from kCompiled to kDone (or kFailed).
void FinalizeOnMainThread(Isolate* isolate);
// Transition from kReadyToCompile to kCompiled.
void Compile();
// Transition from kReportErrors to kFailed.
void ReportErrorsOnMainThread(Isolate* isolate);
// Transition from kCompiled to kDone (or kFailed).
void FinalizeCompilingOnMainThread(Isolate* isolate);
// Free all resources.
void ResetDataOnMainThread(Isolate* isolate);
DISALLOW_COPY_AND_ASSIGN(UnoptimizedCompileJob);
};
......
......@@ -11,40 +11,36 @@ namespace internal {
TEST(CompilerDispatcherTracerTest, EstimateWithoutSamples) {
CompilerDispatcherTracer tracer(nullptr);
EXPECT_EQ(0.0, tracer.EstimatePrepareToParseInMs());
EXPECT_EQ(1.0, tracer.EstimateParseInMs(0));
EXPECT_EQ(1.0, tracer.EstimateParseInMs(42));
EXPECT_EQ(0.0, tracer.EstimateFinalizeParsingInMs());
EXPECT_EQ(0.0, tracer.EstimatePrepareToCompileInMs());
EXPECT_EQ(0.0, tracer.EstimateCompileInMs());
EXPECT_EQ(0.0, tracer.EstimateCompileInMs());
EXPECT_EQ(0.0, tracer.EstimateFinalizeCompilingInMs());
EXPECT_EQ(0.0, tracer.EstimatePrepareInMs());
EXPECT_EQ(1.0, tracer.EstimateCompileInMs(1));
EXPECT_EQ(1.0, tracer.EstimateCompileInMs(42));
EXPECT_EQ(0.0, tracer.EstimateFinalizeInMs());
}
TEST(CompilerDispatcherTracerTest, Average) {
CompilerDispatcherTracer tracer(nullptr);
EXPECT_EQ(0.0, tracer.EstimatePrepareToParseInMs());
EXPECT_EQ(0.0, tracer.EstimatePrepareInMs());
tracer.RecordPrepareToParse(1.0);
tracer.RecordPrepareToParse(2.0);
tracer.RecordPrepareToParse(3.0);
tracer.RecordPrepare(1.0);
tracer.RecordPrepare(2.0);
tracer.RecordPrepare(3.0);
EXPECT_EQ((1.0 + 2.0 + 3.0) / 3, tracer.EstimatePrepareToParseInMs());
EXPECT_EQ((1.0 + 2.0 + 3.0) / 3, tracer.EstimatePrepareInMs());
}
TEST(CompilerDispatcherTracerTest, SizeBasedAverage) {
CompilerDispatcherTracer tracer(nullptr);
EXPECT_EQ(1.0, tracer.EstimateParseInMs(100));
EXPECT_EQ(1.0, tracer.EstimateCompileInMs(100));
// All three samples parse 100 units/ms.
tracer.RecordParse(1.0, 100);
tracer.RecordParse(2.0, 200);
tracer.RecordParse(3.0, 300);
tracer.RecordCompile(1.0, 100);
tracer.RecordCompile(2.0, 200);
tracer.RecordCompile(3.0, 300);
EXPECT_EQ(1.0, tracer.EstimateParseInMs(100));
EXPECT_EQ(5.0, tracer.EstimateParseInMs(500));
EXPECT_EQ(1.0, tracer.EstimateCompileInMs(100));
EXPECT_EQ(5.0, tracer.EstimateCompileInMs(500));
}
} // namespace internal
......
......@@ -31,9 +31,8 @@
#define STR(x) _STR(x)
#define _SCRIPT(fn, a, b, c) a fn b fn c
#define SCRIPT(a, b, c) _SCRIPT("f" STR(__LINE__), a, b, c)
#define TEST_SCRIPT() \
SCRIPT("function g() { var y = 1; function ", \
"(x) { return x * y }; return ", "; } g();")
#define TEST_SCRIPT() \
"function f" STR(__LINE__) "(x, y) { return x * y }; f" STR(__LINE__) ";"
namespace v8 {
namespace internal {
......@@ -335,9 +334,8 @@ TEST_F(CompilerDispatcherTest, FinishAllNow) {
std::stringstream ss;
ss << 'f' << STR(__LINE__) << '_' << i;
std::string func_name = ss.str();
std::string script("function g() { function " + func_name +
"(x) { var a = 'x'; }; return " + func_name +
"; } g();");
std::string script("function f" + func_name + "(x, y) { return x * y }; f" +
func_name + ";");
f[i] = RunJS<JSFunction>(script.c_str());
shared[i] = Handle<SharedFunctionInfo>(f[i]->shared(), i_isolate());
ASSERT_FALSE(shared[i]->is_compiled());
......@@ -400,7 +398,7 @@ 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_EQ(UnoptimizedCompileJob::Status::kReadyToParse,
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
// Now grant a lot of idle time and freeze time.
......@@ -416,12 +414,12 @@ TEST_F(CompilerDispatcherTest, IdleTaskException) {
CompilerDispatcher dispatcher(i_isolate(), &platform, 50);
std::string func_name("f" STR(__LINE__));
std::string script("function g() { function " + func_name + "(x) { var a = ");
std::string script("function " + func_name + "(x) { var a = ");
for (int i = 0; i < 500; i++) {
// Alternate + and - to avoid n-ary operation nodes.
script += "'x' + 'x' - ";
}
script += " 'x'; }; return " + func_name + "; } g();";
script += " 'x'; }; " + func_name + ";";
Handle<JSFunction> f = RunJS<JSFunction>(script.c_str());
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
......@@ -456,7 +454,7 @@ TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) {
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0);
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
......@@ -499,7 +497,7 @@ TEST_F(CompilerDispatcherTest, FinishNowWithBackgroundTask) {
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0);
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
......@@ -552,12 +550,12 @@ TEST_F(CompilerDispatcherTest, FinishNowException) {
CompilerDispatcher dispatcher(i_isolate(), &platform, 50);
std::string func_name("f" STR(__LINE__));
std::string script("function g() { function " + func_name + "(x) { var a = ");
std::string script("function " + func_name + "(x) { var a = ");
for (int i = 0; i < 500; i++) {
// Alternate + and - to avoid n-ary operation nodes.
script += "'x' + 'x' - ";
}
script += " 'x'; }; return " + func_name + "; } g();";
script += " 'x'; }; " + func_name + ";";
Handle<JSFunction> f = RunJS<JSFunction>(script.c_str());
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
......@@ -593,7 +591,7 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllPendingBackgroundTask) {
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0);
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
......@@ -639,7 +637,7 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllRunningBackgroundTask) {
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0);
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
......@@ -715,7 +713,7 @@ TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) {
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0);
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
......@@ -884,7 +882,7 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStep) {
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToParse,
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(platform.IdleTaskPending());
......@@ -898,7 +896,7 @@ TEST_F(CompilerDispatcherTest, CompileLazyFinishesDispatcherJob) {
// enqueued functions.
CompilerDispatcher* dispatcher = i_isolate()->compiler_dispatcher();
const char script[] = TEST_SCRIPT();
const char script[] = "function lazy() { return 42; }; lazy;";
Handle<JSFunction> f = RunJS<JSFunction>(script);
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
......@@ -909,7 +907,7 @@ TEST_F(CompilerDispatcherTest, CompileLazyFinishesDispatcherJob) {
// Now force the function to run and ensure CompileLazy finished and dequeues
// it from the dispatcher.
RunJS("g()();");
RunJS("lazy();");
ASSERT_TRUE(shared->is_compiled());
ASSERT_FALSE(dispatcher->IsEnqueued(shared));
}
......@@ -950,12 +948,12 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepTwice) {
ASSERT_FALSE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared));
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToParse,
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
// EnqueueAndStep of the same function again (shouldn't step the job.
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared));
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToParse,
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
GetUnoptimizedJobStatus(dispatcher.jobs_.begin()->second));
ASSERT_TRUE(platform.IdleTaskPending());
......@@ -988,7 +986,7 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) {
// Make compiling super expensive, and advance job as much as possible on the
// foreground thread.
dispatcher.tracer_->RecordCompile(50000.0);
dispatcher.tracer_->RecordCompile(50000.0, 1);
platform.RunIdleTask(10.0, 0.0);
ASSERT_EQ(dispatcher.jobs_.size(), 2u);
ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToCompile,
......@@ -1023,5 +1021,11 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) {
ASSERT_FALSE(platform.IdleTaskPending());
}
#undef _STR
#undef STR
#undef _SCRIPT
#undef SCRIPT
#undef TEST_SCRIPT
} // namespace internal
} // namespace v8
......@@ -84,18 +84,6 @@ TEST_F(UnoptimizedCompileJobTest, StateTransitions) {
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToParse, job);
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kParsed, job);
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToAnalyze, job);
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kAnalyzed, job);
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToCompile, job);
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
......@@ -128,39 +116,6 @@ TEST_F(UnoptimizedCompileJobTest, SyntaxError) {
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
}
TEST_F(UnoptimizedCompileJobTest, ScopeChain) {
const char script[] =
"function g() { var y = 1; function f(x) { return x * y }; return f; } "
"g();";
Handle<JSFunction> f = RunJS<JSFunction>(script);
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kReadyToCompile, job);
Variable* var = LookupVariableByName(job.get(), "x");
ASSERT_TRUE(var);
ASSERT_TRUE(var->IsParameter());
var = LookupVariableByName(job.get(), "y");
ASSERT_TRUE(var);
ASSERT_TRUE(var->IsContextSlot());
job->ResetOnMainThread(isolate());
ASSERT_JOB_STATUS(UnoptimizedCompileJob::Status::kInitial, job);
}
TEST_F(UnoptimizedCompileJobTest, CompileAndRun) {
const char script[] =
"function g() {\n"
......@@ -175,14 +130,6 @@ TEST_F(UnoptimizedCompileJobTest, CompileAndRun) {
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
......@@ -213,8 +160,6 @@ TEST_F(UnoptimizedCompileJobTest, CompileFailureToAnalyse) {
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), &script),
100));
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
......@@ -241,14 +186,6 @@ TEST_F(UnoptimizedCompileJobTest, CompileFailureToFinalize) {
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), &script),
50));
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
......@@ -296,14 +233,6 @@ TEST_F(UnoptimizedCompileJobTest, CompileOnBackgroundThread) {
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
base::Semaphore semaphore(0);
CompileTask* background_task = new CompileTask(job.get(), &semaphore);
......@@ -321,27 +250,16 @@ TEST_F(UnoptimizedCompileJobTest, CompileOnBackgroundThread) {
TEST_F(UnoptimizedCompileJobTest, LazyInnerFunctions) {
const char script[] =
"function g() {\n"
" f = function() {\n"
" e = (function() { return 42; });\n"
" return e;\n"
" };\n"
" return f;\n"
"}\n"
"g();";
"f = function() {\n"
" e = (function() { return 42; });\n"
" return e;\n"
"};\n"
"f;";
Handle<JSFunction> f = RunJS<JSFunction>(script);
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
ASSERT_FALSE(job->IsFailed());
job->StepNextOnMainThread(isolate());
......
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