diff options
Diffstat (limited to 'deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc | 590 |
1 files changed, 272 insertions, 318 deletions
diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc index 45121aedb3..bfc111aed5 100644 --- a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc +++ b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc @@ -9,6 +9,8 @@ #include "include/v8-platform.h" #include "src/api-inl.h" #include "src/ast/ast-value-factory.h" +#include "src/ast/ast.h" +#include "src/ast/scopes.h" #include "src/base/platform/semaphore.h" #include "src/base/template-utils.h" #include "src/compiler-dispatcher/compiler-dispatcher-job.h" @@ -25,16 +27,6 @@ #include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" -// V8 is smart enough to know something was already compiled and return compiled -// code straight away. We need a unique name for each test function so that V8 -// returns an empty SharedFunctionInfo. -#define _STR(x) #x -#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() \ - "function f" STR(__LINE__) "(x, y) { return x * y }; f" STR(__LINE__) ";" - namespace v8 { namespace internal { @@ -77,6 +69,37 @@ class CompilerDispatcherTest : public TestWithNativeContext { CompilerDispatcherTestFlags::RestoreFlags(); } + static base::Optional<CompilerDispatcher::JobId> EnqueueUnoptimizedCompileJob( + CompilerDispatcher* dispatcher, Isolate* isolate, + Handle<SharedFunctionInfo> shared) { + std::unique_ptr<ParseInfo> outer_parse_info = + test::OuterParseInfoForShared(isolate, shared); + AstValueFactory* ast_value_factory = + outer_parse_info->GetOrCreateAstValueFactory(); + AstNodeFactory ast_node_factory(ast_value_factory, + outer_parse_info->zone()); + + const AstRawString* function_name = + ast_value_factory->GetOneByteString("f"); + DeclarationScope* script_scope = new (outer_parse_info->zone()) + DeclarationScope(outer_parse_info->zone(), ast_value_factory); + DeclarationScope* function_scope = + new (outer_parse_info->zone()) DeclarationScope( + outer_parse_info->zone(), script_scope, FUNCTION_SCOPE); + function_scope->set_start_position(shared->StartPosition()); + function_scope->set_end_position(shared->EndPosition()); + const FunctionLiteral* function_literal = + ast_node_factory.NewFunctionLiteral( + function_name, function_scope, nullptr, -1, -1, -1, + FunctionLiteral::kNoDuplicateParameters, + FunctionLiteral::kAnonymousExpression, + FunctionLiteral::kShouldEagerCompile, shared->StartPosition(), true, + shared->FunctionLiteralId(isolate), nullptr); + + return dispatcher->Enqueue(outer_parse_info.get(), function_name, + function_literal); + } + private: DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherTest); }; @@ -238,7 +261,7 @@ class MockPlatform : public v8::Platform { TaskWrapper(MockPlatform* platform, std::vector<std::unique_ptr<Task>> tasks, bool signal) : platform_(platform), tasks_(std::move(tasks)), signal_(signal) {} - ~TaskWrapper() = default; + ~TaskWrapper() override = default; void Run() override { for (auto& task : tasks_) { @@ -313,17 +336,27 @@ TEST_F(CompilerDispatcherTest, IsEnqueued) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); + ASSERT_FALSE(dispatcher.IsEnqueued(shared)); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); - ASSERT_FALSE(dispatcher.IsEnqueued(shared)); - ASSERT_TRUE(dispatcher.Enqueue(shared)); + ASSERT_TRUE(job_id); + ASSERT_TRUE(dispatcher.IsEnqueued(*job_id)); + ASSERT_FALSE(dispatcher.IsEnqueued(shared)); // SFI not yet registered. + + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); + ASSERT_TRUE(dispatcher.IsEnqueued(*job_id)); ASSERT_TRUE(dispatcher.IsEnqueued(shared)); + dispatcher.AbortAll(BlockingBehavior::kBlock); + ASSERT_FALSE(dispatcher.IsEnqueued(*job_id)); ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(platform.IdleTaskPending()); + platform.ClearWorkerTasks(); platform.ClearIdleTask(); } @@ -331,79 +364,71 @@ TEST_F(CompilerDispatcherTest, FinishNow) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); - + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); ASSERT_FALSE(shared->is_compiled()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); + + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); + ASSERT_TRUE(dispatcher.FinishNow(shared)); // Finishing removes the SFI from the queue. + ASSERT_FALSE(dispatcher.IsEnqueued(*job_id)); ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(shared->is_compiled()); ASSERT_TRUE(platform.IdleTaskPending()); - platform.ClearIdleTask(); -} - -TEST_F(CompilerDispatcherTest, FinishAllNow) { - MockPlatform platform; - CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - - constexpr int num_funcs = 2; - Handle<JSFunction> f[num_funcs]; - Handle<SharedFunctionInfo> shared[num_funcs]; - - for (int i = 0; i < num_funcs; ++i) { - std::stringstream ss; - ss << 'f' << STR(__LINE__) << '_' << i; - std::string func_name = ss.str(); - 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()); - ASSERT_TRUE(dispatcher.Enqueue(shared[i])); - } - dispatcher.FinishAllNow(); - for (int i = 0; i < num_funcs; ++i) { - // Finishing removes the SFI from the queue. - ASSERT_FALSE(dispatcher.IsEnqueued(shared[i])); - ASSERT_TRUE(shared[i]->is_compiled()); - } - platform.ClearIdleTask(); platform.ClearWorkerTasks(); + platform.ClearIdleTask(); } TEST_F(CompilerDispatcherTest, IdleTask) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); - + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); + + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), 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); + // Since we haven't yet registered the SFI for the job, it should still be + // enqueued and waiting. + ASSERT_TRUE(dispatcher.IsEnqueued(*job_id)); + ASSERT_FALSE(shared->is_compiled()); + ASSERT_FALSE(platform.IdleTaskPending()); + + // Register SFI, which should schedule another idle task to complete the + // compilation. + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); + ASSERT_TRUE(platform.IdleTaskPending()); + platform.RunIdleTask(1000.0, 0.0); + ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(shared->is_compiled()); + platform.ClearWorkerTasks(); } TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); - + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); + + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); + ASSERT_TRUE(platform.IdleTaskPending()); // The job should be scheduled for the main thread. @@ -419,9 +444,9 @@ TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) { ASSERT_TRUE(platform.IdleTaskPending()); // The job should be still scheduled for the main thread, but ready for - // parsing. + // finalization. ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kPrepared, + ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToFinalize, dispatcher.jobs_.begin()->second->status()); // Now grant a lot of idle time and freeze time. @@ -430,25 +455,28 @@ TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) { ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(shared->is_compiled()); ASSERT_FALSE(platform.IdleTaskPending()); + platform.ClearWorkerTasks(); } TEST_F(CompilerDispatcherTest, IdleTaskException) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, 50); - std::string func_name("f" STR(__LINE__)); - std::string script("function " + func_name + "(x) { var a = "); - for (int i = 0; i < 500; i++) { + std::string raw_script("(x) { var a = "); + for (int i = 0; i < 1000; i++) { // Alternate + and - to avoid n-ary operation nodes. - script += "'x' + 'x' - "; + raw_script += "'x' + 'x' - "; } - script += " 'x'; }; " + func_name + ";"; - Handle<JSFunction> f = RunJS<JSFunction>(script.c_str()); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + raw_script += " 'x'; };"; + test::ScriptResource* script = + new test::ScriptResource(raw_script.c_str(), strlen(raw_script.c_str())); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), script); + ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); - ASSERT_TRUE(platform.IdleTaskPending()); + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); // Since time doesn't progress on the MockPlatform, this is enough idle time // to finish compiling the function. @@ -457,41 +485,33 @@ TEST_F(CompilerDispatcherTest, IdleTaskException) { ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(shared->is_compiled()); ASSERT_FALSE(i_isolate()->has_pending_exception()); + platform.ClearWorkerTasks(); } TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); - ASSERT_TRUE(platform.IdleTaskPending()); + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); + ASSERT_TRUE(dispatcher.IsEnqueued(shared)); + ASSERT_FALSE(shared->is_compiled()); ASSERT_EQ(dispatcher.jobs_.size(), 1u); ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, dispatcher.jobs_.begin()->second->status()); - - // 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_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); ASSERT_TRUE(platform.WorkerTasksPending()); platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); ASSERT_TRUE(platform.IdleTaskPending()); ASSERT_FALSE(platform.WorkerTasksPending()); - ASSERT_EQ(UnoptimizedCompileJob::Status::kCompiled, + ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToFinalize, dispatcher.jobs_.begin()->second->status()); // Now grant a lot of idle time and freeze time. @@ -500,34 +520,30 @@ TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) { ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(shared->is_compiled()); ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_FALSE(platform.WorkerTasksPending()); } TEST_F(CompilerDispatcherTest, FinishNowWithWorkerTask) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); - ASSERT_TRUE(platform.IdleTaskPending()); + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); ASSERT_EQ(dispatcher.jobs_.size(), 1u); ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, dispatcher.jobs_.begin()->second->status()); - // 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_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_EQ(dispatcher.jobs_.size(), 1u); + ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, + dispatcher.jobs_.begin()->second->status()); ASSERT_TRUE(platform.WorkerTasksPending()); // This does not block, but races with the FinishNow() call below. @@ -545,46 +561,54 @@ TEST_F(CompilerDispatcherTest, IdleTaskMultipleJobs) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script1[] = TEST_SCRIPT(); - Handle<JSFunction> f1 = RunJS<JSFunction>(script1); - Handle<SharedFunctionInfo> shared1(f1->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared_1 = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared_1->is_compiled()); + Handle<SharedFunctionInfo> shared_2 = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared_2->is_compiled()); - const char script2[] = TEST_SCRIPT(); - Handle<JSFunction> f2 = RunJS<JSFunction>(script2); - Handle<SharedFunctionInfo> shared2(f2->shared(), i_isolate()); + base::Optional<CompilerDispatcher::JobId> job_id_1 = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_1); + base::Optional<CompilerDispatcher::JobId> job_id_2 = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared1)); - ASSERT_TRUE(dispatcher.Enqueue(shared2)); - ASSERT_TRUE(platform.IdleTaskPending()); + dispatcher.RegisterSharedFunctionInfo(*job_id_1, *shared_1); + dispatcher.RegisterSharedFunctionInfo(*job_id_2, *shared_2); + + ASSERT_TRUE(dispatcher.IsEnqueued(shared_1)); + ASSERT_TRUE(dispatcher.IsEnqueued(shared_2)); // 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()); + ASSERT_FALSE(dispatcher.IsEnqueued(shared_1)); + ASSERT_FALSE(dispatcher.IsEnqueued(shared_2)); + ASSERT_TRUE(shared_1->is_compiled()); + ASSERT_TRUE(shared_2->is_compiled()); + platform.ClearWorkerTasks(); } TEST_F(CompilerDispatcherTest, FinishNowException) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, 50); - std::string func_name("f" STR(__LINE__)); - std::string script("function " + func_name + "(x) { var a = "); - for (int i = 0; i < 500; i++) { + std::string raw_script("(x) { var a = "); + for (int i = 0; i < 1000; i++) { // Alternate + and - to avoid n-ary operation nodes. - script += "'x' + 'x' - "; + raw_script += "'x' + 'x' - "; } - script += " 'x'; }; " + func_name + ";"; - Handle<JSFunction> f = RunJS<JSFunction>(script.c_str()); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + raw_script += " 'x'; };"; + test::ScriptResource* script = + new test::ScriptResource(raw_script.c_str(), strlen(raw_script.c_str())); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), script); + ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); - ASSERT_TRUE(platform.IdleTaskPending()); + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); ASSERT_FALSE(dispatcher.FinishNow(shared)); @@ -594,34 +618,26 @@ TEST_F(CompilerDispatcherTest, FinishNowException) { i_isolate()->clear_pending_exception(); platform.ClearIdleTask(); + platform.ClearWorkerTasks(); } TEST_F(CompilerDispatcherTest, AsyncAbortAllPendingWorkerTask) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); - ASSERT_TRUE(platform.IdleTaskPending()); + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); ASSERT_EQ(dispatcher.jobs_.size(), 1u); ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, dispatcher.jobs_.begin()->second->status()); - - // 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_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); ASSERT_TRUE(platform.WorkerTasksPending()); // The background task hasn't yet started, so we can just cancel it. @@ -642,32 +658,23 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllRunningWorkerTask) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script1[] = TEST_SCRIPT(); - Handle<JSFunction> f1 = RunJS<JSFunction>(script1); - Handle<SharedFunctionInfo> shared1(f1->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared_1 = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared_1->is_compiled()); + Handle<SharedFunctionInfo> shared_2 = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared_2->is_compiled()); - const char script2[] = TEST_SCRIPT(); - Handle<JSFunction> f2 = RunJS<JSFunction>(script2); - Handle<SharedFunctionInfo> shared2(f2->shared(), i_isolate()); - - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared1)); - ASSERT_TRUE(platform.IdleTaskPending()); + base::Optional<CompilerDispatcher::JobId> job_id_1 = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_1); + dispatcher.RegisterSharedFunctionInfo(*job_id_1, *shared_1); ASSERT_EQ(dispatcher.jobs_.size(), 1u); ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, dispatcher.jobs_.begin()->second->status()); - - // 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_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - - ASSERT_TRUE(dispatcher.IsEnqueued(shared1)); - ASSERT_FALSE(shared1->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_TRUE(dispatcher.IsEnqueued(shared_1)); + ASSERT_FALSE(shared_1->is_compiled()); + ASSERT_TRUE(platform.IdleTaskPending()); ASSERT_TRUE(platform.WorkerTasksPending()); // Kick off background tasks and freeze them. @@ -681,7 +688,9 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllRunningWorkerTask) { ASSERT_TRUE(platform.ForegroundTasksPending()); // We can't schedule new tasks while we're aborting. - ASSERT_FALSE(dispatcher.Enqueue(shared2)); + base::Optional<CompilerDispatcher::JobId> job_id_2 = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2); + ASSERT_FALSE(job_id_2); // Run the first AbortTask. Since the background job is still pending, it // can't do anything. @@ -711,10 +720,14 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllRunningWorkerTask) { ASSERT_FALSE(platform.ForegroundTasksPending()); // Now it's possible to enqueue new functions again. - ASSERT_TRUE(dispatcher.Enqueue(shared2)); + job_id_2 = EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2); + ASSERT_TRUE(job_id_2); ASSERT_TRUE(platform.IdleTaskPending()); - ASSERT_FALSE(platform.WorkerTasksPending()); + ASSERT_TRUE(platform.WorkerTasksPending()); ASSERT_FALSE(platform.ForegroundTasksPending()); + + dispatcher.AbortAll(BlockingBehavior::kBlock); + platform.ClearWorkerTasks(); platform.ClearIdleTask(); } @@ -722,28 +735,20 @@ TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared)); - ASSERT_TRUE(platform.IdleTaskPending()); + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); + ASSERT_TRUE(dispatcher.IsEnqueued(shared)); + ASSERT_FALSE(shared->is_compiled()); ASSERT_EQ(dispatcher.jobs_.size(), 1u); ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, dispatcher.jobs_.begin()->second->status()); - - // 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_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - ASSERT_FALSE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_TRUE(platform.IdleTaskPending()); ASSERT_TRUE(platform.WorkerTasksPending()); // Kick off background tasks and freeze them. @@ -764,7 +769,12 @@ TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) { ASSERT_TRUE(dispatcher.abort_); } - // While the background thread holds on to a job, it is still enqueud. + // Run the idle task, which should have already been canceled and won't do + // anything. + ASSERT_TRUE(platform.IdleTaskPending()); + platform.RunIdleTask(5.0, 1.0); + + // While the background thread holds on to a job, it is still enqueued. ASSERT_TRUE(dispatcher.IsEnqueued(shared)); // Release background task. @@ -783,7 +793,7 @@ TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) { } ASSERT_TRUE(platform.ForegroundTasksPending()); - ASSERT_TRUE(platform.IdleTaskPending()); + ASSERT_FALSE(platform.IdleTaskPending()); ASSERT_FALSE(platform.WorkerTasksPending()); platform.RunForegroundTasks(); @@ -791,32 +801,34 @@ TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) { base::LockGuard<base::Mutex> lock(&dispatcher.mutex_); ASSERT_FALSE(dispatcher.abort_); } - - platform.ClearForegroundTasks(); - platform.ClearIdleTask(); } TEST_F(CompilerDispatcherTest, MemoryPressure) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); // Can't enqueue tasks under memory pressure. dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kCritical, true); - ASSERT_FALSE(dispatcher.Enqueue(shared)); + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + ASSERT_FALSE(job_id); dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kNone, true); - ASSERT_TRUE(dispatcher.Enqueue(shared)); + + job_id = EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + ASSERT_TRUE(job_id); // Memory pressure cancels current jobs. dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kCritical, true); - ASSERT_FALSE(dispatcher.IsEnqueued(shared)); + ASSERT_FALSE(dispatcher.IsEnqueued(*job_id)); platform.ClearIdleTask(); + platform.ClearWorkerTasks(); } namespace { @@ -826,7 +838,7 @@ class PressureNotificationTask : public CancelableTask { PressureNotificationTask(Isolate* isolate, CompilerDispatcher* dispatcher, base::Semaphore* sem) : CancelableTask(isolate), dispatcher_(dispatcher), sem_(sem) {} - ~PressureNotificationTask() override {} + ~PressureNotificationTask() override = default; void RunInternal() override { dispatcher_->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical, @@ -847,11 +859,14 @@ TEST_F(CompilerDispatcherTest, MemoryPressureFromBackground) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); + + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); + dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); - ASSERT_TRUE(dispatcher.Enqueue(shared)); base::Semaphore sem(0); V8::GetCurrentPlatform()->CallOnWorkerThread( base::make_unique<PressureNotificationTask>(i_isolate(), &dispatcher, @@ -873,44 +888,6 @@ TEST_F(CompilerDispatcherTest, MemoryPressureFromBackground) { ASSERT_FALSE(platform.ForegroundTasksPending()); platform.ClearIdleTask(); -} - -TEST_F(CompilerDispatcherTest, EnqueueJob) { - MockPlatform platform; - CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); - std::unique_ptr<CompilerDispatcherJob> job( - new UnoptimizedCompileJob(i_isolate(), dispatcher.tracer_.get(), shared, - dispatcher.max_stack_size_)); - ASSERT_FALSE(dispatcher.IsEnqueued(shared)); - dispatcher.Enqueue(std::move(job)); - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - - ASSERT_TRUE(platform.IdleTaskPending()); - platform.ClearIdleTask(); - ASSERT_FALSE(platform.WorkerTasksPending()); -} - -TEST_F(CompilerDispatcherTest, EnqueueAndStep) { - MockPlatform platform; - CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); - - ASSERT_FALSE(dispatcher.IsEnqueued(shared)); - ASSERT_TRUE(dispatcher.EnqueueAndStep(shared)); - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - - ASSERT_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - - ASSERT_TRUE(platform.IdleTaskPending()); - platform.ClearIdleTask(); - ASSERT_TRUE(platform.WorkerTasksPending()); platform.ClearWorkerTasks(); } @@ -919,14 +896,16 @@ TEST_F(CompilerDispatcherTest, CompileLazyFinishesDispatcherJob) { // enqueued functions. CompilerDispatcher* dispatcher = i_isolate()->compiler_dispatcher(); - const char script[] = "function lazy() { return 42; }; lazy;"; + const char raw_script[] = "function lazy() { return 42; }; lazy;"; + test::ScriptResource* script = + new test::ScriptResource(raw_script, strlen(raw_script)); Handle<JSFunction> f = RunJS<JSFunction>(script); 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)); + + base::Optional<CompilerDispatcher::JobId> job_id = + EnqueueUnoptimizedCompileJob(dispatcher, i_isolate(), shared); + dispatcher->RegisterSharedFunctionInfo(*job_id, *shared); // Now force the function to run and ensure CompileLazy finished and dequeues // it from the dispatcher. @@ -940,66 +919,57 @@ TEST_F(CompilerDispatcherTest, CompileLazy2FinishesDispatcherJob) { // enqueued functions. CompilerDispatcher* dispatcher = i_isolate()->compiler_dispatcher(); - const char source2[] = "function lazy2() { return 42; }; lazy2;"; - Handle<JSFunction> lazy2 = RunJS<JSFunction>(source2); - Handle<SharedFunctionInfo> shared2(lazy2->shared(), i_isolate()); - ASSERT_FALSE(shared2->is_compiled()); + const char raw_source_2[] = "function lazy2() { return 42; }; lazy2;"; + test::ScriptResource* source_2 = + new test::ScriptResource(raw_source_2, strlen(raw_source_2)); + Handle<JSFunction> lazy2 = RunJS<JSFunction>(source_2); + Handle<SharedFunctionInfo> shared_2(lazy2->shared(), i_isolate()); + ASSERT_FALSE(shared_2->is_compiled()); - const char source1[] = "function lazy1() { return lazy2(); }; lazy1;"; - Handle<JSFunction> lazy1 = RunJS<JSFunction>(source1); - Handle<SharedFunctionInfo> shared1(lazy1->shared(), i_isolate()); - ASSERT_FALSE(shared1->is_compiled()); + const char raw_source_1[] = "function lazy1() { return lazy2(); }; lazy1;"; + test::ScriptResource* source_1 = + new test::ScriptResource(raw_source_1, strlen(raw_source_1)); + Handle<JSFunction> lazy1 = RunJS<JSFunction>(source_1); + Handle<SharedFunctionInfo> shared_1(lazy1->shared(), i_isolate()); + ASSERT_FALSE(shared_1->is_compiled()); - ASSERT_TRUE(dispatcher->Enqueue(shared1)); - ASSERT_TRUE(dispatcher->Enqueue(shared2)); + base::Optional<CompilerDispatcher::JobId> job_id_1 = + EnqueueUnoptimizedCompileJob(dispatcher, i_isolate(), shared_1); + dispatcher->RegisterSharedFunctionInfo(*job_id_1, *shared_1); - RunJS("lazy1();"); - ASSERT_TRUE(shared1->is_compiled()); - ASSERT_TRUE(shared2->is_compiled()); - ASSERT_FALSE(dispatcher->IsEnqueued(shared1)); - ASSERT_FALSE(dispatcher->IsEnqueued(shared2)); -} + base::Optional<CompilerDispatcher::JobId> job_id_2 = + EnqueueUnoptimizedCompileJob(dispatcher, i_isolate(), shared_2); + dispatcher->RegisterSharedFunctionInfo(*job_id_2, *shared_2); -TEST_F(CompilerDispatcherTest, EnqueueAndStepTwice) { - MockPlatform platform; - CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); + ASSERT_TRUE(dispatcher->IsEnqueued(shared_1)); + ASSERT_TRUE(dispatcher->IsEnqueued(shared_2)); - const char script[] = TEST_SCRIPT(); - Handle<JSFunction> f = RunJS<JSFunction>(script); - Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); - - ASSERT_FALSE(dispatcher.IsEnqueued(shared)); - ASSERT_TRUE(dispatcher.EnqueueAndStep(shared)); - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - ASSERT_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - - // EnqueueAndStep of the same function again (shouldn't step the job. - ASSERT_TRUE(dispatcher.EnqueueAndStep(shared)); - ASSERT_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - - ASSERT_TRUE(platform.IdleTaskPending()); - ASSERT_TRUE(platform.WorkerTasksPending()); - platform.ClearIdleTask(); - platform.ClearWorkerTasks(); + RunJS("lazy1();"); + ASSERT_TRUE(shared_1->is_compiled()); + ASSERT_TRUE(shared_2->is_compiled()); + ASSERT_FALSE(dispatcher->IsEnqueued(shared_1)); + ASSERT_FALSE(dispatcher->IsEnqueued(shared_2)); } TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - const char script1[] = TEST_SCRIPT(); - Handle<JSFunction> f1 = RunJS<JSFunction>(script1); - Handle<SharedFunctionInfo> shared1(f1->shared(), i_isolate()); - const char script2[] = TEST_SCRIPT(); - Handle<JSFunction> f2 = RunJS<JSFunction>(script2); - Handle<SharedFunctionInfo> shared2(f2->shared(), i_isolate()); + Handle<SharedFunctionInfo> shared_1 = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared_1->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_TRUE(dispatcher.Enqueue(shared1)); - ASSERT_TRUE(dispatcher.Enqueue(shared2)); - ASSERT_TRUE(platform.IdleTaskPending()); + Handle<SharedFunctionInfo> shared_2 = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared_2->is_compiled()); + + base::Optional<CompilerDispatcher::JobId> job_id_1 = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_1); + dispatcher.RegisterSharedFunctionInfo(*job_id_1, *shared_1); + + base::Optional<CompilerDispatcher::JobId> job_id_2 = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2); + dispatcher.RegisterSharedFunctionInfo(*job_id_2, *shared_2); ASSERT_EQ(dispatcher.jobs_.size(), 2u); ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, @@ -1007,21 +977,11 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) { ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, (++dispatcher.jobs_.begin())->second->status()); - // 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_EQ(dispatcher.jobs_.size(), 2u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kPrepared, - dispatcher.jobs_.begin()->second->status()); - ASSERT_EQ(UnoptimizedCompileJob::Status::kPrepared, - (++dispatcher.jobs_.begin())->second->status()); - - ASSERT_TRUE(dispatcher.IsEnqueued(shared1)); - ASSERT_TRUE(dispatcher.IsEnqueued(shared2)); - ASSERT_FALSE(shared1->is_compiled()); - ASSERT_FALSE(shared2->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_TRUE(dispatcher.IsEnqueued(shared_1)); + ASSERT_TRUE(dispatcher.IsEnqueued(shared_2)); + ASSERT_FALSE(shared_1->is_compiled()); + ASSERT_FALSE(shared_2->is_compiled()); + ASSERT_TRUE(platform.IdleTaskPending()); ASSERT_TRUE(platform.WorkerTasksPending()); platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); @@ -1029,26 +989,20 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) { ASSERT_TRUE(platform.IdleTaskPending()); ASSERT_FALSE(platform.WorkerTasksPending()); ASSERT_EQ(dispatcher.jobs_.size(), 2u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kCompiled, + ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToFinalize, dispatcher.jobs_.begin()->second->status()); - ASSERT_EQ(UnoptimizedCompileJob::Status::kCompiled, + ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToFinalize, (++dispatcher.jobs_.begin())->second->status()); // Now grant a lot of idle time and freeze time. 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()); + ASSERT_FALSE(dispatcher.IsEnqueued(shared_1)); + ASSERT_FALSE(dispatcher.IsEnqueued(shared_2)); + ASSERT_TRUE(shared_1->is_compiled()); + ASSERT_TRUE(shared_2->is_compiled()); ASSERT_FALSE(platform.IdleTaskPending()); } -#undef _STR -#undef STR -#undef _SCRIPT -#undef SCRIPT -#undef TEST_SCRIPT - } // namespace internal } // namespace v8 |