Commit 53c11006 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Compiler] Avoid blocking on inner function parallel compilation.

Don't block on inner function compilation before competing outer function
compilation. Instead wait for the compilation to complete when the function
is called.

BUG=v8:5203

Review-Url: https://codereview.chromium.org/2686673002
Cr-Commit-Position: refs/heads/master@{#43116}
parent 2bfd8a7c
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "src/parsing/scanner-character-streams.h" #include "src/parsing/scanner-character-streams.h"
#include "src/unicode-cache.h" #include "src/unicode-cache.h"
#include "src/utils.h" #include "src/utils.h"
#include "src/zone/zone.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -75,8 +74,8 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, ...@@ -75,8 +74,8 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
isolate_->global_handles()->Create(*shared))), isolate_->global_handles()->Create(*shared))),
max_stack_size_(max_stack_size), max_stack_size_(max_stack_size),
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) { trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
DCHECK(!shared_->is_toplevel());
HandleScope scope(isolate_); HandleScope scope(isolate_);
DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_));
Handle<Script> script(Script::cast(shared_->script()), isolate_); Handle<Script> script(Script::cast(shared_->script()), isolate_);
Handle<String> source(String::cast(script->source()), isolate_); Handle<String> source(String::cast(script->source()), isolate_);
if (trace_compiler_dispatcher_jobs_) { if (trace_compiler_dispatcher_jobs_) {
...@@ -87,7 +86,7 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate, ...@@ -87,7 +86,7 @@ CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
} }
CompilerDispatcherJob::CompilerDispatcherJob( CompilerDispatcherJob::CompilerDispatcherJob(
Isolate* isolate, CompilerDispatcherTracer* tracer, Isolate* isolate, CompilerDispatcherTracer* tracer, Handle<Script> script,
Handle<SharedFunctionInfo> shared, FunctionLiteral* literal, Handle<SharedFunctionInfo> shared, FunctionLiteral* literal,
std::shared_ptr<Zone> parse_zone, std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles, std::shared_ptr<DeferredHandles> parse_handles,
...@@ -106,6 +105,7 @@ CompilerDispatcherJob::CompilerDispatcherJob( ...@@ -106,6 +105,7 @@ CompilerDispatcherJob::CompilerDispatcherJob(
Handle<JSFunction>::null())), Handle<JSFunction>::null())),
trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) { trace_compiler_dispatcher_jobs_(FLAG_trace_compiler_dispatcher_jobs) {
parse_info_->set_literal(literal); parse_info_->set_literal(literal);
parse_info_->set_script(script);
parse_info_->set_deferred_handles(parse_handles); parse_info_->set_deferred_handles(parse_handles);
compile_info_->set_deferred_handles(compile_handles); compile_info_->set_deferred_handles(compile_handles);
...@@ -224,12 +224,12 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() { ...@@ -224,12 +224,12 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() {
parse_info_->set_function_literal_id(shared_->function_literal_id()); parse_info_->set_function_literal_id(shared_->function_literal_id());
parser_.reset(new Parser(parse_info_.get())); parser_.reset(new Parser(parse_info_.get()));
Handle<ScopeInfo> outer_scope_info( MaybeHandle<ScopeInfo> outer_scope_info;
handle(ScopeInfo::cast(shared_->outer_scope_info()))); if (!shared_->outer_scope_info()->IsTheHole(isolate_) &&
parser_->DeserializeScopeChain(parse_info_.get(), ScopeInfo::cast(shared_->outer_scope_info())->length() > 0) {
outer_scope_info->length() > 0 outer_scope_info = handle(ScopeInfo::cast(shared_->outer_scope_info()));
? MaybeHandle<ScopeInfo>(outer_scope_info) }
: MaybeHandle<ScopeInfo>()); parser_->DeserializeScopeChain(parse_info_.get(), outer_scope_info);
Handle<String> name(String::cast(shared_->name())); Handle<String> name(String::cast(shared_->name()));
parse_info_->set_function_name( parse_info_->set_function_name(
...@@ -295,9 +295,11 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() { ...@@ -295,9 +295,11 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
DeferredHandleScope scope(isolate_); DeferredHandleScope scope(isolate_);
{ {
parse_info_->ReopenHandlesInNewHandleScope(); parse_info_->ReopenHandlesInNewHandleScope();
Handle<ScopeInfo> outer_scope_info(
handle(ScopeInfo::cast(shared_->outer_scope_info()))); if (!shared_->outer_scope_info()->IsTheHole(isolate_) &&
if (outer_scope_info->length() > 0) { 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); parse_info_->set_outer_scope_info(outer_scope_info);
} }
parse_info_->set_shared_info(shared_); parse_info_->set_shared_info(shared_);
......
...@@ -50,6 +50,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob { ...@@ -50,6 +50,7 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
size_t max_stack_size); size_t max_stack_size);
// Creates a CompilerDispatcherJob in the analyzed state. // Creates a CompilerDispatcherJob in the analyzed state.
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer, CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
Handle<Script> script,
Handle<SharedFunctionInfo> shared, Handle<SharedFunctionInfo> shared,
FunctionLiteral* literal, FunctionLiteral* literal,
std::shared_ptr<Zone> parse_zone, std::shared_ptr<Zone> parse_zone,
......
...@@ -293,8 +293,8 @@ bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) { ...@@ -293,8 +293,8 @@ bool CompilerDispatcher::EnqueueAndStep(Handle<SharedFunctionInfo> function) {
} }
bool CompilerDispatcher::Enqueue( bool CompilerDispatcher::Enqueue(
Handle<SharedFunctionInfo> function, FunctionLiteral* literal, Handle<Script> script, Handle<SharedFunctionInfo> function,
std::shared_ptr<Zone> parse_zone, FunctionLiteral* literal, std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles, std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles) { std::shared_ptr<DeferredHandles> compile_handles) {
if (!CanEnqueue(function)) return false; if (!CanEnqueue(function)) return false;
...@@ -307,8 +307,8 @@ bool CompilerDispatcher::Enqueue( ...@@ -307,8 +307,8 @@ bool CompilerDispatcher::Enqueue(
} }
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
isolate_, tracer_.get(), function, literal, parse_zone, parse_handles, isolate_, tracer_.get(), script, function, literal, parse_zone,
compile_handles, max_stack_size_)); parse_handles, compile_handles, max_stack_size_));
std::pair<int, int> key(Script::cast(function->script())->id(), std::pair<int, int> key(Script::cast(function->script())->id(),
function->function_literal_id()); function->function_literal_id());
jobs_.insert(std::make_pair(key, std::move(job))); jobs_.insert(std::make_pair(key, std::move(job)));
...@@ -317,11 +317,12 @@ bool CompilerDispatcher::Enqueue( ...@@ -317,11 +317,12 @@ bool CompilerDispatcher::Enqueue(
} }
bool CompilerDispatcher::EnqueueAndStep( bool CompilerDispatcher::EnqueueAndStep(
Handle<SharedFunctionInfo> function, FunctionLiteral* literal, Handle<Script> script, Handle<SharedFunctionInfo> function,
std::shared_ptr<Zone> parse_zone, FunctionLiteral* literal, std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles, std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles) { std::shared_ptr<DeferredHandles> compile_handles) {
if (!Enqueue(function, literal, parse_zone, parse_handles, compile_handles)) { if (!Enqueue(script, function, literal, parse_zone, parse_handles,
compile_handles)) {
return false; return false;
} }
...@@ -345,6 +346,9 @@ bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const { ...@@ -345,6 +346,9 @@ bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const {
void CompilerDispatcher::WaitForJobIfRunningOnBackground( void CompilerDispatcher::WaitForJobIfRunningOnBackground(
CompilerDispatcherJob* job) { CompilerDispatcherJob* job) {
RuntimeCallTimerScope runtimeTimer(
isolate_, &RuntimeCallStats::CompileWaitForDispatcher);
base::LockGuard<base::Mutex> lock(&mutex_); base::LockGuard<base::Mutex> lock(&mutex_);
if (running_background_jobs_.find(job) == running_background_jobs_.end()) { if (running_background_jobs_.find(job) == running_background_jobs_.end()) {
pending_background_jobs_.erase(job); pending_background_jobs_.erase(job);
...@@ -359,16 +363,6 @@ void CompilerDispatcher::WaitForJobIfRunningOnBackground( ...@@ -359,16 +363,6 @@ 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());
...@@ -379,7 +373,12 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { ...@@ -379,7 +373,12 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
PrintF(" now\n"); PrintF(" now\n");
} }
bool result = FinishNow(job->second.get()); WaitForJobIfRunningOnBackground(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 ");
...@@ -388,6 +387,7 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { ...@@ -388,6 +387,7 @@ 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_);
...@@ -396,30 +396,6 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { ...@@ -396,30 +396,6 @@ 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;
......
...@@ -84,15 +84,16 @@ class V8_EXPORT_PRIVATE CompilerDispatcher { ...@@ -84,15 +84,16 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
// Enqueue a job for compilation. Function must have already been parsed and // 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. // analyzed and be ready for compilation. Returns true if a job was enqueued.
bool Enqueue(Handle<SharedFunctionInfo> function, FunctionLiteral* literal, bool Enqueue(Handle<Script> script, Handle<SharedFunctionInfo> function,
std::shared_ptr<Zone> parse_zone, FunctionLiteral* literal, std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles, std::shared_ptr<DeferredHandles> parse_handles,
std::shared_ptr<DeferredHandles> compile_handles); std::shared_ptr<DeferredHandles> compile_handles);
// Like Enqueue, but also advances the job so that it can potentially // Like Enqueue, but also advances the job so that it can potentially
// continue running on a background thread (if at all possible). Returns // continue running on a background thread (if at all possible). Returns
// true if the job was enqueued. // true if the job was enqueued.
bool EnqueueAndStep(Handle<SharedFunctionInfo> function, bool EnqueueAndStep(Handle<Script> script,
Handle<SharedFunctionInfo> function,
FunctionLiteral* literal, FunctionLiteral* literal,
std::shared_ptr<Zone> parse_zone, std::shared_ptr<Zone> parse_zone,
std::shared_ptr<DeferredHandles> parse_handles, std::shared_ptr<DeferredHandles> parse_handles,
...@@ -105,10 +106,6 @@ class V8_EXPORT_PRIVATE CompilerDispatcher { ...@@ -105,10 +106,6 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
// possible). Returns true if the compile job was successful. // 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);
...@@ -141,7 +138,6 @@ class V8_EXPORT_PRIVATE CompilerDispatcher { ...@@ -141,7 +138,6 @@ class V8_EXPORT_PRIVATE CompilerDispatcher {
void AbortInactiveJobs(); void AbortInactiveJobs();
bool CanEnqueue(Handle<SharedFunctionInfo> function); 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();
......
...@@ -538,7 +538,8 @@ bool CompileUnoptimizedInnerFunctions( ...@@ -538,7 +538,8 @@ bool CompileUnoptimizedInnerFunctions(
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher(); CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
if (UseCompilerDispatcher(inner_function_mode, dispatcher, literal->scope(), if (UseCompilerDispatcher(inner_function_mode, dispatcher, literal->scope(),
shared, is_debug, will_serialize) && shared, is_debug, will_serialize) &&
dispatcher->EnqueueAndStep(shared, literal, parse_zone, dispatcher->EnqueueAndStep(outer_info->script(), shared, literal,
parse_zone,
outer_info->parse_info()->deferred_handles(), outer_info->parse_info()->deferred_handles(),
outer_info->deferred_handles())) { outer_info->deferred_handles())) {
// If we have successfully queued up the function for compilation on the // If we have successfully queued up the function for compilation on the
...@@ -620,17 +621,6 @@ bool CompileUnoptimizedCode(CompilationInfo* info, ...@@ -620,17 +621,6 @@ 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;
} }
...@@ -1249,13 +1239,25 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) { ...@@ -1249,13 +1239,25 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) {
Isolate* isolate = function->GetIsolate(); Isolate* isolate = function->GetIsolate();
DCHECK(AllowCompilation::IsAllowed(isolate)); DCHECK(AllowCompilation::IsAllowed(isolate));
// Start a compilation. CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
Handle<Code> code; Handle<Code> code;
if (!GetLazyCode(function).ToHandle(&code)) { if (dispatcher->IsEnqueued(shared)) {
if (flag == CLEAR_EXCEPTION) { if (!dispatcher->FinishNow(shared)) {
isolate->clear_pending_exception(); if (flag == CLEAR_EXCEPTION) {
isolate->clear_pending_exception();
}
return false;
}
code = handle(shared->code(), isolate);
} else {
// Start a compilation.
if (!GetLazyCode(function).ToHandle(&code)) {
if (flag == CLEAR_EXCEPTION) {
isolate->clear_pending_exception();
}
return false;
} }
return false;
} }
// Install code on closure. // Install code on closure.
...@@ -1378,7 +1380,10 @@ MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) { ...@@ -1378,7 +1380,10 @@ MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
bool Compiler::EnsureBytecode(CompilationInfo* info) { bool Compiler::EnsureBytecode(CompilationInfo* info) {
if (!info->shared_info()->is_compiled()) { if (!info->shared_info()->is_compiled()) {
if (GetUnoptimizedCode(info, Compiler::NOT_CONCURRENT).is_null()) { CompilerDispatcher* dispatcher = info->isolate()->compiler_dispatcher();
if (dispatcher->IsEnqueued(info->shared_info())) {
if (!dispatcher->FinishNow(info->shared_info())) return false;
} else if (GetUnoptimizedCode(info, Compiler::NOT_CONCURRENT).is_null()) {
return false; return false;
} }
} }
...@@ -1396,6 +1401,12 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { ...@@ -1396,6 +1401,12 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
DCHECK_NOT_NULL(info->literal()); DCHECK_NOT_NULL(info->literal());
DCHECK_NOT_NULL(info->scope()); DCHECK_NOT_NULL(info->scope());
Handle<SharedFunctionInfo> shared = info->shared_info(); Handle<SharedFunctionInfo> shared = info->shared_info();
CompilerDispatcher* dispatcher = info->isolate()->compiler_dispatcher();
if (dispatcher->IsEnqueued(shared)) {
if (!dispatcher->FinishNow(shared)) return false;
}
if (!shared->has_deoptimization_support()) { if (!shared->has_deoptimization_support()) {
Zone compile_zone(info->isolate()->allocator(), ZONE_NAME); Zone compile_zone(info->isolate()->allocator(), ZONE_NAME);
CompilationInfo unoptimized(&compile_zone, info->parse_info(), CompilationInfo unoptimized(&compile_zone, info->parse_info(),
......
...@@ -843,18 +843,19 @@ TEST_F(CompilerDispatcherTest, EnqueueParsed) { ...@@ -843,18 +843,19 @@ TEST_F(CompilerDispatcherTest, EnqueueParsed) {
MockPlatform platform; MockPlatform platform;
CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
const char script[] = const char source[] =
"function g() { var y = 1; function f17(x) { return x * y }; return f17; " "function g() { var y = 1; function f17(x) { return x * y }; return f17; "
"} g();"; "} g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script)); Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), source));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
Handle<Script> script(Script::cast(shared->script()), i_isolate());
ParseInfo parse_info(shared); ParseInfo parse_info(shared);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info)); ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
std::shared_ptr<DeferredHandles> handles; std::shared_ptr<DeferredHandles> handles;
ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.Enqueue(shared, parse_info.literal(), ASSERT_TRUE(dispatcher.Enqueue(script, shared, parse_info.literal(),
parse_info.zone_shared(), handles, handles)); parse_info.zone_shared(), handles, handles));
ASSERT_TRUE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(dispatcher.IsEnqueued(shared));
...@@ -870,18 +871,19 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) { ...@@ -870,18 +871,19 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) {
MockPlatform platform; MockPlatform platform;
CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
const char script[] = const char source[] =
"function g() { var y = 1; function f18(x) { return x * y }; return f18; " "function g() { var y = 1; function f18(x) { return x * y }; return f18; "
"} g();"; "} g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script)); Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), source));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
Handle<Script> script(Script::cast(shared->script()), i_isolate());
ParseInfo parse_info(shared); ParseInfo parse_info(shared);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info)); ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
std::shared_ptr<DeferredHandles> handles; std::shared_ptr<DeferredHandles> handles;
ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(dispatcher.IsEnqueued(shared));
ASSERT_TRUE(dispatcher.EnqueueAndStep(shared, parse_info.literal(), ASSERT_TRUE(dispatcher.EnqueueAndStep(script, shared, parse_info.literal(),
parse_info.zone_shared(), handles, parse_info.zone_shared(), handles,
handles)); handles));
ASSERT_TRUE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(dispatcher.IsEnqueued(shared));
...@@ -895,55 +897,16 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) { ...@@ -895,55 +897,16 @@ TEST_F(CompilerDispatcherTest, EnqueueAndStepParsed) {
platform.ClearBackgroundTasks(); 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.
ParseInfo parse_info(shared1);
ASSERT_TRUE(Compiler::ParseAndAnalyze(&parse_info));
std::shared_ptr<DeferredHandles> handles;
ASSERT_TRUE(dispatcher.Enqueue(shared1, parse_info.literal(),
parse_info.zone_shared(), handles, handles));
// 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();
}
TEST_F(CompilerDispatcherTest, CompileParsedOutOfScope) { TEST_F(CompilerDispatcherTest, CompileParsedOutOfScope) {
MockPlatform platform; MockPlatform platform;
CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
const char script[] = const char source[] =
"function g() { var y = 1; function f20(x) { return x + y }; return f20; " "function g() { var y = 1; function f20(x) { return x + y }; return f20; "
"} g();"; "} g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script)); Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), source));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
Handle<Script> script(Script::cast(shared->script()), i_isolate());
{ {
HandleScope scope(i_isolate()); // Create handles scope for parsing. HandleScope scope(i_isolate()); // Create handles scope for parsing.
...@@ -959,7 +922,7 @@ TEST_F(CompilerDispatcherTest, CompileParsedOutOfScope) { ...@@ -959,7 +922,7 @@ TEST_F(CompilerDispatcherTest, CompileParsedOutOfScope) {
ASSERT_FALSE(platform.IdleTaskPending()); ASSERT_FALSE(platform.IdleTaskPending());
ASSERT_TRUE(dispatcher.Enqueue( ASSERT_TRUE(dispatcher.Enqueue(
shared, parse_info.literal(), parse_info.zone_shared(), script, shared, parse_info.literal(), parse_info.zone_shared(),
parse_info.deferred_handles(), compilation_handles)); parse_info.deferred_handles(), compilation_handles));
ASSERT_TRUE(platform.IdleTaskPending()); ASSERT_TRUE(platform.IdleTaskPending());
} }
...@@ -1033,7 +996,7 @@ TEST_F(CompilerDispatcherTestWithoutContext, CompileExtensionWithoutContext) { ...@@ -1033,7 +996,7 @@ TEST_F(CompilerDispatcherTestWithoutContext, CompileExtensionWithoutContext) {
ASSERT_FALSE(platform.IdleTaskPending()); ASSERT_FALSE(platform.IdleTaskPending());
ASSERT_TRUE(dispatcher.Enqueue( ASSERT_TRUE(dispatcher.Enqueue(
shared, parse_info.literal(), parse_info.zone_shared(), script, shared, parse_info.literal(), parse_info.zone_shared(),
parse_info.deferred_handles(), compilation_handles)); parse_info.deferred_handles(), compilation_handles));
ASSERT_TRUE(platform.IdleTaskPending()); ASSERT_TRUE(platform.IdleTaskPending());
} }
...@@ -1047,5 +1010,55 @@ TEST_F(CompilerDispatcherTestWithoutContext, CompileExtensionWithoutContext) { ...@@ -1047,5 +1010,55 @@ TEST_F(CompilerDispatcherTestWithoutContext, CompileExtensionWithoutContext) {
ASSERT_TRUE(shared->is_compiled()); ASSERT_TRUE(shared->is_compiled());
} }
TEST_F(CompilerDispatcherTest, CompileLazyFinishesDispatcherJob) {
// Use the real dispatcher so that CompileLazy checks the same one for
// enqueued functions.
CompilerDispatcher* dispatcher = i_isolate()->compiler_dispatcher();
const char source[] =
"function g() { var y = 1; function f16(x) { return x * y }; return f16; "
"} g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), source));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
ASSERT_FALSE(shared->is_compiled());
ASSERT_FALSE(dispatcher->IsEnqueued(shared));
ASSERT_TRUE(dispatcher->Enqueue(shared));
ASSERT_TRUE(dispatcher->IsEnqueued(shared));
// Now force the function to run and ensure CompileLazy finished and dequeues
// it from the dispatcher.
RunJS(isolate(), "g()();");
ASSERT_TRUE(shared->is_compiled());
ASSERT_FALSE(dispatcher->IsEnqueued(shared));
}
TEST_F(CompilerDispatcherTest, CompileLazy2FinishesDispatcherJob) {
// Use the real dispatcher so that CompileLazy checks the same one for
// enqueued functions.
CompilerDispatcher* dispatcher = i_isolate()->compiler_dispatcher();
const char source2[] = "function lazy2() { return 42; }; lazy2;";
Handle<JSFunction> lazy2 =
Handle<JSFunction>::cast(RunJS(isolate(), source2));
Handle<SharedFunctionInfo> shared2(lazy2->shared(), i_isolate());
ASSERT_FALSE(shared2->is_compiled());
const char source1[] = "function lazy1() { return lazy2(); }; lazy1;";
Handle<JSFunction> lazy1 =
Handle<JSFunction>::cast(RunJS(isolate(), source1));
Handle<SharedFunctionInfo> shared1(lazy1->shared(), i_isolate());
ASSERT_FALSE(shared1->is_compiled());
ASSERT_TRUE(dispatcher->Enqueue(shared1));
ASSERT_TRUE(dispatcher->Enqueue(shared2));
RunJS(isolate(), "lazy1();");
ASSERT_TRUE(shared1->is_compiled());
ASSERT_TRUE(shared2->is_compiled());
ASSERT_FALSE(dispatcher->IsEnqueued(shared1));
ASSERT_FALSE(dispatcher->IsEnqueued(shared2));
}
} // 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