aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/test/unittests/background-compile-task-unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/unittests/background-compile-task-unittest.cc')
-rw-r--r--deps/v8/test/unittests/background-compile-task-unittest.cc267
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