diff options
Diffstat (limited to 'deps/v8/test/unittests/background-compile-task-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/background-compile-task-unittest.cc | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/deps/v8/test/unittests/background-compile-task-unittest.cc b/deps/v8/test/unittests/background-compile-task-unittest.cc new file mode 100644 index 0000000000..5bb6b68285 --- /dev/null +++ b/deps/v8/test/unittests/background-compile-task-unittest.cc @@ -0,0 +1,267 @@ +// Copyright 2018 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 "include/v8.h" +#include "src/api-inl.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.h" +#include "src/flags.h" +#include "src/isolate-inl.h" +#include "src/objects/smi.h" +#include "src/parsing/parse-info.h" +#include "src/parsing/parser.h" +#include "src/parsing/preparse-data.h" +#include "src/v8.h" +#include "test/unittests/test-helpers.h" +#include "test/unittests/test-utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { +namespace internal { + +class BackgroundCompileTaskTest : public TestWithNativeContext { + public: + BackgroundCompileTaskTest() : allocator_(isolate()->allocator()) {} + ~BackgroundCompileTaskTest() override = default; + + AccountingAllocator* allocator() { return allocator_; } + + static void SetUpTestCase() { + CHECK_NULL(save_flags_); + save_flags_ = new SaveFlags(); + TestWithNativeContext ::SetUpTestCase(); + } + + static void TearDownTestCase() { + TestWithNativeContext ::TearDownTestCase(); + CHECK_NOT_NULL(save_flags_); + delete save_flags_; + save_flags_ = nullptr; + } + + BackgroundCompileTask* NewBackgroundCompileTask( + Isolate* isolate, Handle<SharedFunctionInfo> shared, + size_t stack_size = FLAG_stack_size) { + 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()); + std::vector<void*> buffer; + ScopedPtrList<Statement> statements(&buffer); + const FunctionLiteral* function_literal = + ast_node_factory.NewFunctionLiteral( + function_name, function_scope, statements, -1, -1, -1, + FunctionLiteral::kNoDuplicateParameters, + FunctionLiteral::kAnonymousExpression, + FunctionLiteral::kShouldEagerCompile, shared->StartPosition(), true, + shared->FunctionLiteralId(isolate), nullptr); + + return new BackgroundCompileTask( + allocator(), outer_parse_info.get(), function_name, function_literal, + isolate->counters()->worker_thread_runtime_call_stats(), + isolate->counters()->compile_function_on_background(), FLAG_stack_size); + } + + private: + AccountingAllocator* allocator_; + static SaveFlags* save_flags_; + + DISALLOW_COPY_AND_ASSIGN(BackgroundCompileTaskTest); +}; + +SaveFlags* BackgroundCompileTaskTest::save_flags_ = nullptr; + +TEST_F(BackgroundCompileTaskTest, Construct) { + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(isolate(), nullptr); + ASSERT_FALSE(shared->is_compiled()); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); +} + +TEST_F(BackgroundCompileTaskTest, SyntaxError) { + test::ScriptResource* script = new test::ScriptResource("^^^", strlen("^^^")); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(isolate(), script); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); + + task->Run(); + ASSERT_FALSE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); + ASSERT_TRUE(isolate()->has_pending_exception()); + + isolate()->clear_pending_exception(); +} + +TEST_F(BackgroundCompileTaskTest, CompileAndRun) { + const char raw_script[] = + "function g() {\n" + " f = function(a) {\n" + " for (var i = 0; i < 3; i++) { a += 20; }\n" + " return a;\n" + " }\n" + " return f;\n" + "}\n" + "g();"; + test::ScriptResource* script = + new test::ScriptResource(raw_script, strlen(raw_script)); + Handle<JSFunction> f = RunJS<JSFunction>(script); + Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate()); + ASSERT_FALSE(shared->is_compiled()); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); + + task->Run(); + ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); + ASSERT_TRUE(shared->is_compiled()); + + Smi value = Smi::cast(*RunJS("f(100);")); + ASSERT_TRUE(value == Smi::FromInt(160)); +} + +TEST_F(BackgroundCompileTaskTest, CompileFailure) { + std::string raw_script("() { var a = "); + for (int i = 0; i < 10000; i++) { + // TODO(leszeks): Figure out a more "unit-test-y" way of forcing an analysis + // failure than a binop stack overflow. + + // Alternate + and - to avoid n-ary operation nodes. + raw_script += "'x' + 'x' - "; + } + raw_script += " 'x'; }"; + test::ScriptResource* script = + new test::ScriptResource(raw_script.c_str(), strlen(raw_script.c_str())); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(isolate(), script); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared, 100)); + + task->Run(); + ASSERT_FALSE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); + ASSERT_TRUE(isolate()->has_pending_exception()); + + isolate()->clear_pending_exception(); +} + +class CompileTask : public Task { + public: + CompileTask(BackgroundCompileTask* task, base::Semaphore* semaphore) + : task_(task), semaphore_(semaphore) {} + ~CompileTask() override = default; + + void Run() override { + task_->Run(); + semaphore_->Signal(); + } + + private: + BackgroundCompileTask* task_; + base::Semaphore* semaphore_; + DISALLOW_COPY_AND_ASSIGN(CompileTask); +}; + +TEST_F(BackgroundCompileTaskTest, CompileOnBackgroundThread) { + const char* raw_script = + "(a, b) {\n" + " var c = a + b;\n" + " function bar() { return b }\n" + " var d = { foo: 100, bar : bar() }\n" + " return bar;" + "}"; + test::ScriptResource* script = + new test::ScriptResource(raw_script, strlen(raw_script)); + Handle<SharedFunctionInfo> shared = + test::CreateSharedFunctionInfo(isolate(), script); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); + + base::Semaphore semaphore(0); + auto background_task = base::make_unique<CompileTask>(task.get(), &semaphore); + + V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(background_task)); + semaphore.Wait(); + ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); + ASSERT_TRUE(shared->is_compiled()); +} + +TEST_F(BackgroundCompileTaskTest, EagerInnerFunctions) { + const char raw_script[] = + "function g() {\n" + " f = function() {\n" + " // Simulate an eager IIFE with brackets.\n " + " var e = (function () { return 42; });\n" + " return e;\n" + " }\n" + " return f;\n" + "}\n" + "g();"; + test::ScriptResource* script = + new test::ScriptResource(raw_script, strlen(raw_script)); + Handle<JSFunction> f = RunJS<JSFunction>(script); + Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate()); + ASSERT_FALSE(shared->is_compiled()); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); + + task->Run(); + ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); + ASSERT_TRUE(shared->is_compiled()); + + Handle<JSFunction> e = RunJS<JSFunction>("f();"); + + ASSERT_TRUE(e->shared()->is_compiled()); +} + +TEST_F(BackgroundCompileTaskTest, LazyInnerFunctions) { + const char raw_script[] = + "function g() {\n" + " f = function() {\n" + " function e() { return 42; };\n" + " return e;\n" + " }\n" + " return f;\n" + "}\n" + "g();"; + test::ScriptResource* script = + new test::ScriptResource(raw_script, strlen(raw_script)); + Handle<JSFunction> f = RunJS<JSFunction>(script); + Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate()); + ASSERT_FALSE(shared->is_compiled()); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); + + task->Run(); + ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); + ASSERT_TRUE(shared->is_compiled()); + + Handle<JSFunction> e = RunJS<JSFunction>("f();"); + + ASSERT_FALSE(e->shared()->is_compiled()); +} + +} // namespace internal +} // namespace v8 |