LCOV - code coverage report
Current view: top level - test/cctest - test-lockers.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 394 394 100.0 %
Date: 2017-10-20 Functions: 59 67 88.1 %

          Line data    Source code
       1             : // Copyright 2007-2011 the V8 project authors. All rights reserved.
       2             : // Redistribution and use in source and binary forms, with or without
       3             : // modification, are permitted provided that the following conditions are
       4             : // met:
       5             : //
       6             : //     * Redistributions of source code must retain the above copyright
       7             : //       notice, this list of conditions and the following disclaimer.
       8             : //     * Redistributions in binary form must reproduce the above
       9             : //       copyright notice, this list of conditions and the following
      10             : //       disclaimer in the documentation and/or other materials provided
      11             : //       with the distribution.
      12             : //     * Neither the name of Google Inc. nor the names of its
      13             : //       contributors may be used to endorse or promote products derived
      14             : //       from this software without specific prior written permission.
      15             : //
      16             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      17             : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      18             : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      19             : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      20             : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      22             : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23             : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      26             : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             : 
      28             : #include <limits.h>
      29             : 
      30             : #include <memory>
      31             : 
      32             : #include "src/v8.h"
      33             : 
      34             : #include "src/api.h"
      35             : #include "src/base/platform/platform.h"
      36             : #include "src/compilation-cache.h"
      37             : #include "src/execution.h"
      38             : #include "src/isolate.h"
      39             : #include "src/objects-inl.h"
      40             : #include "src/unicode-inl.h"
      41             : #include "src/utils.h"
      42             : #include "test/cctest/cctest.h"
      43             : 
      44             : namespace {
      45             : 
      46          15 : class DeoptimizeCodeThread : public v8::base::Thread {
      47             :  public:
      48          15 :   DeoptimizeCodeThread(v8::Isolate* isolate, v8::Local<v8::Context> context,
      49             :                        const char* trigger)
      50             :       : Thread(Options("DeoptimizeCodeThread")),
      51             :         isolate_(isolate),
      52             :         context_(isolate, context),
      53          30 :         source_(trigger) {}
      54             : 
      55          15 :   void Run() {
      56          15 :     v8::Locker locker(isolate_);
      57          15 :     isolate_->Enter();
      58          30 :     v8::HandleScope handle_scope(isolate_);
      59             :     v8::Local<v8::Context> context =
      60          15 :         v8::Local<v8::Context>::New(isolate_, context_);
      61             :     v8::Context::Scope context_scope(context);
      62          15 :     CHECK_EQ(isolate_, v8::Isolate::GetCurrent());
      63             :     // This code triggers deoptimization of some function that will be
      64             :     // used in a different thread.
      65          15 :     CompileRun(source_);
      66          30 :     isolate_->Exit();
      67          15 :   }
      68             : 
      69             :  private:
      70             :   v8::Isolate* isolate_;
      71             :   v8::Persistent<v8::Context> context_;
      72             :   // The code that triggers the deoptimization.
      73             :   const char* source_;
      74             : };
      75             : 
      76           5 : void UnlockForDeoptimization(const v8::FunctionCallbackInfo<v8::Value>& args) {
      77           5 :   v8::Isolate* isolate = v8::Isolate::GetCurrent();
      78             :   // Gets the pointer to the thread that will trigger the deoptimization of the
      79             :   // code.
      80             :   DeoptimizeCodeThread* deoptimizer =
      81             :       reinterpret_cast<DeoptimizeCodeThread*>(isolate->GetData(0));
      82             :   {
      83             :     // Exits and unlocks the isolate.
      84           5 :     isolate->Exit();
      85             :     v8::Unlocker unlocker(isolate);
      86             :     // Starts the deoptimizing thread.
      87           5 :     deoptimizer->Start();
      88             :     // Waits for deoptimization to finish.
      89           5 :     deoptimizer->Join();
      90             :   }
      91             :   // The deoptimizing thread has finished its work, and the isolate
      92             :   // will now be used by the current thread.
      93           5 :   isolate->Enter();
      94           5 : }
      95             : 
      96          40 : void UnlockForDeoptimizationIfReady(
      97             :     const v8::FunctionCallbackInfo<v8::Value>& args) {
      98          40 :   v8::Isolate* isolate = v8::Isolate::GetCurrent();
      99             :   bool* ready_to_deoptimize = reinterpret_cast<bool*>(isolate->GetData(1));
     100          40 :   if (*ready_to_deoptimize) {
     101             :     // The test should enter here only once, so put the flag back to false.
     102          10 :     *ready_to_deoptimize = false;
     103             :     // Gets the pointer to the thread that will trigger the deoptimization of
     104             :     // the code.
     105             :     DeoptimizeCodeThread* deoptimizer =
     106             :         reinterpret_cast<DeoptimizeCodeThread*>(isolate->GetData(0));
     107             :     {
     108             :       // Exits and unlocks the thread.
     109          10 :       isolate->Exit();
     110             :       v8::Unlocker unlocker(isolate);
     111             :       // Starts the thread that deoptimizes the function.
     112          10 :       deoptimizer->Start();
     113             :       // Waits for the deoptimizing thread to finish.
     114          10 :       deoptimizer->Join();
     115             :     }
     116             :     // The deoptimizing thread has finished its work, and the isolate
     117             :     // will now be used by the current thread.
     118          10 :     isolate->Enter();
     119             :   }
     120          40 : }
     121             : }  // namespace
     122             : 
     123             : namespace v8 {
     124             : namespace internal {
     125             : namespace test_lockers {
     126             : 
     127       23723 : TEST(LazyDeoptimizationMultithread) {
     128           5 :   i::FLAG_allow_natives_syntax = true;
     129             :   v8::Isolate::CreateParams create_params;
     130           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     131           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     132             :   {
     133             :     v8::Locker locker(isolate);
     134             :     v8::Isolate::Scope isolate_scope(isolate);
     135          10 :     v8::HandleScope scope(isolate);
     136           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
     137             :     const char* trigger_deopt = "obj = { y: 0, x: 1 };";
     138             : 
     139             :     // We use the isolate to pass arguments to the UnlockForDeoptimization
     140             :     // function. Namely, we pass a pointer to the deoptimizing thread.
     141           5 :     DeoptimizeCodeThread deoptimize_thread(isolate, context, trigger_deopt);
     142             :     isolate->SetData(0, &deoptimize_thread);
     143             :     v8::Context::Scope context_scope(context);
     144             : 
     145             :     // Create the function templace for C++ code that is invoked from
     146             :     // JavaScript code.
     147             :     Local<v8::FunctionTemplate> fun_templ =
     148           5 :         v8::FunctionTemplate::New(isolate, UnlockForDeoptimization);
     149           5 :     Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
     150          20 :     CHECK(context->Global()
     151             :               ->Set(context, v8_str("unlock_for_deoptimization"), fun)
     152             :               .FromJust());
     153             : 
     154             :     // Optimizes a function f, which will be deoptimized in another
     155             :     // thread.
     156             :     CompileRun(
     157             :         "var b = false; var obj = { x: 1 };"
     158             :         "function f() { g(); return obj.x; }"
     159             :         "function g() { if (b) { unlock_for_deoptimization(); } }"
     160             :         "%NeverOptimizeFunction(g);"
     161             :         "f(); f(); %OptimizeFunctionOnNextCall(f);"
     162             :         "f();");
     163             : 
     164             :     // Trigger the unlocking.
     165             :     Local<Value> v = CompileRun("b = true; f();");
     166             : 
     167             :     // Once the isolate has been unlocked, the thread will wait for the
     168             :     // other thread to finish its task. Once this happens, this thread
     169             :     // continues with its execution, that is, with the execution of the
     170             :     // function g, which then returns to f. The function f should have
     171             :     // also been deoptimized. If the replacement did not happen on this
     172             :     // thread's stack, then the test will fail here.
     173           5 :     CHECK(v->IsNumber());
     174          15 :     CHECK_EQ(1, static_cast<int>(v->NumberValue(context).FromJust()));
     175             :   }
     176           5 :   isolate->Dispose();
     177           5 : }
     178             : 
     179       23723 : TEST(LazyDeoptimizationMultithreadWithNatives) {
     180           5 :   i::FLAG_allow_natives_syntax = true;
     181             :   v8::Isolate::CreateParams create_params;
     182           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     183           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     184             :   {
     185             :     v8::Locker locker(isolate);
     186             :     v8::Isolate::Scope isolate_scope(isolate);
     187          10 :     v8::HandleScope scope(isolate);
     188           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
     189             :     const char* trigger_deopt = "%DeoptimizeFunction(f);";
     190             : 
     191             :     // We use the isolate to pass arguments to the UnlockForDeoptimization
     192             :     // function. Namely, we pass a pointer to the deoptimizing thread.
     193           5 :     DeoptimizeCodeThread deoptimize_thread(isolate, context, trigger_deopt);
     194             :     isolate->SetData(0, &deoptimize_thread);
     195           5 :     bool ready_to_deopt = false;
     196             :     isolate->SetData(1, &ready_to_deopt);
     197             :     v8::Context::Scope context_scope(context);
     198             : 
     199             :     // Create the function templace for C++ code that is invoked from
     200             :     // JavaScript code.
     201             :     Local<v8::FunctionTemplate> fun_templ =
     202           5 :         v8::FunctionTemplate::New(isolate, UnlockForDeoptimizationIfReady);
     203           5 :     Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
     204          20 :     CHECK(context->Global()
     205             :               ->Set(context, v8_str("unlock_for_deoptimization"), fun)
     206             :               .FromJust());
     207             : 
     208             :     // Optimizes a function f, which will be deoptimized in another
     209             :     // thread.
     210             :     CompileRun(
     211             :         "var obj = { x: 1 };"
     212             :         "function f() { g(); return obj.x;}"
     213             :         "function g() { "
     214             :         "  unlock_for_deoptimization(); }"
     215             :         "%NeverOptimizeFunction(g);"
     216             :         "f(); f(); %OptimizeFunctionOnNextCall(f);");
     217             : 
     218             :     // Trigger the unlocking.
     219           5 :     ready_to_deopt = true;
     220             :     isolate->SetData(1, &ready_to_deopt);
     221             :     Local<Value> v = CompileRun("f();");
     222             : 
     223             :     // Once the isolate has been unlocked, the thread will wait for the
     224             :     // other thread to finish its task. Once this happens, this thread
     225             :     // continues with its execution, that is, with the execution of the
     226             :     // function g, which then returns to f. The function f should have
     227             :     // also been deoptimized. Otherwise, the test will fail here.
     228           5 :     CHECK(v->IsNumber());
     229          15 :     CHECK_EQ(1, static_cast<int>(v->NumberValue(context).FromJust()));
     230             :   }
     231           5 :   isolate->Dispose();
     232           5 : }
     233             : 
     234       23723 : TEST(EagerDeoptimizationMultithread) {
     235           5 :   i::FLAG_allow_natives_syntax = true;
     236             :   v8::Isolate::CreateParams create_params;
     237           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     238           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     239             :   {
     240             :     v8::Locker locker(isolate);
     241             :     v8::Isolate::Scope isolate_scope(isolate);
     242          10 :     v8::HandleScope scope(isolate);
     243           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
     244             :     const char* trigger_deopt = "f({y: 0, x: 1});";
     245             : 
     246             :     // We use the isolate to pass arguments to the UnlockForDeoptimization
     247             :     // function. Namely, we pass a pointer to the deoptimizing thread.
     248           5 :     DeoptimizeCodeThread deoptimize_thread(isolate, context, trigger_deopt);
     249             :     isolate->SetData(0, &deoptimize_thread);
     250           5 :     bool ready_to_deopt = false;
     251             :     isolate->SetData(1, &ready_to_deopt);
     252             :     v8::Context::Scope context_scope(context);
     253             : 
     254             :     // Create the function templace for C++ code that is invoked from
     255             :     // JavaScript code.
     256             :     Local<v8::FunctionTemplate> fun_templ =
     257           5 :         v8::FunctionTemplate::New(isolate, UnlockForDeoptimizationIfReady);
     258           5 :     Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
     259          20 :     CHECK(context->Global()
     260             :               ->Set(context, v8_str("unlock_for_deoptimization"), fun)
     261             :               .FromJust());
     262             : 
     263             :     // Optimizes a function f, which will be deoptimized by another thread.
     264             :     CompileRun(
     265             :         "function f(obj) { unlock_for_deoptimization(); return obj.x; }"
     266             :         "f({x: 1}); f({x: 1});"
     267             :         "%OptimizeFunctionOnNextCall(f);"
     268             :         "f({x: 1});");
     269             : 
     270             :     // Trigger the unlocking.
     271           5 :     ready_to_deopt = true;
     272             :     isolate->SetData(1, &ready_to_deopt);
     273             :     Local<Value> v = CompileRun("f({x: 1});");
     274             : 
     275             :     // Once the isolate has been unlocked, the thread will wait for the
     276             :     // other thread to finish its task. Once this happens, this thread
     277             :     // continues with its execution, that is, with the execution of the
     278             :     // function g, which then returns to f. The function f should have
     279             :     // also been deoptimized. Otherwise, the test will fail here.
     280           5 :     CHECK(v->IsNumber());
     281          15 :     CHECK_EQ(1, static_cast<int>(v->NumberValue(context).FromJust()));
     282             :   }
     283           5 :   isolate->Dispose();
     284           5 : }
     285             : 
     286             : // Migrating an isolate
     287           5 : class KangarooThread : public v8::base::Thread {
     288             :  public:
     289           5 :   KangarooThread(v8::Isolate* isolate, v8::Local<v8::Context> context)
     290             :       : Thread(Options("KangarooThread")),
     291             :         isolate_(isolate),
     292          10 :         context_(isolate, context) {}
     293             : 
     294           5 :   void Run() {
     295             :     {
     296           5 :       v8::Locker locker(isolate_);
     297           5 :       v8::Isolate::Scope isolate_scope(isolate_);
     298           5 :       CHECK_EQ(isolate_, v8::Isolate::GetCurrent());
     299          10 :       v8::HandleScope scope(isolate_);
     300             :       v8::Local<v8::Context> context =
     301           5 :           v8::Local<v8::Context>::New(isolate_, context_);
     302             :       v8::Context::Scope context_scope(context);
     303             :       Local<Value> v = CompileRun("getValue()");
     304           5 :       CHECK(v->IsNumber());
     305          15 :       CHECK_EQ(30, static_cast<int>(v->NumberValue(context).FromJust()));
     306             :     }
     307             :     {
     308           5 :       v8::Locker locker(isolate_);
     309           5 :       v8::Isolate::Scope isolate_scope(isolate_);
     310          10 :       v8::HandleScope scope(isolate_);
     311             :       v8::Local<v8::Context> context =
     312           5 :           v8::Local<v8::Context>::New(isolate_, context_);
     313             :       v8::Context::Scope context_scope(context);
     314             :       Local<Value> v = CompileRun("getValue()");
     315           5 :       CHECK(v->IsNumber());
     316          15 :       CHECK_EQ(30, static_cast<int>(v->NumberValue(context).FromJust()));
     317             :     }
     318           5 :     isolate_->Dispose();
     319           5 :   }
     320             : 
     321             :  private:
     322             :   v8::Isolate* isolate_;
     323             :   v8::Persistent<v8::Context> context_;
     324             : };
     325             : 
     326             : 
     327             : // Migrates an isolate from one thread to another
     328       23723 : TEST(KangarooIsolates) {
     329             :   v8::Isolate::CreateParams create_params;
     330           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     331           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     332             :   std::unique_ptr<KangarooThread> thread1;
     333             :   {
     334             :     v8::Locker locker(isolate);
     335             :     v8::Isolate::Scope isolate_scope(isolate);
     336          10 :     v8::HandleScope handle_scope(isolate);
     337           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
     338             :     v8::Context::Scope context_scope(context);
     339           5 :     CHECK_EQ(isolate, v8::Isolate::GetCurrent());
     340             :     CompileRun("function getValue() { return 30; }");
     341          10 :     thread1.reset(new KangarooThread(isolate, context));
     342             :   }
     343           5 :   thread1->Start();
     344           5 :   thread1->Join();
     345           5 : }
     346             : 
     347             : 
     348        7520 : static void CalcFibAndCheck(v8::Local<v8::Context> context) {
     349             :   Local<Value> v = CompileRun("function fib(n) {"
     350             :                               "  if (n <= 2) return 1;"
     351             :                               "  return fib(n-1) + fib(n-2);"
     352             :                               "}"
     353             :                               "fib(10)");
     354        7520 :   CHECK(v->IsNumber());
     355       15040 :   CHECK_EQ(55, static_cast<int>(v->NumberValue(context).FromJust()));
     356        7520 : }
     357             : 
     358             : class JoinableThread {
     359             :  public:
     360        5210 :   explicit JoinableThread(const char* name)
     361             :     : name_(name),
     362             :       semaphore_(0),
     363        5210 :       thread_(this) {
     364        5210 :   }
     365             : 
     366       10420 :   virtual ~JoinableThread() {}
     367             : 
     368             :   void Start() {
     369        5210 :     thread_.Start();
     370             :   }
     371             : 
     372             :   void Join() {
     373        5210 :     semaphore_.Wait();
     374        5210 :     thread_.Join();
     375             :   }
     376             : 
     377             :   virtual void Run() = 0;
     378             : 
     379             :  private:
     380        5210 :   class ThreadWithSemaphore : public v8::base::Thread {
     381             :    public:
     382             :     explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
     383             :         : Thread(Options(joinable_thread->name_)),
     384       10420 :           joinable_thread_(joinable_thread) {}
     385             : 
     386        5200 :     virtual void Run() {
     387        5200 :       joinable_thread_->Run();
     388        5210 :       joinable_thread_->semaphore_.Signal();
     389        5210 :     }
     390             : 
     391             :    private:
     392             :     JoinableThread* joinable_thread_;
     393             :   };
     394             : 
     395             :   const char* name_;
     396             :   v8::base::Semaphore semaphore_;
     397             :   ThreadWithSemaphore thread_;
     398             : 
     399             :   friend class ThreadWithSemaphore;
     400             : 
     401             :   DISALLOW_COPY_AND_ASSIGN(JoinableThread);
     402             : };
     403             : 
     404             : 
     405        2500 : class IsolateLockingThreadWithLocalContext : public JoinableThread {
     406             :  public:
     407             :   explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
     408             :     : JoinableThread("IsolateLockingThread"),
     409        1000 :       isolate_(isolate) {
     410             :   }
     411             : 
     412         999 :   virtual void Run() {
     413         999 :     v8::Locker locker(isolate_);
     414        1000 :     v8::Isolate::Scope isolate_scope(isolate_);
     415        2000 :     v8::HandleScope handle_scope(isolate_);
     416        2000 :     LocalContext local_context(isolate_);
     417        1000 :     CHECK_EQ(isolate_, v8::Isolate::GetCurrent());
     418        2000 :     CalcFibAndCheck(local_context.local());
     419        1000 :   }
     420             :  private:
     421             :   v8::Isolate* isolate_;
     422             : };
     423             : 
     424          40 : static void StartJoinAndDeleteThreads(
     425             :     const std::vector<JoinableThread*>& threads) {
     426        3780 :   for (const auto& thread : threads) {
     427        3700 :     thread->Start();
     428             :   }
     429        3780 :   for (const auto& thread : threads) {
     430        3700 :     thread->Join();
     431             :   }
     432        3780 :   for (const auto& thread : threads) {
     433        3700 :     delete thread;
     434             :   }
     435          40 : }
     436             : 
     437             : 
     438             : // Run many threads all locking on the same isolate
     439       23723 : TEST(IsolateLockingStress) {
     440           5 :   i::FLAG_always_opt = false;
     441             : #if V8_TARGET_ARCH_MIPS
     442             :   const int kNThreads = 50;
     443             : #else
     444             :   const int kNThreads = 100;
     445             : #endif
     446             :   std::vector<JoinableThread*> threads;
     447           5 :   threads.reserve(kNThreads);
     448             :   v8::Isolate::CreateParams create_params;
     449           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     450           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     451         505 :   for (int i = 0; i < kNThreads; i++) {
     452        1500 :     threads.push_back(new IsolateLockingThreadWithLocalContext(isolate));
     453             :   }
     454           5 :   StartJoinAndDeleteThreads(threads);
     455           5 :   isolate->Dispose();
     456           5 : }
     457             : 
     458             : 
     459        1500 : class IsolateNestedLockingThread : public JoinableThread {
     460             :  public:
     461             :   explicit IsolateNestedLockingThread(v8::Isolate* isolate)
     462         500 :     : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
     463             :   }
     464         489 :   virtual void Run() {
     465         489 :     v8::Locker lock(isolate_);
     466         500 :     v8::Isolate::Scope isolate_scope(isolate_);
     467        1000 :     v8::HandleScope handle_scope(isolate_);
     468        1000 :     LocalContext local_context(isolate_);
     469             :     {
     470         500 :       v8::Locker another_lock(isolate_);
     471         500 :       CalcFibAndCheck(local_context.local());
     472             :     }
     473             :     {
     474         500 :       v8::Locker another_lock(isolate_);
     475         500 :       CalcFibAndCheck(local_context.local());
     476         500 :     }
     477         500 :   }
     478             :  private:
     479             :   v8::Isolate* isolate_;
     480             : };
     481             : 
     482             : 
     483             : // Run  many threads with nested locks
     484       23723 : TEST(IsolateNestedLocking) {
     485           5 :   i::FLAG_always_opt = false;
     486             : #if V8_TARGET_ARCH_MIPS
     487             :   const int kNThreads = 50;
     488             : #else
     489             :   const int kNThreads = 100;
     490             : #endif
     491             :   v8::Isolate::CreateParams create_params;
     492           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     493           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     494             :   std::vector<JoinableThread*> threads;
     495           5 :   threads.reserve(kNThreads);
     496         505 :   for (int i = 0; i < kNThreads; i++) {
     497        1500 :     threads.push_back(new IsolateNestedLockingThread(isolate));
     498             :   }
     499           5 :   StartJoinAndDeleteThreads(threads);
     500           5 :   isolate->Dispose();
     501           5 : }
     502             : 
     503             : 
     504        1500 : class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread {
     505             :  public:
     506             :   SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
     507             :                                           v8::Isolate* isolate2)
     508             :     : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
     509         500 :       isolate1_(isolate1), isolate2_(isolate2) {
     510             :   }
     511             : 
     512         500 :   virtual void Run() {
     513         500 :     v8::Locker lock(isolate1_);
     514         500 :     v8::Isolate::Scope isolate_scope(isolate1_);
     515        1000 :     v8::HandleScope handle_scope(isolate1_);
     516        1000 :     LocalContext local_context(isolate1_);
     517             : 
     518        1000 :     IsolateLockingThreadWithLocalContext threadB(isolate2_);
     519             :     threadB.Start();
     520         500 :     CalcFibAndCheck(local_context.local());
     521         500 :     threadB.Join();
     522         500 :   }
     523             :  private:
     524             :   v8::Isolate* isolate1_;
     525             :   v8::Isolate* isolate2_;
     526             : };
     527             : 
     528             : 
     529             : // Run parallel threads that lock and access different isolates in parallel
     530       23723 : TEST(SeparateIsolatesLocksNonexclusive) {
     531           5 :   i::FLAG_always_opt = false;
     532             : #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_S390
     533             :   const int kNThreads = 50;
     534             : #else
     535             :   const int kNThreads = 100;
     536             : #endif
     537             :   v8::Isolate::CreateParams create_params;
     538           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     539           5 :   v8::Isolate* isolate1 = v8::Isolate::New(create_params);
     540           5 :   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
     541             :   std::vector<JoinableThread*> threads;
     542           5 :   threads.reserve(kNThreads);
     543         505 :   for (int i = 0; i < kNThreads; i++) {
     544             :     threads.push_back(
     545        1500 :         new SeparateIsolatesLocksNonexclusiveThread(isolate1, isolate2));
     546             :   }
     547           5 :   StartJoinAndDeleteThreads(threads);
     548           5 :   isolate2->Dispose();
     549           5 :   isolate1->Dispose();
     550           5 : }
     551             : 
     552        2015 : class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread {
     553             :  public:
     554        1005 :   explicit LockIsolateAndCalculateFibSharedContextThread(
     555             :       v8::Isolate* isolate, v8::Local<v8::Context> context)
     556             :       : JoinableThread("LockIsolateAndCalculateFibThread"),
     557             :         isolate_(isolate),
     558        2010 :         context_(isolate, context) {}
     559             : 
     560        1000 :   virtual void Run() {
     561        1000 :     v8::Locker lock(isolate_);
     562        1005 :     v8::Isolate::Scope isolate_scope(isolate_);
     563        2010 :     v8::HandleScope handle_scope(isolate_);
     564             :     v8::Local<v8::Context> context =
     565        1005 :         v8::Local<v8::Context>::New(isolate_, context_);
     566             :     v8::Context::Scope context_scope(context);
     567        2010 :     CalcFibAndCheck(context);
     568        1005 :   }
     569             :  private:
     570             :   v8::Isolate* isolate_;
     571             :   v8::Persistent<v8::Context> context_;
     572             : };
     573             : 
     574        1500 : class LockerUnlockerThread : public JoinableThread {
     575             :  public:
     576             :   explicit LockerUnlockerThread(v8::Isolate* isolate)
     577             :     : JoinableThread("LockerUnlockerThread"),
     578         500 :       isolate_(isolate) {
     579             :   }
     580             : 
     581         500 :   virtual void Run() {
     582         500 :     isolate_->DiscardThreadSpecificMetadata();  // No-op
     583             :     {
     584         499 :       v8::Locker lock(isolate_);
     585         500 :       v8::Isolate::Scope isolate_scope(isolate_);
     586        1000 :       v8::HandleScope handle_scope(isolate_);
     587         500 :       v8::Local<v8::Context> context = v8::Context::New(isolate_);
     588             :       {
     589             :         v8::Context::Scope context_scope(context);
     590         500 :         CalcFibAndCheck(context);
     591             :       }
     592             :       {
     593         500 :         LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
     594         500 :         isolate_->Exit();
     595        1000 :         v8::Unlocker unlocker(isolate_);
     596             :         thread.Start();
     597         500 :         thread.Join();
     598             :       }
     599         500 :       isolate_->Enter();
     600             :       {
     601             :         v8::Context::Scope context_scope(context);
     602         500 :         CalcFibAndCheck(context);
     603         500 :       }
     604             :     }
     605         500 :     isolate_->DiscardThreadSpecificMetadata();
     606         500 :     isolate_->DiscardThreadSpecificMetadata();  // No-op
     607         500 :   }
     608             : 
     609             :  private:
     610             :   v8::Isolate* isolate_;
     611             : };
     612             : 
     613             : 
     614             : // Use unlocker inside of a Locker, multiple threads.
     615       23723 : TEST(LockerUnlocker) {
     616           5 :   i::FLAG_always_opt = false;
     617             : #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_S390
     618             :   const int kNThreads = 50;
     619             : #else
     620             :   const int kNThreads = 100;
     621             : #endif
     622             :   std::vector<JoinableThread*> threads;
     623           5 :   threads.reserve(kNThreads);
     624             :   v8::Isolate::CreateParams create_params;
     625           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     626           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     627         505 :   for (int i = 0; i < kNThreads; i++) {
     628        1500 :     threads.push_back(new LockerUnlockerThread(isolate));
     629             :   }
     630           5 :   StartJoinAndDeleteThreads(threads);
     631           5 :   isolate->Dispose();
     632           5 : }
     633             : 
     634        1500 : class LockTwiceAndUnlockThread : public JoinableThread {
     635             :  public:
     636             :   explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
     637             :     : JoinableThread("LockTwiceAndUnlockThread"),
     638         500 :       isolate_(isolate) {
     639             :   }
     640             : 
     641         500 :   virtual void Run() {
     642         500 :     v8::Locker lock(isolate_);
     643         500 :     v8::Isolate::Scope isolate_scope(isolate_);
     644        1000 :     v8::HandleScope handle_scope(isolate_);
     645         500 :     v8::Local<v8::Context> context = v8::Context::New(isolate_);
     646             :     {
     647             :       v8::Context::Scope context_scope(context);
     648         500 :       CalcFibAndCheck(context);
     649             :     }
     650             :     {
     651         500 :       v8::Locker second_lock(isolate_);
     652             :       {
     653         500 :         LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
     654         500 :         isolate_->Exit();
     655        1000 :         v8::Unlocker unlocker(isolate_);
     656             :         thread.Start();
     657         500 :         thread.Join();
     658         500 :       }
     659             :     }
     660         500 :     isolate_->Enter();
     661             :     {
     662             :       v8::Context::Scope context_scope(context);
     663         500 :       CalcFibAndCheck(context);
     664         500 :     }
     665         500 :   }
     666             : 
     667             :  private:
     668             :   v8::Isolate* isolate_;
     669             : };
     670             : 
     671             : 
     672             : // Use Unlocker inside two Lockers.
     673       23723 : TEST(LockTwiceAndUnlock) {
     674           5 :   i::FLAG_always_opt = false;
     675             : #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_S390
     676             :   const int kNThreads = 50;
     677             : #else
     678             :   const int kNThreads = 100;
     679             : #endif
     680             :   std::vector<JoinableThread*> threads;
     681           5 :   threads.reserve(kNThreads);
     682             :   v8::Isolate::CreateParams create_params;
     683           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     684           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     685         505 :   for (int i = 0; i < kNThreads; i++) {
     686        1500 :     threads.push_back(new LockTwiceAndUnlockThread(isolate));
     687             :   }
     688           5 :   StartJoinAndDeleteThreads(threads);
     689           5 :   isolate->Dispose();
     690           5 : }
     691             : 
     692          10 : class LockAndUnlockDifferentIsolatesThread : public JoinableThread {
     693             :  public:
     694             :   LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
     695             :                                        v8::Isolate* isolate2)
     696             :     : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
     697             :       isolate1_(isolate1),
     698           5 :       isolate2_(isolate2) {
     699             :   }
     700             : 
     701           5 :   virtual void Run() {
     702             :     std::unique_ptr<LockIsolateAndCalculateFibSharedContextThread> thread;
     703          10 :     v8::Locker lock1(isolate1_);
     704           5 :     CHECK(v8::Locker::IsLocked(isolate1_));
     705           5 :     CHECK(!v8::Locker::IsLocked(isolate2_));
     706             :     {
     707           5 :       v8::Isolate::Scope isolate_scope(isolate1_);
     708          10 :       v8::HandleScope handle_scope(isolate1_);
     709           5 :       v8::Local<v8::Context> context1 = v8::Context::New(isolate1_);
     710             :       {
     711             :         v8::Context::Scope context_scope(context1);
     712           5 :         CalcFibAndCheck(context1);
     713             :       }
     714             :       thread.reset(new LockIsolateAndCalculateFibSharedContextThread(isolate1_,
     715           5 :                                                                      context1));
     716             :     }
     717          10 :     v8::Locker lock2(isolate2_);
     718           5 :     CHECK(v8::Locker::IsLocked(isolate1_));
     719           5 :     CHECK(v8::Locker::IsLocked(isolate2_));
     720             :     {
     721           5 :       v8::Isolate::Scope isolate_scope(isolate2_);
     722          10 :       v8::HandleScope handle_scope(isolate2_);
     723           5 :       v8::Local<v8::Context> context2 = v8::Context::New(isolate2_);
     724             :       {
     725             :         v8::Context::Scope context_scope(context2);
     726           5 :         CalcFibAndCheck(context2);
     727             :       }
     728          10 :       v8::Unlocker unlock1(isolate1_);
     729           5 :       CHECK(!v8::Locker::IsLocked(isolate1_));
     730           5 :       CHECK(v8::Locker::IsLocked(isolate2_));
     731             :       v8::Context::Scope context_scope(context2);
     732             :       thread->Start();
     733           5 :       CalcFibAndCheck(context2);
     734             :       thread->Join();
     735             :     }
     736           5 :   }
     737             : 
     738             :  private:
     739             :   v8::Isolate* isolate1_;
     740             :   v8::Isolate* isolate2_;
     741             : };
     742             : 
     743             : 
     744             : // Lock two isolates and unlock one of them.
     745       23723 : TEST(LockAndUnlockDifferentIsolates) {
     746             :   v8::Isolate::CreateParams create_params;
     747           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     748           5 :   v8::Isolate* isolate1 = v8::Isolate::New(create_params);
     749           5 :   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
     750             :   LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2);
     751             :   thread.Start();
     752             :   thread.Join();
     753           5 :   isolate2->Dispose();
     754           5 :   isolate1->Dispose();
     755           5 : }
     756             : 
     757        1500 : class LockUnlockLockThread : public JoinableThread {
     758             :  public:
     759         500 :   LockUnlockLockThread(v8::Isolate* isolate, v8::Local<v8::Context> context)
     760             :       : JoinableThread("LockUnlockLockThread"),
     761             :         isolate_(isolate),
     762        1000 :         context_(isolate, context) {}
     763             : 
     764         500 :   virtual void Run() {
     765         500 :     v8::Locker lock1(isolate_);
     766         500 :     CHECK(v8::Locker::IsLocked(isolate_));
     767         500 :     CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
     768             :     {
     769         500 :       v8::Isolate::Scope isolate_scope(isolate_);
     770        1000 :       v8::HandleScope handle_scope(isolate_);
     771             :       v8::Local<v8::Context> context =
     772         500 :           v8::Local<v8::Context>::New(isolate_, context_);
     773             :       v8::Context::Scope context_scope(context);
     774         500 :       CalcFibAndCheck(context);
     775             :     }
     776             :     {
     777         500 :       v8::Unlocker unlock1(isolate_);
     778         500 :       CHECK(!v8::Locker::IsLocked(isolate_));
     779         500 :       CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
     780             :       {
     781         500 :         v8::Locker lock2(isolate_);
     782         500 :         v8::Isolate::Scope isolate_scope(isolate_);
     783        1000 :         v8::HandleScope handle_scope(isolate_);
     784         500 :         CHECK(v8::Locker::IsLocked(isolate_));
     785         500 :         CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
     786             :         v8::Local<v8::Context> context =
     787         500 :             v8::Local<v8::Context>::New(isolate_, context_);
     788             :         v8::Context::Scope context_scope(context);
     789        1000 :         CalcFibAndCheck(context);
     790         500 :       }
     791         500 :     }
     792         500 :   }
     793             : 
     794             :  private:
     795             :   v8::Isolate* isolate_;
     796             :   v8::Persistent<v8::Context> context_;
     797             : };
     798             : 
     799             : 
     800             : // Locker inside an Unlocker inside a Locker.
     801       23723 : TEST(LockUnlockLockMultithreaded) {
     802             : #if V8_TARGET_ARCH_MIPS
     803             :   const int kNThreads = 50;
     804             : #else
     805             :   const int kNThreads = 100;
     806             : #endif
     807             :   v8::Isolate::CreateParams create_params;
     808           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     809           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     810             :   std::vector<JoinableThread*> threads;
     811           5 :   threads.reserve(kNThreads);
     812             :   {
     813             :     v8::Locker locker_(isolate);
     814             :     v8::Isolate::Scope isolate_scope(isolate);
     815          10 :     v8::HandleScope handle_scope(isolate);
     816           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
     817         505 :     for (int i = 0; i < kNThreads; i++) {
     818        1000 :       threads.push_back(new LockUnlockLockThread(isolate, context));
     819           5 :     }
     820             :   }
     821           5 :   StartJoinAndDeleteThreads(threads);
     822           5 :   isolate->Dispose();
     823           5 : }
     824             : 
     825        1500 : class LockUnlockLockDefaultIsolateThread : public JoinableThread {
     826             :  public:
     827         500 :   explicit LockUnlockLockDefaultIsolateThread(v8::Local<v8::Context> context)
     828             :       : JoinableThread("LockUnlockLockDefaultIsolateThread"),
     829        1000 :         context_(CcTest::isolate(), context) {}
     830             : 
     831         499 :   virtual void Run() {
     832         499 :     v8::Locker lock1(CcTest::isolate());
     833             :     {
     834         500 :       v8::Isolate::Scope isolate_scope(CcTest::isolate());
     835        1000 :       v8::HandleScope handle_scope(CcTest::isolate());
     836             :       v8::Local<v8::Context> context =
     837         500 :           v8::Local<v8::Context>::New(CcTest::isolate(), context_);
     838             :       v8::Context::Scope context_scope(context);
     839         500 :       CalcFibAndCheck(context);
     840             :     }
     841             :     {
     842         500 :       v8::Unlocker unlock1(CcTest::isolate());
     843             :       {
     844         500 :         v8::Locker lock2(CcTest::isolate());
     845         500 :         v8::Isolate::Scope isolate_scope(CcTest::isolate());
     846        1000 :         v8::HandleScope handle_scope(CcTest::isolate());
     847             :         v8::Local<v8::Context> context =
     848         500 :             v8::Local<v8::Context>::New(CcTest::isolate(), context_);
     849             :         v8::Context::Scope context_scope(context);
     850        1000 :         CalcFibAndCheck(context);
     851         500 :       }
     852         500 :     }
     853         500 :   }
     854             : 
     855             :  private:
     856             :   v8::Persistent<v8::Context> context_;
     857             : };
     858             : 
     859             : 
     860             : // Locker inside an Unlocker inside a Locker for default isolate.
     861       23723 : TEST(LockUnlockLockDefaultIsolateMultithreaded) {
     862             : #if V8_TARGET_ARCH_MIPS
     863             :   const int kNThreads = 50;
     864             : #else
     865             :   const int kNThreads = 100;
     866             : #endif
     867             :   Local<v8::Context> context;
     868             :   std::vector<JoinableThread*> threads;
     869           5 :   threads.reserve(kNThreads);
     870             :   {
     871           5 :     v8::Locker locker_(CcTest::isolate());
     872           5 :     v8::Isolate::Scope isolate_scope(CcTest::isolate());
     873          10 :     v8::HandleScope handle_scope(CcTest::isolate());
     874           5 :     context = v8::Context::New(CcTest::isolate());
     875         505 :     for (int i = 0; i < kNThreads; i++) {
     876        1000 :       threads.push_back(new LockUnlockLockDefaultIsolateThread(context));
     877           5 :     }
     878             :   }
     879           5 :   StartJoinAndDeleteThreads(threads);
     880           5 : }
     881             : 
     882             : 
     883       23723 : TEST(Regress1433) {
     884          55 :   for (int i = 0; i < 10; i++) {
     885             :     v8::Isolate::CreateParams create_params;
     886          50 :     create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     887          50 :     v8::Isolate* isolate = v8::Isolate::New(create_params);
     888             :     {
     889             :       v8::Locker lock(isolate);
     890             :       v8::Isolate::Scope isolate_scope(isolate);
     891         100 :       v8::HandleScope handle_scope(isolate);
     892          50 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
     893             :       v8::Context::Scope context_scope(context);
     894          50 :       v8::Local<v8::String> source = v8_str("1+1");
     895             :       v8::Local<v8::Script> script =
     896          50 :           v8::Script::Compile(context, source).ToLocalChecked();
     897         100 :       v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
     898         100 :       v8::String::Utf8Value utf8(isolate, result);
     899             :     }
     900          50 :     isolate->Dispose();
     901             :   }
     902           5 : }
     903             : 
     904             : 
     905             : static const char* kSimpleExtensionSource =
     906             :   "(function Foo() {"
     907             :   "  return 4;"
     908             :   "})() ";
     909             : 
     910         600 : class IsolateGenesisThread : public JoinableThread {
     911             :  public:
     912             :   IsolateGenesisThread(int count, const char* extension_names[])
     913             :     : JoinableThread("IsolateGenesisThread"),
     914             :       count_(count),
     915         200 :       extension_names_(extension_names)
     916             :   {}
     917             : 
     918         200 :   virtual void Run() {
     919             :     v8::Isolate::CreateParams create_params;
     920         200 :     create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     921         200 :     v8::Isolate* isolate = v8::Isolate::New(create_params);
     922             :     {
     923             :       v8::Isolate::Scope isolate_scope(isolate);
     924         200 :       v8::ExtensionConfiguration extensions(count_, extension_names_);
     925         400 :       v8::HandleScope handle_scope(isolate);
     926         200 :       v8::Context::New(isolate, &extensions);
     927             :     }
     928         200 :     isolate->Dispose();
     929         200 :   }
     930             : 
     931             :  private:
     932             :   int count_;
     933             :   const char** extension_names_;
     934             : };
     935             : 
     936             : 
     937             : // Test installing extensions in separate isolates concurrently.
     938             : // http://code.google.com/p/v8/issues/detail?id=1821
     939       23723 : TEST(ExtensionsRegistration) {
     940             : #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
     941             :   const int kNThreads = 10;
     942             : #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
     943             :   const int kNThreads = 4;
     944             : #elif V8_TARGET_ARCH_S390 && V8_TARGET_ARCH_32_BIT
     945             :   const int kNThreads = 10;
     946             : #else
     947             :   const int kNThreads = 40;
     948             : #endif
     949             :   v8::RegisterExtension(new v8::Extension("test0",
     950           5 :                                           kSimpleExtensionSource));
     951             :   v8::RegisterExtension(new v8::Extension("test1",
     952           5 :                                           kSimpleExtensionSource));
     953             :   v8::RegisterExtension(new v8::Extension("test2",
     954           5 :                                           kSimpleExtensionSource));
     955             :   v8::RegisterExtension(new v8::Extension("test3",
     956           5 :                                           kSimpleExtensionSource));
     957             :   v8::RegisterExtension(new v8::Extension("test4",
     958           5 :                                           kSimpleExtensionSource));
     959             :   v8::RegisterExtension(new v8::Extension("test5",
     960           5 :                                           kSimpleExtensionSource));
     961             :   v8::RegisterExtension(new v8::Extension("test6",
     962           5 :                                           kSimpleExtensionSource));
     963             :   v8::RegisterExtension(new v8::Extension("test7",
     964           5 :                                           kSimpleExtensionSource));
     965             :   const char* extension_names[] = { "test0", "test1",
     966             :                                     "test2", "test3", "test4",
     967           5 :                                     "test5", "test6", "test7" };
     968             :   std::vector<JoinableThread*> threads;
     969           5 :   threads.reserve(kNThreads);
     970         205 :   for (int i = 0; i < kNThreads; i++) {
     971         600 :     threads.push_back(new IsolateGenesisThread(8, extension_names));
     972             :   }
     973           5 :   StartJoinAndDeleteThreads(threads);
     974           5 : }
     975             : 
     976             : }  // namespace test_lockers
     977             : }  // namespace internal
     978       71154 : }  // namespace v8

Generated by: LCOV version 1.10