summaryrefslogtreecommitdiff
path: root/deps/v8/test/unittests/compiler-dispatcher
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/unittests/compiler-dispatcher')
-rw-r--r--deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-helper.cc28
-rw-r--r--deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h23
-rw-r--r--deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc104
-rw-r--r--deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc12
-rw-r--r--deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc806
5 files changed, 921 insertions, 52 deletions
diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-helper.cc b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-helper.cc
new file mode 100644
index 0000000000..16fa160aec
--- /dev/null
+++ b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-helper.cc
@@ -0,0 +1,28 @@
+// 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"
+#include "src/objects-inl.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
diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h
new file mode 100644
index 0000000000..97084bd31f
--- /dev/null
+++ b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h
@@ -0,0 +1,23 @@
+// 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_
diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc
index d4c54247e2..ca9f44725b 100644
--- a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc
+++ b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-job-unittest.cc
@@ -10,27 +10,28 @@
#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 IgnitionCompilerDispatcherJobTest : public TestWithContext {
+class CompilerDispatcherJobTest : public TestWithContext {
public:
- IgnitionCompilerDispatcherJobTest() {}
- ~IgnitionCompilerDispatcherJobTest() override {}
+ CompilerDispatcherJobTest() : tracer_(i_isolate()) {}
+ ~CompilerDispatcherJobTest() override {}
+
+ CompilerDispatcherTracer* tracer() { return &tracer_; }
static void SetUpTestCase() {
old_flag_ = i::FLAG_ignition;
i::FLAG_ignition = true;
- i::FLAG_never_compact = true;
TestWithContext::SetUpTestCase();
}
@@ -40,11 +41,13 @@ class IgnitionCompilerDispatcherJobTest : public TestWithContext {
}
private:
+ CompilerDispatcherTracer tracer_;
static bool old_flag_;
- DISALLOW_COPY_AND_ASSIGN(IgnitionCompilerDispatcherJobTest);
+
+ DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherJobTest);
};
-bool IgnitionCompilerDispatcherJobTest::old_flag_;
+bool CompilerDispatcherJobTest::old_flag_;
namespace {
@@ -78,53 +81,29 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
source = isolate->factory()->NewStringFromAsciiChecked(test_script);
}
Handle<Script> script = isolate->factory()->NewScript(source);
+ Handle<FixedArray> infos = isolate->factory()->NewFixedArray(3);
+ script->set_shared_function_infos(*infos);
Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo(
isolate->factory()->NewStringFromAsciiChecked("f"),
isolate->builtins()->CompileLazy(), false);
- SharedFunctionInfo::SetScript(shared, script);
shared->set_end_position(source->length());
shared->set_outer_scope_info(ScopeInfo::Empty(isolate));
+ shared->set_function_literal_id(1);
+ SharedFunctionInfo::SetScript(shared, script);
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),
- 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),
- FLAG_stack_size));
- ASSERT_TRUE(job->can_parse_on_background_thread());
- }
-}
-
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);
@@ -147,7 +126,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();
@@ -169,7 +148,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();
@@ -205,7 +184,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();
@@ -230,7 +209,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();
@@ -252,7 +232,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();
@@ -285,7 +266,7 @@ class CompileTask : public Task {
DISALLOW_COPY_AND_ASSIGN(CompileTask);
};
-TEST_F(IgnitionCompilerDispatcherJobTest, CompileOnBackgroundThread) {
+TEST_F(CompilerDispatcherJobTest, CompileOnBackgroundThread) {
const char* raw_script =
"(a, b) {\n"
" var c = a + b;\n"
@@ -295,13 +276,13 @@ 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();
job->FinalizeParsingOnMainThread();
job->PrepareToCompileOnMainThread();
- ASSERT_TRUE(job->can_compile_on_background_thread());
base::Semaphore semaphore(0);
CompileTask* background_task = new CompileTask(job.get(), &semaphore);
@@ -315,5 +296,36 @@ TEST_F(IgnitionCompilerDispatcherJobTest, CompileOnBackgroundThread) {
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
+TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
+ const char script[] =
+ "function g() {\n"
+ " f = function() {\n"
+ " e = (function() { return 42; });\n"
+ " return e;\n"
+ " };\n"
+ " return f;\n"
+ "}\n"
+ "g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+
+ std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
+ i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
+
+ job->PrepareToParseOnMainThread();
+ job->Parse();
+ ASSERT_TRUE(job->FinalizeParsingOnMainThread());
+ ASSERT_TRUE(job->PrepareToCompileOnMainThread());
+ job->Compile();
+ ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
+ ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
+
+ Handle<JSFunction> e = Handle<JSFunction>::cast(RunJS(isolate(), "f();"));
+
+ ASSERT_FALSE(e->shared()->HasBaselineCode());
+
+ job->ResetOnMainThread();
+ ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc
index 997765ff83..21ffe76210 100644
--- a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc
+++ b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc
@@ -8,16 +8,16 @@
namespace v8 {
namespace internal {
-TEST(CompilerDispatcherTracerTest, EstimateZeroWithoutSamples) {
+TEST(CompilerDispatcherTracerTest, EstimateWithoutSamples) {
CompilerDispatcherTracer tracer(nullptr);
EXPECT_EQ(0.0, tracer.EstimatePrepareToParseInMs());
- EXPECT_EQ(0.0, tracer.EstimateParseInMs(0));
- EXPECT_EQ(0.0, tracer.EstimateParseInMs(42));
+ 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(0));
- EXPECT_EQ(0.0, tracer.EstimateCompileInMs(42));
+ EXPECT_EQ(1.0, tracer.EstimateCompileInMs(0));
+ EXPECT_EQ(1.0, tracer.EstimateCompileInMs(42));
EXPECT_EQ(0.0, tracer.EstimateFinalizeCompilingInMs());
}
@@ -36,7 +36,7 @@ TEST(CompilerDispatcherTracerTest, Average) {
TEST(CompilerDispatcherTracerTest, SizeBasedAverage) {
CompilerDispatcherTracer tracer(nullptr);
- EXPECT_EQ(0.0, tracer.EstimateParseInMs(100));
+ EXPECT_EQ(1.0, tracer.EstimateParseInMs(100));
// All three samples parse 100 units/ms.
tracer.RecordParse(1.0, 100);
diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc
new file mode 100644
index 0000000000..8e47c48866
--- /dev/null
+++ b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc
@@ -0,0 +1,806 @@
+// 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 "include/v8-platform.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/handles.h"
+#include "src/objects-inl.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 {
+
+class CompilerDispatcherTest : public TestWithContext {
+ public:
+ CompilerDispatcherTest() = default;
+ ~CompilerDispatcherTest() override = default;
+
+ static void SetUpTestCase() {
+ old_flag_ = i::FLAG_ignition;
+ i::FLAG_compiler_dispatcher = true;
+ old_ignition_flag_ = i::FLAG_ignition;
+ i::FLAG_ignition = true;
+ TestWithContext::SetUpTestCase();
+ }
+
+ static void TearDownTestCase() {
+ TestWithContext::TearDownTestCase();
+ i::FLAG_compiler_dispatcher = old_flag_;
+ i::FLAG_ignition = old_ignition_flag_;
+ }
+
+ private:
+ static bool old_flag_;
+ static bool old_ignition_flag_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherTest);
+};
+
+bool CompilerDispatcherTest::old_flag_;
+bool CompilerDispatcherTest::old_ignition_flag_;
+
+namespace {
+
+class MockPlatform : public v8::Platform {
+ public:
+ MockPlatform() : time_(0.0), time_step_(0.0), idle_task_(nullptr), sem_(0) {}
+ ~MockPlatform() override {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ EXPECT_TRUE(foreground_tasks_.empty());
+ EXPECT_TRUE(background_tasks_.empty());
+ EXPECT_TRUE(idle_task_ == nullptr);
+ }
+
+ size_t NumberOfAvailableBackgroundThreads() override { return 1; }
+
+ void CallOnBackgroundThread(Task* task,
+ ExpectedRuntime expected_runtime) override {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ background_tasks_.push_back(task);
+ }
+
+ void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ foreground_tasks_.push_back(task);
+ }
+
+ void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
+ double delay_in_seconds) override {
+ UNREACHABLE();
+ }
+
+ void CallIdleOnForegroundThread(v8::Isolate* isolate,
+ IdleTask* task) override {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ ASSERT_TRUE(idle_task_ == nullptr);
+ idle_task_ = task;
+ }
+
+ bool IdleTasksEnabled(v8::Isolate* isolate) override { return true; }
+
+ double MonotonicallyIncreasingTime() override {
+ time_ += time_step_;
+ return time_;
+ }
+
+ void RunIdleTask(double deadline_in_seconds, double time_step) {
+ time_step_ = time_step;
+ IdleTask* task;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ task = idle_task_;
+ ASSERT_TRUE(idle_task_ != nullptr);
+ idle_task_ = nullptr;
+ }
+ task->Run(deadline_in_seconds);
+ delete task;
+ }
+
+ bool IdleTaskPending() {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ return idle_task_;
+ }
+
+ bool BackgroundTasksPending() {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ return !background_tasks_.empty();
+ }
+
+ bool ForegroundTasksPending() {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ return !foreground_tasks_.empty();
+ }
+
+ void RunBackgroundTasksAndBlock(Platform* platform) {
+ std::vector<Task*> tasks;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ tasks.swap(background_tasks_);
+ }
+ platform->CallOnBackgroundThread(new TaskWrapper(this, tasks, true),
+ kShortRunningTask);
+ sem_.Wait();
+ }
+
+ void RunBackgroundTasks(Platform* platform) {
+ std::vector<Task*> tasks;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ tasks.swap(background_tasks_);
+ }
+ platform->CallOnBackgroundThread(new TaskWrapper(this, tasks, false),
+ kShortRunningTask);
+ }
+
+ void RunForegroundTasks() {
+ std::vector<Task*> tasks;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ tasks.swap(foreground_tasks_);
+ }
+ for (auto& task : tasks) {
+ task->Run();
+ delete task;
+ }
+ }
+
+ void ClearBackgroundTasks() {
+ std::vector<Task*> tasks;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ tasks.swap(background_tasks_);
+ }
+ for (auto& task : tasks) {
+ delete task;
+ }
+ }
+
+ void ClearForegroundTasks() {
+ std::vector<Task*> tasks;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ tasks.swap(foreground_tasks_);
+ }
+ for (auto& task : tasks) {
+ delete task;
+ }
+ }
+
+ void ClearIdleTask() {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ ASSERT_TRUE(idle_task_ != nullptr);
+ delete idle_task_;
+ idle_task_ = nullptr;
+ }
+
+ private:
+ class TaskWrapper : public Task {
+ public:
+ TaskWrapper(MockPlatform* platform, const std::vector<Task*>& tasks,
+ bool signal)
+ : platform_(platform), tasks_(tasks), signal_(signal) {}
+ ~TaskWrapper() = default;
+
+ void Run() override {
+ for (auto& task : tasks_) {
+ task->Run();
+ delete task;
+ }
+ if (signal_) platform_->sem_.Signal();
+ }
+
+ private:
+ MockPlatform* platform_;
+ std::vector<Task*> tasks_;
+ bool signal_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskWrapper);
+ };
+
+ double time_;
+ double time_step_;
+
+ // Protects all *_tasks_.
+ base::Mutex mutex_;
+
+ IdleTask* idle_task_;
+ std::vector<Task*> background_tasks_;
+ std::vector<Task*> foreground_tasks_;
+
+ base::Semaphore sem_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPlatform);
+};
+
+} // namespace
+
+TEST_F(CompilerDispatcherTest, Construct) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+}
+
+TEST_F(CompilerDispatcherTest, IsEnqueued) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f1(x) { return x * y }; return f1; } "
+ "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.AbortAll(CompilerDispatcher::BlockingBehavior::kBlock);
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+ platform.ClearIdleTask();
+}
+
+TEST_F(CompilerDispatcherTest, FinishNow) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f2(x) { return x * y }; return f2; } "
+ "g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(shared->is_compiled());
+ 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->is_compiled());
+ ASSERT_TRUE(platform.IdleTaskPending());
+ platform.ClearIdleTask();
+}
+
+TEST_F(CompilerDispatcherTest, IdleTask) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f3(x) { return x * y }; return f3; } "
+ "g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ // Since time doesn't progress on the MockPlatform, this is enough idle time
+ // to finish compiling the function.
+ platform.RunIdleTask(1000.0, 0.0);
+
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_TRUE(shared->is_compiled());
+}
+
+TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f4(x) { return x * y }; return f4; } "
+ "g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ // The job should be scheduled for the main thread.
+ ASSERT_EQ(dispatcher.jobs_.size(), 1u);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kInitial);
+
+ // Only grant a little idle time and have time advance beyond it in one step.
+ platform.RunIdleTask(2.0, 1.0);
+
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ // The job should be still scheduled for the main thread, but ready for
+ // parsing.
+ ASSERT_EQ(dispatcher.jobs_.size(), 1u);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kReadyToParse);
+
+ // Now grant a lot of idle time and freeze time.
+ platform.RunIdleTask(1000.0, 0.0);
+
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_TRUE(shared->is_compiled());
+ ASSERT_FALSE(platform.IdleTaskPending());
+}
+
+TEST_F(CompilerDispatcherTest, IdleTaskException) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, 50);
+
+ std::string script("function g() { function f5(x) { var a = ");
+ for (int i = 0; i < 1000; i++) {
+ script += "'x' + ";
+ }
+ script += " 'x'; }; return f5; } g();";
+ Handle<JSFunction> f =
+ Handle<JSFunction>::cast(RunJS(isolate(), script.c_str()));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ // Since time doesn't progress on the MockPlatform, this is enough idle time
+ // to finish compiling the function.
+ platform.RunIdleTask(1000.0, 0.0);
+
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+ ASSERT_FALSE(i_isolate()->has_pending_exception());
+}
+
+TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f6(x) { return x * y }; return f6; } "
+ "g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ ASSERT_EQ(dispatcher.jobs_.size(), 1u);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kInitial);
+
+ // Make compiling super expensive, and advance job as much as possible on the
+ // foreground thread.
+ dispatcher.tracer_->RecordCompile(50000.0, 1);
+ platform.RunIdleTask(10.0, 0.0);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kReadyToCompile);
+
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(platform.BackgroundTasksPending());
+
+ platform.RunBackgroundTasksAndBlock(V8::GetCurrentPlatform());
+
+ ASSERT_TRUE(platform.IdleTaskPending());
+ ASSERT_FALSE(platform.BackgroundTasksPending());
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kCompiled);
+
+ // Now grant a lot of idle time and freeze time.
+ platform.RunIdleTask(1000.0, 0.0);
+
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_TRUE(shared->is_compiled());
+ ASSERT_FALSE(platform.IdleTaskPending());
+}
+
+TEST_F(CompilerDispatcherTest, FinishNowWithBackgroundTask) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f7(x) { return x * y }; return f7; } "
+ "g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ ASSERT_EQ(dispatcher.jobs_.size(), 1u);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kInitial);
+
+ // Make compiling super expensive, and advance job as much as possible on the
+ // foreground thread.
+ dispatcher.tracer_->RecordCompile(50000.0, 1);
+ platform.RunIdleTask(10.0, 0.0);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kReadyToCompile);
+
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(platform.BackgroundTasksPending());
+
+ // This does not block, but races with the FinishNow() call below.
+ platform.RunBackgroundTasks(V8::GetCurrentPlatform());
+
+ ASSERT_TRUE(dispatcher.FinishNow(shared));
+ // Finishing removes the SFI from the queue.
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_TRUE(shared->is_compiled());
+ if (platform.IdleTaskPending()) platform.ClearIdleTask();
+ ASSERT_FALSE(platform.BackgroundTasksPending());
+}
+
+TEST_F(CompilerDispatcherTest, IdleTaskMultipleJobs) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script1[] =
+ "function g() { var y = 1; function f8(x) { return x * y }; return f8; } "
+ "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 f9(x) { return x * y }; return f9; } "
+ "g();";
+ Handle<JSFunction> f2 = Handle<JSFunction>::cast(RunJS(isolate(), script2));
+ Handle<SharedFunctionInfo> shared2(f2->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared1));
+ ASSERT_TRUE(dispatcher.Enqueue(shared2));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ // Since time doesn't progress on the MockPlatform, this is enough idle time
+ // to finish compiling the function.
+ platform.RunIdleTask(1000.0, 0.0);
+
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared1));
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared2));
+ ASSERT_TRUE(shared1->is_compiled());
+ ASSERT_TRUE(shared2->is_compiled());
+}
+
+TEST_F(CompilerDispatcherTest, FinishNowException) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, 50);
+
+ std::string script("function g() { function f10(x) { var a = ");
+ for (int i = 0; i < 1000; i++) {
+ script += "'x' + ";
+ }
+ script += " 'x'; }; return f10; } g();";
+ Handle<JSFunction> f =
+ Handle<JSFunction>::cast(RunJS(isolate(), script.c_str()));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ ASSERT_FALSE(dispatcher.FinishNow(shared));
+
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+ ASSERT_TRUE(i_isolate()->has_pending_exception());
+
+ i_isolate()->clear_pending_exception();
+ platform.ClearIdleTask();
+}
+
+TEST_F(CompilerDispatcherTest, AsyncAbortAllPendingBackgroundTask) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f11(x) { return x * y }; return f11; "
+ "} g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ ASSERT_EQ(dispatcher.jobs_.size(), 1u);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kInitial);
+
+ // Make compiling super expensive, and advance job as much as possible on the
+ // foreground thread.
+ dispatcher.tracer_->RecordCompile(50000.0, 1);
+ platform.RunIdleTask(10.0, 0.0);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kReadyToCompile);
+
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(platform.BackgroundTasksPending());
+
+ // The background task hasn't yet started, so we can just cancel it.
+ dispatcher.AbortAll(CompilerDispatcher::BlockingBehavior::kDontBlock);
+ ASSERT_FALSE(platform.ForegroundTasksPending());
+
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+
+ platform.RunBackgroundTasksAndBlock(V8::GetCurrentPlatform());
+
+ if (platform.IdleTaskPending()) platform.ClearIdleTask();
+ ASSERT_FALSE(platform.BackgroundTasksPending());
+ ASSERT_FALSE(platform.ForegroundTasksPending());
+}
+
+TEST_F(CompilerDispatcherTest, AsyncAbortAllRunningBackgroundTask) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script1[] =
+ "function g() { var y = 1; function f11(x) { return x * y }; return f11; "
+ "} 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 f12(x) { return x * y }; return f12; "
+ "} g();";
+ Handle<JSFunction> f2 = Handle<JSFunction>::cast(RunJS(isolate(), script2));
+ Handle<SharedFunctionInfo> shared2(f2->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared1));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ ASSERT_EQ(dispatcher.jobs_.size(), 1u);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kInitial);
+
+ // Make compiling super expensive, and advance job as much as possible on the
+ // foreground thread.
+ dispatcher.tracer_->RecordCompile(50000.0, 1);
+ platform.RunIdleTask(10.0, 0.0);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kReadyToCompile);
+
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared1));
+ ASSERT_FALSE(shared1->is_compiled());
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(platform.BackgroundTasksPending());
+
+ // Kick off background tasks and freeze them.
+ dispatcher.block_for_testing_.SetValue(true);
+ platform.RunBackgroundTasks(V8::GetCurrentPlatform());
+
+ // Busy loop until the background task started running.
+ while (dispatcher.block_for_testing_.Value()) {
+ }
+ dispatcher.AbortAll(CompilerDispatcher::BlockingBehavior::kDontBlock);
+ ASSERT_TRUE(platform.ForegroundTasksPending());
+
+ // We can't schedule new tasks while we're aborting.
+ ASSERT_FALSE(dispatcher.Enqueue(shared2));
+
+ // Run the first AbortTask. Since the background job is still pending, it
+ // can't do anything.
+ platform.RunForegroundTasks();
+ {
+ base::LockGuard<base::Mutex> lock(&dispatcher.mutex_);
+ ASSERT_TRUE(dispatcher.abort_);
+ }
+
+ // Release background task.
+ dispatcher.semaphore_for_testing_.Signal();
+
+ // Busy loop until the background task scheduled another AbortTask task.
+ while (!platform.ForegroundTasksPending()) {
+ }
+
+ platform.RunForegroundTasks();
+ ASSERT_TRUE(dispatcher.jobs_.empty());
+ {
+ base::LockGuard<base::Mutex> lock(&dispatcher.mutex_);
+ ASSERT_FALSE(dispatcher.abort_);
+ }
+
+ ASSERT_TRUE(platform.IdleTaskPending());
+ platform.RunIdleTask(5.0, 1.0);
+ ASSERT_FALSE(platform.BackgroundTasksPending());
+ ASSERT_FALSE(platform.ForegroundTasksPending());
+
+ // Now it's possible to enqueue new functions again.
+ ASSERT_TRUE(dispatcher.Enqueue(shared2));
+ ASSERT_TRUE(platform.IdleTaskPending());
+ ASSERT_FALSE(platform.BackgroundTasksPending());
+ ASSERT_FALSE(platform.ForegroundTasksPending());
+ platform.ClearIdleTask();
+}
+
+TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f13(x) { return x * y }; return f13; "
+ "} g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ ASSERT_TRUE(platform.IdleTaskPending());
+
+ ASSERT_EQ(dispatcher.jobs_.size(), 1u);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kInitial);
+
+ // Make compiling super expensive, and advance job as much as possible on the
+ // foreground thread.
+ dispatcher.tracer_->RecordCompile(50000.0, 1);
+ platform.RunIdleTask(10.0, 0.0);
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kReadyToCompile);
+
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+ ASSERT_FALSE(platform.IdleTaskPending());
+ ASSERT_TRUE(platform.BackgroundTasksPending());
+
+ // Kick off background tasks and freeze them.
+ dispatcher.block_for_testing_.SetValue(true);
+ platform.RunBackgroundTasks(V8::GetCurrentPlatform());
+
+ // Busy loop until the background task started running.
+ while (dispatcher.block_for_testing_.Value()) {
+ }
+ dispatcher.AbortAll(CompilerDispatcher::BlockingBehavior::kDontBlock);
+ ASSERT_TRUE(platform.ForegroundTasksPending());
+
+ // Run the first AbortTask. Since the background job is still pending, it
+ // can't do anything.
+ platform.RunForegroundTasks();
+ {
+ base::LockGuard<base::Mutex> lock(&dispatcher.mutex_);
+ ASSERT_TRUE(dispatcher.abort_);
+ }
+
+ // While the background thread holds on to a job, it is still enqueud.
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared));
+
+ // Release background task.
+ dispatcher.semaphore_for_testing_.Signal();
+
+ // Force the compilation to finish, even while aborting.
+ ASSERT_TRUE(dispatcher.FinishNow(shared));
+ ASSERT_TRUE(dispatcher.jobs_.empty());
+ {
+ base::LockGuard<base::Mutex> lock(&dispatcher.mutex_);
+ ASSERT_FALSE(dispatcher.abort_);
+ }
+
+ ASSERT_TRUE(platform.ForegroundTasksPending());
+ ASSERT_TRUE(platform.IdleTaskPending());
+ ASSERT_FALSE(platform.BackgroundTasksPending());
+ platform.ClearForegroundTasks();
+ platform.ClearIdleTask();
+}
+
+TEST_F(CompilerDispatcherTest, MemoryPressure) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f14(x) { return x * y }; return f14; "
+ "} g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ // Can't enqueue tasks under memory pressure.
+ dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kCritical,
+ true);
+ ASSERT_FALSE(dispatcher.Enqueue(shared));
+
+ dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kNone, true);
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+
+ // Memory pressure cancels current jobs.
+ dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kCritical,
+ true);
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ platform.ClearIdleTask();
+}
+
+namespace {
+
+class PressureNotificationTask : public CancelableTask {
+ public:
+ PressureNotificationTask(Isolate* isolate, CompilerDispatcher* dispatcher,
+ base::Semaphore* sem)
+ : CancelableTask(isolate), dispatcher_(dispatcher), sem_(sem) {}
+ ~PressureNotificationTask() override {}
+
+ void RunInternal() override {
+ dispatcher_->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical,
+ false);
+ sem_->Signal();
+ }
+
+ private:
+ CompilerDispatcher* dispatcher_;
+ base::Semaphore* sem_;
+
+ DISALLOW_COPY_AND_ASSIGN(PressureNotificationTask);
+};
+
+} // namespace
+
+TEST_F(CompilerDispatcherTest, MemoryPressureFromBackground) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f15(x) { return x * y }; return f15; "
+ "} g();";
+ Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
+ Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
+
+ ASSERT_TRUE(dispatcher.Enqueue(shared));
+ base::Semaphore sem(0);
+ V8::GetCurrentPlatform()->CallOnBackgroundThread(
+ new PressureNotificationTask(i_isolate(), &dispatcher, &sem),
+ v8::Platform::kShortRunningTask);
+
+ sem.Wait();
+
+ // A memory pressure task is pending, and running it will cancel the job.
+ ASSERT_TRUE(platform.ForegroundTasksPending());
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared));
+ platform.RunForegroundTasks();
+ ASSERT_FALSE(dispatcher.IsEnqueued(shared));
+ ASSERT_FALSE(shared->is_compiled());
+
+ // Since the AbortAll() call is made from a task, AbortAll thinks that there
+ // is at least one task running, and fires of an AbortTask to be safe.
+ ASSERT_TRUE(platform.ForegroundTasksPending());
+ platform.RunForegroundTasks();
+ ASSERT_FALSE(platform.ForegroundTasksPending());
+
+ platform.ClearIdleTask();
+}
+
+TEST_F(CompilerDispatcherTest, EnqueueAndStep) {
+ MockPlatform platform;
+ CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
+
+ const char script[] =
+ "function g() { var y = 1; function f16(x) { return x * y }; return f16; "
+ "} 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.EnqueueAndStep(shared));
+ ASSERT_TRUE(dispatcher.IsEnqueued(shared));
+
+ ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
+ CompileJobStatus::kReadyToParse);
+
+ ASSERT_TRUE(platform.IdleTaskPending());
+ platform.ClearIdleTask();
+ ASSERT_TRUE(platform.BackgroundTasksPending());
+ platform.ClearBackgroundTasks();
+}
+
+} // namespace internal
+} // namespace v8