LCOV - code coverage report
Current view: top level - test/unittests - background-compile-task-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 97 97 100.0 %
Date: 2019-01-20 Functions: 21 31 67.7 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <memory>
       6             : 
       7             : #include "include/v8.h"
       8             : #include "src/api-inl.h"
       9             : #include "src/ast/ast.h"
      10             : #include "src/ast/scopes.h"
      11             : #include "src/base/platform/semaphore.h"
      12             : #include "src/base/template-utils.h"
      13             : #include "src/compiler.h"
      14             : #include "src/flags.h"
      15             : #include "src/isolate-inl.h"
      16             : #include "src/objects/smi.h"
      17             : #include "src/parsing/parse-info.h"
      18             : #include "src/parsing/parser.h"
      19             : #include "src/parsing/preparse-data.h"
      20             : #include "src/v8.h"
      21             : #include "test/unittests/test-helpers.h"
      22             : #include "test/unittests/test-utils.h"
      23             : #include "testing/gtest/include/gtest/gtest.h"
      24             : 
      25             : namespace v8 {
      26             : namespace internal {
      27             : 
      28             : class BackgroundCompileTaskTest : public TestWithNativeContext {
      29             :  public:
      30          14 :   BackgroundCompileTaskTest() : allocator_(isolate()->allocator()) {}
      31           7 :   ~BackgroundCompileTaskTest() override = default;
      32             : 
      33             :   AccountingAllocator* allocator() { return allocator_; }
      34             : 
      35           7 :   static void SetUpTestCase() {
      36           7 :     CHECK_NULL(save_flags_);
      37           7 :     save_flags_ = new SaveFlags();
      38             :     TestWithNativeContext ::SetUpTestCase();
      39           7 :   }
      40             : 
      41           7 :   static void TearDownTestCase() {
      42             :     TestWithNativeContext ::TearDownTestCase();
      43           7 :     CHECK_NOT_NULL(save_flags_);
      44           7 :     delete save_flags_;
      45           7 :     save_flags_ = nullptr;
      46           7 :   }
      47             : 
      48           7 :   BackgroundCompileTask* NewBackgroundCompileTask(
      49             :       Isolate* isolate, Handle<SharedFunctionInfo> shared,
      50           7 :       size_t stack_size = FLAG_stack_size) {
      51             :     std::unique_ptr<ParseInfo> outer_parse_info =
      52           7 :         test::OuterParseInfoForShared(isolate, shared);
      53             :     AstValueFactory* ast_value_factory =
      54           7 :         outer_parse_info->GetOrCreateAstValueFactory();
      55             :     AstNodeFactory ast_node_factory(ast_value_factory,
      56           7 :                                     outer_parse_info->zone());
      57             : 
      58             :     const AstRawString* function_name =
      59           7 :         ast_value_factory->GetOneByteString("f");
      60             :     DeclarationScope* script_scope = new (outer_parse_info->zone())
      61           7 :         DeclarationScope(outer_parse_info->zone(), ast_value_factory);
      62             :     DeclarationScope* function_scope =
      63             :         new (outer_parse_info->zone()) DeclarationScope(
      64           7 :             outer_parse_info->zone(), script_scope, FUNCTION_SCOPE);
      65          14 :     function_scope->set_start_position(shared->StartPosition());
      66          14 :     function_scope->set_end_position(shared->EndPosition());
      67             :     std::vector<void*> buffer;
      68             :     ScopedPtrList<Statement> statements(&buffer);
      69             :     const FunctionLiteral* function_literal =
      70             :         ast_node_factory.NewFunctionLiteral(
      71             :             function_name, function_scope, statements, -1, -1, -1,
      72             :             FunctionLiteral::kNoDuplicateParameters,
      73             :             FunctionLiteral::kAnonymousExpression,
      74             :             FunctionLiteral::kShouldEagerCompile, shared->StartPosition(), true,
      75          14 :             shared->FunctionLiteralId(isolate), nullptr);
      76             : 
      77             :     return new BackgroundCompileTask(
      78             :         allocator(), outer_parse_info.get(), function_name, function_literal,
      79             :         isolate->counters()->worker_thread_runtime_call_stats(),
      80          14 :         isolate->counters()->compile_function_on_background(), FLAG_stack_size);
      81             :   }
      82             : 
      83             :  private:
      84             :   AccountingAllocator* allocator_;
      85             :   static SaveFlags* save_flags_;
      86             : 
      87             :   DISALLOW_COPY_AND_ASSIGN(BackgroundCompileTaskTest);
      88             : };
      89             : 
      90             : SaveFlags* BackgroundCompileTaskTest::save_flags_ = nullptr;
      91             : 
      92       15129 : TEST_F(BackgroundCompileTaskTest, Construct) {
      93             :   Handle<SharedFunctionInfo> shared =
      94           1 :       test::CreateSharedFunctionInfo(isolate(), nullptr);
      95           3 :   ASSERT_FALSE(shared->is_compiled());
      96             :   std::unique_ptr<BackgroundCompileTask> task(
      97           2 :       NewBackgroundCompileTask(isolate(), shared));
      98             : }
      99             : 
     100       15129 : TEST_F(BackgroundCompileTaskTest, SyntaxError) {
     101           1 :   test::ScriptResource* script = new test::ScriptResource("^^^", strlen("^^^"));
     102             :   Handle<SharedFunctionInfo> shared =
     103           1 :       test::CreateSharedFunctionInfo(isolate(), script);
     104             :   std::unique_ptr<BackgroundCompileTask> task(
     105           2 :       NewBackgroundCompileTask(isolate(), shared));
     106             : 
     107           1 :   task->Run();
     108           2 :   ASSERT_FALSE(Compiler::FinalizeBackgroundCompileTask(
     109             :       task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION));
     110           2 :   ASSERT_TRUE(isolate()->has_pending_exception());
     111             : 
     112           1 :   isolate()->clear_pending_exception();
     113             : }
     114             : 
     115       15129 : TEST_F(BackgroundCompileTaskTest, CompileAndRun) {
     116             :   const char raw_script[] =
     117             :       "function g() {\n"
     118             :       "  f = function(a) {\n"
     119             :       "        for (var i = 0; i < 3; i++) { a += 20; }\n"
     120             :       "        return a;\n"
     121             :       "      }\n"
     122             :       "  return f;\n"
     123             :       "}\n"
     124           1 :       "g();";
     125             :   test::ScriptResource* script =
     126           1 :       new test::ScriptResource(raw_script, strlen(raw_script));
     127           1 :   Handle<JSFunction> f = RunJS<JSFunction>(script);
     128           2 :   Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate());
     129           2 :   ASSERT_FALSE(shared->is_compiled());
     130             :   std::unique_ptr<BackgroundCompileTask> task(
     131           2 :       NewBackgroundCompileTask(isolate(), shared));
     132             : 
     133           1 :   task->Run();
     134           2 :   ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask(
     135             :       task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION));
     136           2 :   ASSERT_TRUE(shared->is_compiled());
     137             : 
     138           2 :   Smi value = Smi::cast(*RunJS("f(100);"));
     139           1 :   ASSERT_TRUE(value == Smi::FromInt(160));
     140             : }
     141             : 
     142       15129 : TEST_F(BackgroundCompileTaskTest, CompileFailure) {
     143           1 :   std::string raw_script("() { var a = ");
     144       10001 :   for (int i = 0; i < 10000; i++) {
     145             :     // TODO(leszeks): Figure out a more "unit-test-y" way of forcing an analysis
     146             :     // failure than a binop stack overflow.
     147             : 
     148             :     // Alternate + and - to avoid n-ary operation nodes.
     149             :     raw_script += "'x' + 'x' - ";
     150             :   }
     151             :   raw_script += " 'x'; }";
     152             :   test::ScriptResource* script =
     153           1 :       new test::ScriptResource(raw_script.c_str(), strlen(raw_script.c_str()));
     154             :   Handle<SharedFunctionInfo> shared =
     155           1 :       test::CreateSharedFunctionInfo(isolate(), script);
     156             :   std::unique_ptr<BackgroundCompileTask> task(
     157           1 :       NewBackgroundCompileTask(isolate(), shared, 100));
     158             : 
     159           1 :   task->Run();
     160           2 :   ASSERT_FALSE(Compiler::FinalizeBackgroundCompileTask(
     161             :       task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION));
     162           2 :   ASSERT_TRUE(isolate()->has_pending_exception());
     163             : 
     164           1 :   isolate()->clear_pending_exception();
     165             : }
     166             : 
     167             : class CompileTask : public Task {
     168             :  public:
     169             :   CompileTask(BackgroundCompileTask* task, base::Semaphore* semaphore)
     170           1 :       : task_(task), semaphore_(semaphore) {}
     171           2 :   ~CompileTask() override = default;
     172             : 
     173           1 :   void Run() override {
     174           1 :     task_->Run();
     175           1 :     semaphore_->Signal();
     176           1 :   }
     177             : 
     178             :  private:
     179             :   BackgroundCompileTask* task_;
     180             :   base::Semaphore* semaphore_;
     181             :   DISALLOW_COPY_AND_ASSIGN(CompileTask);
     182             : };
     183             : 
     184       15129 : TEST_F(BackgroundCompileTaskTest, CompileOnBackgroundThread) {
     185             :   const char* raw_script =
     186             :       "(a, b) {\n"
     187             :       "  var c = a + b;\n"
     188             :       "  function bar() { return b }\n"
     189             :       "  var d = { foo: 100, bar : bar() }\n"
     190             :       "  return bar;"
     191             :       "}";
     192             :   test::ScriptResource* script =
     193           1 :       new test::ScriptResource(raw_script, strlen(raw_script));
     194             :   Handle<SharedFunctionInfo> shared =
     195           1 :       test::CreateSharedFunctionInfo(isolate(), script);
     196             :   std::unique_ptr<BackgroundCompileTask> task(
     197           2 :       NewBackgroundCompileTask(isolate(), shared));
     198             : 
     199           2 :   base::Semaphore semaphore(0);
     200             :   auto background_task = base::make_unique<CompileTask>(task.get(), &semaphore);
     201             : 
     202           3 :   V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(background_task));
     203           1 :   semaphore.Wait();
     204           2 :   ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask(
     205             :       task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION));
     206           2 :   ASSERT_TRUE(shared->is_compiled());
     207             : }
     208             : 
     209       15129 : TEST_F(BackgroundCompileTaskTest, EagerInnerFunctions) {
     210             :   const char raw_script[] =
     211             :       "function g() {\n"
     212             :       "  f = function() {\n"
     213             :       "    // Simulate an eager IIFE with brackets.\n "
     214             :       "    var e = (function () { return 42; });\n"
     215             :       "    return e;\n"
     216             :       "  }\n"
     217             :       "  return f;\n"
     218             :       "}\n"
     219           1 :       "g();";
     220             :   test::ScriptResource* script =
     221           1 :       new test::ScriptResource(raw_script, strlen(raw_script));
     222           1 :   Handle<JSFunction> f = RunJS<JSFunction>(script);
     223           2 :   Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate());
     224           2 :   ASSERT_FALSE(shared->is_compiled());
     225             :   std::unique_ptr<BackgroundCompileTask> task(
     226           2 :       NewBackgroundCompileTask(isolate(), shared));
     227             : 
     228           1 :   task->Run();
     229           2 :   ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask(
     230             :       task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION));
     231           2 :   ASSERT_TRUE(shared->is_compiled());
     232             : 
     233           1 :   Handle<JSFunction> e = RunJS<JSFunction>("f();");
     234             : 
     235           2 :   ASSERT_TRUE(e->shared()->is_compiled());
     236             : }
     237             : 
     238       15129 : TEST_F(BackgroundCompileTaskTest, LazyInnerFunctions) {
     239             :   const char raw_script[] =
     240             :       "function g() {\n"
     241             :       "  f = function() {\n"
     242             :       "    function e() { return 42; };\n"
     243             :       "    return e;\n"
     244             :       "  }\n"
     245             :       "  return f;\n"
     246             :       "}\n"
     247           1 :       "g();";
     248             :   test::ScriptResource* script =
     249           1 :       new test::ScriptResource(raw_script, strlen(raw_script));
     250           1 :   Handle<JSFunction> f = RunJS<JSFunction>(script);
     251           2 :   Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate());
     252           2 :   ASSERT_FALSE(shared->is_compiled());
     253             :   std::unique_ptr<BackgroundCompileTask> task(
     254           2 :       NewBackgroundCompileTask(isolate(), shared));
     255             : 
     256           1 :   task->Run();
     257           2 :   ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask(
     258             :       task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION));
     259           2 :   ASSERT_TRUE(shared->is_compiled());
     260             : 
     261           1 :   Handle<JSFunction> e = RunJS<JSFunction>("f();");
     262             : 
     263           2 :   ASSERT_FALSE(e->shared()->is_compiled());
     264             : }
     265             : 
     266             : }  // namespace internal
     267        9075 : }  // namespace v8

Generated by: LCOV version 1.10