Commit 1bdf908d authored by jochen's avatar jochen Committed by Commit bot

Add a basic compiler dispatcher

It doesn't schedule steps yet, but there are tests.

BUG=v8:5215
R=rmcilroy@chromium.org,marja@chromium.org

Review-Url: https://codereview.chromium.org/2558293004
Cr-Commit-Position: refs/heads/master@{#41650}
parent 02f917f7
......@@ -1001,6 +1001,8 @@ v8_source_set("v8_base") {
"src/compiler-dispatcher/compiler-dispatcher-job.h",
"src/compiler-dispatcher/compiler-dispatcher-tracer.cc",
"src/compiler-dispatcher/compiler-dispatcher-tracer.h",
"src/compiler-dispatcher/compiler-dispatcher.cc",
"src/compiler-dispatcher/compiler-dispatcher.h",
"src/compiler-dispatcher/optimizing-compile-dispatcher.cc",
"src/compiler-dispatcher/optimizing-compile-dispatcher.h",
"src/compiler.cc",
......
......@@ -21,10 +21,11 @@ namespace v8 {
namespace internal {
CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared,
size_t max_stack_size)
: isolate_(isolate),
tracer_(isolate_->compiler_dispatcher_tracer()),
tracer_(tracer),
shared_(Handle<SharedFunctionInfo>::cast(
isolate_->global_handles()->Create(*shared))),
max_stack_size_(max_stack_size),
......@@ -44,6 +45,11 @@ CompilerDispatcherJob::~CompilerDispatcherJob() {
i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location());
}
bool CompilerDispatcherJob::IsAssociatedWith(
Handle<SharedFunctionInfo> shared) const {
return *shared_ == *shared;
}
void CompilerDispatcherJob::PrepareToParseOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kInitial);
......
......@@ -40,7 +40,8 @@ enum class CompileJobStatus {
class V8_EXPORT_PRIVATE CompilerDispatcherJob {
public:
CompilerDispatcherJob(Isolate* isolate, Handle<SharedFunctionInfo> shared,
CompilerDispatcherJob(Isolate* isolate, CompilerDispatcherTracer* tracer,
Handle<SharedFunctionInfo> shared,
size_t max_stack_size);
~CompilerDispatcherJob();
......@@ -54,6 +55,10 @@ class V8_EXPORT_PRIVATE CompilerDispatcherJob {
return can_compile_on_background_thread_;
}
// Returns true if this CompilerDispatcherJob was created for the given
// function.
bool IsAssociatedWith(Handle<SharedFunctionInfo> shared) const;
// Transition from kInitial to kReadyToParse.
void PrepareToParseOnMainThread();
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler-dispatcher/compiler-dispatcher.h"
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
namespace {
bool DoNextStepOnMainThread(CompilerDispatcherJob* job) {
switch (job->status()) {
case CompileJobStatus::kInitial:
job->PrepareToParseOnMainThread();
break;
case CompileJobStatus::kReadyToParse:
job->Parse();
break;
case CompileJobStatus::kParsed:
job->FinalizeParsingOnMainThread();
break;
case CompileJobStatus::kReadyToAnalyse:
job->PrepareToCompileOnMainThread();
break;
case CompileJobStatus::kReadyToCompile:
job->Compile();
break;
case CompileJobStatus::kCompiled:
job->FinalizeCompilingOnMainThread();
break;
case CompileJobStatus::kFailed:
case CompileJobStatus::kDone:
break;
}
return job->status() != CompileJobStatus::kFailed;
}
bool IsFinished(CompilerDispatcherJob* job) {
return job->status() == CompileJobStatus::kDone ||
job->status() == CompileJobStatus::kFailed;
}
} // namespace
CompilerDispatcher::CompilerDispatcher(Isolate* isolate, size_t max_stack_size)
: isolate_(isolate),
max_stack_size_(max_stack_size),
tracer_(new CompilerDispatcherTracer(isolate_)) {}
CompilerDispatcher::~CompilerDispatcher() {}
bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
// We only handle functions (no eval / top-level code / wasm) that are
// attached to a script.
if (!function->script()->IsScript() || !function->is_function() ||
function->asm_function() || function->native()) {
return false;
}
if (IsEnqueued(function)) return true;
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
isolate_, tracer_.get(), function, 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)));
return true;
}
bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const {
return GetJobFor(function) != jobs_.end();
}
bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
JobMap::const_iterator job = GetJobFor(function);
CHECK(job != jobs_.end());
// TODO(jochen): Check if there's an in-flight background task working on this
// job.
while (!IsFinished(job->second.get())) {
DoNextStepOnMainThread(job->second.get());
}
bool result = job->second->status() != CompileJobStatus::kFailed;
jobs_.erase(job);
return result;
}
void CompilerDispatcher::Abort(Handle<SharedFunctionInfo> function,
BlockingBehavior blocking) {
USE(blocking);
JobMap::const_iterator job = GetJobFor(function);
CHECK(job != jobs_.end());
// TODO(jochen): Check if there's an in-flight background task working on this
// job.
jobs_.erase(job);
}
void CompilerDispatcher::AbortAll(BlockingBehavior blocking) {
USE(blocking);
// TODO(jochen): Check if there's an in-flight background task working on this
// job.
jobs_.clear();
}
CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor(
Handle<SharedFunctionInfo> shared) const {
if (!shared->script()->IsScript()) return jobs_.end();
std::pair<int, int> key(Script::cast(shared->script())->id(),
shared->function_literal_id());
auto range = jobs_.equal_range(key);
for (auto job = range.first; job != range.second; ++job) {
if (job->second->IsAssociatedWith(shared)) return job;
}
return jobs_.end();
}
} // namespace internal
} // namespace v8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_H_
#define V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_H_
#include <map>
#include <memory>
#include <utility>
#include "src/base/macros.h"
#include "src/globals.h"
namespace v8 {
namespace internal {
class CompilerDispatcherJob;
class CompilerDispatcherTracer;
class Isolate;
class SharedFunctionInfo;
template <typename T>
class Handle;
class V8_EXPORT_PRIVATE CompilerDispatcher {
public:
enum class BlockingBehavior { kBlock, kDontBlock };
CompilerDispatcher(Isolate* isolate, size_t max_stack_size);
~CompilerDispatcher();
// Returns true if a job was enqueued.
bool Enqueue(Handle<SharedFunctionInfo> function);
// 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.
bool FinishNow(Handle<SharedFunctionInfo> function);
// Aborts a given job. Blocks if requested.
void Abort(Handle<SharedFunctionInfo> function, BlockingBehavior blocking);
// Aborts all jobs. Blocks if requested.
void AbortAll(BlockingBehavior blocking);
private:
typedef std::multimap<std::pair<int, int>,
std::unique_ptr<CompilerDispatcherJob>>
JobMap;
JobMap::const_iterator GetJobFor(Handle<SharedFunctionInfo> shared) const;
Isolate* isolate_;
size_t max_stack_size_;
std::unique_ptr<CompilerDispatcherTracer> tracer_;
// Mapping from (script id, function literal id) to job. We use a multimap,
// as script id is not necessarily unique.
JobMap jobs_;
DISALLOW_COPY_AND_ASSIGN(CompilerDispatcher);
};
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_DISPATCHER_COMPILER_DISPATCHER_H_
......@@ -20,7 +20,7 @@
#include "src/codegen.h"
#include "src/compilation-cache.h"
#include "src/compilation-statistics.h"
#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
#include "src/compiler-dispatcher/compiler-dispatcher.h"
#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
#include "src/crankshaft/hydrogen.h"
#include "src/debug/debug.h"
......@@ -2292,6 +2292,10 @@ void Isolate::Deinit() {
delete heap_profiler_;
heap_profiler_ = NULL;
compiler_dispatcher_->AbortAll(CompilerDispatcher::BlockingBehavior::kBlock);
delete compiler_dispatcher_;
compiler_dispatcher_ = nullptr;
cancelable_task_manager()->CancelAndWait();
heap_.TearDown();
......@@ -2300,9 +2304,6 @@ void Isolate::Deinit() {
delete interpreter_;
interpreter_ = NULL;
delete compiler_dispatcher_tracer_;
compiler_dispatcher_tracer_ = nullptr;
delete cpu_profiler_;
cpu_profiler_ = NULL;
......@@ -2511,7 +2512,7 @@ bool Isolate::Init(Deserializer* des) {
cpu_profiler_ = new CpuProfiler(this);
heap_profiler_ = new HeapProfiler(heap());
interpreter_ = new interpreter::Interpreter(this);
compiler_dispatcher_tracer_ = new CompilerDispatcherTracer(this);
compiler_dispatcher_ = new CompilerDispatcher(this, FLAG_stack_size);
// Enable logging before setting up the heap
logger_->SetUp(this);
......
......@@ -46,7 +46,7 @@ class CodeRange;
class CodeStubDescriptor;
class CodeTracer;
class CompilationCache;
class CompilerDispatcherTracer;
class CompilerDispatcher;
class CompilationStatistics;
class ContextSlotCache;
class Counters;
......@@ -1163,8 +1163,8 @@ class Isolate {
AccountingAllocator* allocator() { return allocator_; }
CompilerDispatcherTracer* compiler_dispatcher_tracer() const {
return compiler_dispatcher_tracer_;
CompilerDispatcher* compiler_dispatcher() const {
return compiler_dispatcher_;
}
// Clear all optimized code stored in native contexts.
......@@ -1399,7 +1399,7 @@ class Isolate {
interpreter::Interpreter* interpreter_;
CompilerDispatcherTracer* compiler_dispatcher_tracer_;
CompilerDispatcher* compiler_dispatcher_;
typedef std::pair<InterruptCallback, void*> InterruptEntry;
std::queue<InterruptEntry> api_interrupts_queue_;
......
......@@ -742,6 +742,8 @@
'compiler/wasm-linkage.cc',
'compiler/zone-stats.cc',
'compiler/zone-stats.h',
'compiler-dispatcher/compiler-dispatcher.cc',
'compiler-dispatcher/compiler-dispatcher.h',
'compiler-dispatcher/compiler-dispatcher-job.cc',
'compiler-dispatcher/compiler-dispatcher-job.h',
'compiler-dispatcher/compiler-dispatcher-tracer.cc',
......
......@@ -28,8 +28,11 @@ v8_executable("unittests") {
"base/utils/random-number-generator-unittest.cc",
"cancelable-tasks-unittest.cc",
"char-predicates-unittest.cc",
"compiler-dispatcher/compiler-dispatcher-helper.cc",
"compiler-dispatcher/compiler-dispatcher-helper.h",
"compiler-dispatcher/compiler-dispatcher-job-unittest.cc",
"compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc",
"compiler-dispatcher/compiler-dispatcher-unittest.cc",
"compiler/branch-elimination-unittest.cc",
"compiler/bytecode-analysis-unittest.cc",
"compiler/checkpoint-elimination-unittest.cc",
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h"
#include <memory>
#include "include/v8.h"
#include "src/api.h"
namespace v8 {
namespace internal {
Handle<Object> RunJS(v8::Isolate* isolate, const char* script) {
return Utils::OpenHandle(
*v8::Script::Compile(
isolate->GetCurrentContext(),
v8::String::NewFromUtf8(isolate, script, v8::NewStringType::kNormal)
.ToLocalChecked())
.ToLocalChecked()
->Run(isolate->GetCurrentContext())
.ToLocalChecked());
}
} // namespace internal
} // namespace v8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UNITTESTS_COMPILER_DISPATCHER_COMPILER_DISPATCHER_HELPER_H_
#define V8_UNITTESTS_COMPILER_DISPATCHER_COMPILER_DISPATCHER_HELPER_H_
namespace v8 {
class Isolate;
namespace internal {
class Object;
template <typename T>
class Handle;
Handle<Object> RunJS(v8::Isolate* isolate, const char* script);
} // namespace internal
} // namespace v8
#endif // V8_UNITTESTS_COMPILER_DISPATCHER_COMPILER_DISPATCHER_HELPER_H_
......@@ -10,19 +10,32 @@
#include "src/ast/scopes.h"
#include "src/base/platform/semaphore.h"
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
#include "src/flags.h"
#include "src/isolate-inl.h"
#include "src/parsing/parse-info.h"
#include "src/v8.h"
#include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
typedef TestWithContext CompilerDispatcherJobTest;
class CompilerDispatcherJobTest : public TestWithContext {
public:
CompilerDispatcherJobTest() : tracer_(i_isolate()) {}
~CompilerDispatcherJobTest() override {}
CompilerDispatcherTracer* tracer() { return &tracer_; }
private:
CompilerDispatcherTracer tracer_;
class IgnitionCompilerDispatcherJobTest : public TestWithContext {
DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherJobTest);
};
class IgnitionCompilerDispatcherJobTest : public CompilerDispatcherJobTest {
public:
IgnitionCompilerDispatcherJobTest() {}
~IgnitionCompilerDispatcherJobTest() override {}
......@@ -90,36 +103,25 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
return scope.CloseAndEscape(shared);
}
Handle<Object> RunJS(v8::Isolate* isolate, const char* script) {
return Utils::OpenHandle(
*v8::Script::Compile(
isolate->GetCurrentContext(),
v8::String::NewFromUtf8(isolate, script, v8::NewStringType::kNormal)
.ToLocalChecked())
.ToLocalChecked()
->Run(isolate->GetCurrentContext())
.ToLocalChecked());
}
} // namespace
TEST_F(CompilerDispatcherJobTest, Construct) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateSharedFunctionInfo(i_isolate(), nullptr),
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), nullptr),
FLAG_stack_size));
}
TEST_F(CompilerDispatcherJobTest, CanParseOnBackgroundThread) {
{
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateSharedFunctionInfo(i_isolate(), nullptr),
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), nullptr),
FLAG_stack_size));
ASSERT_FALSE(job->can_parse_on_background_thread());
}
{
ScriptResource script(test_script, strlen(test_script));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script),
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), &script),
FLAG_stack_size));
ASSERT_TRUE(job->can_parse_on_background_thread());
}
......@@ -127,7 +129,7 @@ TEST_F(CompilerDispatcherJobTest, CanParseOnBackgroundThread) {
TEST_F(CompilerDispatcherJobTest, StateTransitions) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateSharedFunctionInfo(i_isolate(), nullptr),
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), nullptr),
FLAG_stack_size));
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
......@@ -150,7 +152,7 @@ TEST_F(CompilerDispatcherJobTest, StateTransitions) {
TEST_F(CompilerDispatcherJobTest, SyntaxError) {
ScriptResource script("^^^", strlen("^^^"));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script),
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), &script),
FLAG_stack_size));
job->PrepareToParseOnMainThread();
......@@ -172,7 +174,7 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), handle(f->shared()), FLAG_stack_size));
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
......@@ -208,7 +210,7 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
"g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), handle(f->shared()), FLAG_stack_size));
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
......@@ -233,7 +235,8 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToPrepare) {
raw_script += " 'x'; }";
ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script), 100));
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), &script),
100));
job->PrepareToParseOnMainThread();
job->Parse();
......@@ -255,7 +258,8 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) {
raw_script += " 'x'; }";
ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script), 50));
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), &script),
50));
job->PrepareToParseOnMainThread();
job->Parse();
......@@ -298,7 +302,8 @@ TEST_F(IgnitionCompilerDispatcherJobTest, CompileOnBackgroundThread) {
"}";
ScriptResource script(raw_script, strlen(raw_script));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script), 100));
i_isolate(), tracer(), CreateSharedFunctionInfo(i_isolate(), &script),
100));
job->PrepareToParseOnMainThread();
job->Parse();
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "src/compiler-dispatcher/compiler-dispatcher.h"
#include "src/flags.h"
#include "src/handles.h"
#include "src/objects-inl.h"
#include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
typedef TestWithContext CompilerDispatcherTest;
TEST_F(CompilerDispatcherTest, Construct) {
std::unique_ptr<CompilerDispatcher> dispatcher(
new CompilerDispatcher(i_isolate(), FLAG_stack_size));
}
TEST_F(CompilerDispatcherTest, IsEnqueued) {
std::unique_ptr<CompilerDispatcher> dispatcher(
new CompilerDispatcher(i_isolate(), FLAG_stack_size));
const char script[] =
"function g() { var y = 1; function f(x) { return x * y }; return f; } "
"g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
ASSERT_FALSE(dispatcher->IsEnqueued(shared));
ASSERT_TRUE(dispatcher->Enqueue(shared));
ASSERT_TRUE(dispatcher->IsEnqueued(shared));
dispatcher->Abort(shared, CompilerDispatcher::BlockingBehavior::kBlock);
ASSERT_FALSE(dispatcher->IsEnqueued(shared));
}
TEST_F(CompilerDispatcherTest, FinishNow) {
std::unique_ptr<CompilerDispatcher> dispatcher(
new CompilerDispatcher(i_isolate(), FLAG_stack_size));
const char script[] =
"function g() { var y = 1; function f(x) { return x * y }; return f; } "
"g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
ASSERT_FALSE(shared->HasBaselineCode());
ASSERT_TRUE(dispatcher->Enqueue(shared));
ASSERT_TRUE(dispatcher->FinishNow(shared));
// Finishing removes the SFI from the queue.
ASSERT_FALSE(dispatcher->IsEnqueued(shared));
ASSERT_TRUE(shared->HasBaselineCode());
}
} // namespace internal
} // namespace v8
......@@ -82,8 +82,11 @@
'compiler/typer-unittest.cc',
'compiler/value-numbering-reducer-unittest.cc',
'compiler/zone-stats-unittest.cc',
'compiler-dispatcher/compiler-dispatcher-helper.cc',
'compiler-dispatcher/compiler-dispatcher-helper.h',
'compiler-dispatcher/compiler-dispatcher-job-unittest.cc',
'compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc',
'compiler-dispatcher/compiler-dispatcher-unittest.cc',
'counters-unittest.cc',
'eh-frame-iterator-unittest.cc',
'eh-frame-writer-unittest.cc',
......
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