Home | History | Annotate | Download | only in cctest
      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 "src/v8.h"
     31 
     32 #include "src/api.h"
     33 #include "src/base/platform/platform.h"
     34 #include "src/compilation-cache.h"
     35 #include "src/execution.h"
     36 #include "src/isolate.h"
     37 #include "src/parser.h"
     38 #include "src/smart-pointers.h"
     39 #include "src/snapshot.h"
     40 #include "src/unicode-inl.h"
     41 #include "src/utils.h"
     42 #include "test/cctest/cctest.h"
     43 
     44 using ::v8::Context;
     45 using ::v8::Extension;
     46 using ::v8::Function;
     47 using ::v8::HandleScope;
     48 using ::v8::Local;
     49 using ::v8::Object;
     50 using ::v8::ObjectTemplate;
     51 using ::v8::Persistent;
     52 using ::v8::Script;
     53 using ::v8::String;
     54 using ::v8::Value;
     55 using ::v8::V8;
     56 
     57 
     58 // Migrating an isolate
     59 class KangarooThread : public v8::base::Thread {
     60  public:
     61   KangarooThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
     62       : Thread(Options("KangarooThread")),
     63         isolate_(isolate),
     64         context_(isolate, context) {}
     65 
     66   void Run() {
     67     {
     68       v8::Locker locker(isolate_);
     69       v8::Isolate::Scope isolate_scope(isolate_);
     70       CHECK_EQ(isolate_, v8::internal::Isolate::Current());
     71       v8::HandleScope scope(isolate_);
     72       v8::Local<v8::Context> context =
     73           v8::Local<v8::Context>::New(isolate_, context_);
     74       v8::Context::Scope context_scope(context);
     75       Local<Value> v = CompileRun("getValue()");
     76       CHECK(v->IsNumber());
     77       CHECK_EQ(30, static_cast<int>(v->NumberValue()));
     78     }
     79     {
     80       v8::Locker locker(isolate_);
     81       v8::Isolate::Scope isolate_scope(isolate_);
     82       v8::HandleScope scope(isolate_);
     83       v8::Local<v8::Context> context =
     84           v8::Local<v8::Context>::New(isolate_, context_);
     85       v8::Context::Scope context_scope(context);
     86       Local<Value> v = CompileRun("getValue()");
     87       CHECK(v->IsNumber());
     88       CHECK_EQ(30, static_cast<int>(v->NumberValue()));
     89     }
     90     isolate_->Dispose();
     91   }
     92 
     93  private:
     94   v8::Isolate* isolate_;
     95   Persistent<v8::Context> context_;
     96 };
     97 
     98 
     99 // Migrates an isolate from one thread to another
    100 TEST(KangarooIsolates) {
    101   v8::Isolate* isolate = v8::Isolate::New();
    102   i::SmartPointer<KangarooThread> thread1;
    103   {
    104     v8::Locker locker(isolate);
    105     v8::Isolate::Scope isolate_scope(isolate);
    106     v8::HandleScope handle_scope(isolate);
    107     v8::Local<v8::Context> context = v8::Context::New(isolate);
    108     v8::Context::Scope context_scope(context);
    109     CHECK_EQ(isolate, v8::internal::Isolate::Current());
    110     CompileRun("function getValue() { return 30; }");
    111     thread1.Reset(new KangarooThread(isolate, context));
    112   }
    113   thread1->Start();
    114   thread1->Join();
    115 }
    116 
    117 
    118 static void CalcFibAndCheck() {
    119   Local<Value> v = CompileRun("function fib(n) {"
    120                               "  if (n <= 2) return 1;"
    121                               "  return fib(n-1) + fib(n-2);"
    122                               "}"
    123                               "fib(10)");
    124   CHECK(v->IsNumber());
    125   CHECK_EQ(55, static_cast<int>(v->NumberValue()));
    126 }
    127 
    128 class JoinableThread {
    129  public:
    130   explicit JoinableThread(const char* name)
    131     : name_(name),
    132       semaphore_(0),
    133       thread_(this) {
    134   }
    135 
    136   virtual ~JoinableThread() {}
    137 
    138   void Start() {
    139     thread_.Start();
    140   }
    141 
    142   void Join() {
    143     semaphore_.Wait();
    144   }
    145 
    146   virtual void Run() = 0;
    147 
    148  private:
    149   class ThreadWithSemaphore : public v8::base::Thread {
    150    public:
    151     explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
    152         : Thread(Options(joinable_thread->name_)),
    153           joinable_thread_(joinable_thread) {}
    154 
    155     virtual void Run() {
    156       joinable_thread_->Run();
    157       joinable_thread_->semaphore_.Signal();
    158     }
    159 
    160    private:
    161     JoinableThread* joinable_thread_;
    162   };
    163 
    164   const char* name_;
    165   v8::base::Semaphore semaphore_;
    166   ThreadWithSemaphore thread_;
    167 
    168   friend class ThreadWithSemaphore;
    169 
    170   DISALLOW_COPY_AND_ASSIGN(JoinableThread);
    171 };
    172 
    173 
    174 class IsolateLockingThreadWithLocalContext : public JoinableThread {
    175  public:
    176   explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
    177     : JoinableThread("IsolateLockingThread"),
    178       isolate_(isolate) {
    179   }
    180 
    181   virtual void Run() {
    182     v8::Locker locker(isolate_);
    183     v8::Isolate::Scope isolate_scope(isolate_);
    184     v8::HandleScope handle_scope(isolate_);
    185     LocalContext local_context(isolate_);
    186     CHECK_EQ(isolate_, v8::internal::Isolate::Current());
    187     CalcFibAndCheck();
    188   }
    189  private:
    190   v8::Isolate* isolate_;
    191 };
    192 
    193 
    194 static void StartJoinAndDeleteThreads(const i::List<JoinableThread*>& threads) {
    195   for (int i = 0; i < threads.length(); i++) {
    196     threads[i]->Start();
    197   }
    198   for (int i = 0; i < threads.length(); i++) {
    199     threads[i]->Join();
    200   }
    201   for (int i = 0; i < threads.length(); i++) {
    202     delete threads[i];
    203   }
    204 }
    205 
    206 
    207 // Run many threads all locking on the same isolate
    208 TEST(IsolateLockingStress) {
    209 #if V8_TARGET_ARCH_MIPS
    210   const int kNThreads = 50;
    211 #else
    212   const int kNThreads = 100;
    213 #endif
    214   i::List<JoinableThread*> threads(kNThreads);
    215   v8::Isolate* isolate = v8::Isolate::New();
    216   for (int i = 0; i < kNThreads; i++) {
    217     threads.Add(new IsolateLockingThreadWithLocalContext(isolate));
    218   }
    219   StartJoinAndDeleteThreads(threads);
    220   isolate->Dispose();
    221 }
    222 
    223 class IsolateNonlockingThread : public JoinableThread {
    224  public:
    225   IsolateNonlockingThread() : JoinableThread("IsolateNonlockingThread") {}
    226 
    227   virtual void Run() {
    228     v8::Isolate* isolate = v8::Isolate::New();
    229     {
    230       v8::Isolate::Scope isolate_scope(isolate);
    231       v8::HandleScope handle_scope(isolate);
    232       v8::Handle<v8::Context> context = v8::Context::New(isolate);
    233       v8::Context::Scope context_scope(context);
    234       CHECK_EQ(isolate, v8::internal::Isolate::Current());
    235       CalcFibAndCheck();
    236     }
    237     isolate->Dispose();
    238   }
    239  private:
    240 };
    241 
    242 
    243 // Run many threads each accessing its own isolate without locking
    244 TEST(MultithreadedParallelIsolates) {
    245 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
    246   const int kNThreads = 10;
    247 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
    248   const int kNThreads = 4;
    249 #else
    250   const int kNThreads = 50;
    251 #endif
    252   i::List<JoinableThread*> threads(kNThreads);
    253   for (int i = 0; i < kNThreads; i++) {
    254     threads.Add(new IsolateNonlockingThread());
    255   }
    256   StartJoinAndDeleteThreads(threads);
    257 }
    258 
    259 
    260 class IsolateNestedLockingThread : public JoinableThread {
    261  public:
    262   explicit IsolateNestedLockingThread(v8::Isolate* isolate)
    263     : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
    264   }
    265   virtual void Run() {
    266     v8::Locker lock(isolate_);
    267     v8::Isolate::Scope isolate_scope(isolate_);
    268     v8::HandleScope handle_scope(isolate_);
    269     LocalContext local_context(isolate_);
    270     {
    271       v8::Locker another_lock(isolate_);
    272       CalcFibAndCheck();
    273     }
    274     {
    275       v8::Locker another_lock(isolate_);
    276       CalcFibAndCheck();
    277     }
    278   }
    279  private:
    280   v8::Isolate* isolate_;
    281 };
    282 
    283 
    284 // Run  many threads with nested locks
    285 TEST(IsolateNestedLocking) {
    286 #if V8_TARGET_ARCH_MIPS
    287   const int kNThreads = 50;
    288 #else
    289   const int kNThreads = 100;
    290 #endif
    291   v8::Isolate* isolate = v8::Isolate::New();
    292   i::List<JoinableThread*> threads(kNThreads);
    293   for (int i = 0; i < kNThreads; i++) {
    294     threads.Add(new IsolateNestedLockingThread(isolate));
    295   }
    296   StartJoinAndDeleteThreads(threads);
    297   isolate->Dispose();
    298 }
    299 
    300 
    301 class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread {
    302  public:
    303   SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
    304                                           v8::Isolate* isolate2)
    305     : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
    306       isolate1_(isolate1), isolate2_(isolate2) {
    307   }
    308 
    309   virtual void Run() {
    310     v8::Locker lock(isolate1_);
    311     v8::Isolate::Scope isolate_scope(isolate1_);
    312     v8::HandleScope handle_scope(isolate1_);
    313     LocalContext local_context(isolate1_);
    314 
    315     IsolateLockingThreadWithLocalContext threadB(isolate2_);
    316     threadB.Start();
    317     CalcFibAndCheck();
    318     threadB.Join();
    319   }
    320  private:
    321   v8::Isolate* isolate1_;
    322   v8::Isolate* isolate2_;
    323 };
    324 
    325 
    326 // Run parallel threads that lock and access different isolates in parallel
    327 TEST(SeparateIsolatesLocksNonexclusive) {
    328 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
    329   const int kNThreads = 50;
    330 #else
    331   const int kNThreads = 100;
    332 #endif
    333   v8::Isolate* isolate1 = v8::Isolate::New();
    334   v8::Isolate* isolate2 = v8::Isolate::New();
    335   i::List<JoinableThread*> threads(kNThreads);
    336   for (int i = 0; i < kNThreads; i++) {
    337     threads.Add(new SeparateIsolatesLocksNonexclusiveThread(isolate1,
    338                                                              isolate2));
    339   }
    340   StartJoinAndDeleteThreads(threads);
    341   isolate2->Dispose();
    342   isolate1->Dispose();
    343 }
    344 
    345 class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread {
    346  public:
    347   explicit LockIsolateAndCalculateFibSharedContextThread(
    348       v8::Isolate* isolate, v8::Handle<v8::Context> context)
    349     : JoinableThread("LockIsolateAndCalculateFibThread"),
    350       isolate_(isolate),
    351       context_(isolate, context) {
    352   }
    353 
    354   virtual void Run() {
    355     v8::Locker lock(isolate_);
    356     v8::Isolate::Scope isolate_scope(isolate_);
    357     HandleScope handle_scope(isolate_);
    358     v8::Local<v8::Context> context =
    359         v8::Local<v8::Context>::New(isolate_, context_);
    360     v8::Context::Scope context_scope(context);
    361     CalcFibAndCheck();
    362   }
    363  private:
    364   v8::Isolate* isolate_;
    365   Persistent<v8::Context> context_;
    366 };
    367 
    368 class LockerUnlockerThread : public JoinableThread {
    369  public:
    370   explicit LockerUnlockerThread(v8::Isolate* isolate)
    371     : JoinableThread("LockerUnlockerThread"),
    372       isolate_(isolate) {
    373   }
    374 
    375   virtual void Run() {
    376     v8::Locker lock(isolate_);
    377     v8::Isolate::Scope isolate_scope(isolate_);
    378     v8::HandleScope handle_scope(isolate_);
    379     v8::Local<v8::Context> context = v8::Context::New(isolate_);
    380     {
    381       v8::Context::Scope context_scope(context);
    382       CalcFibAndCheck();
    383     }
    384     {
    385       LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
    386       isolate_->Exit();
    387       v8::Unlocker unlocker(isolate_);
    388       thread.Start();
    389       thread.Join();
    390     }
    391     isolate_->Enter();
    392     {
    393       v8::Context::Scope context_scope(context);
    394       CalcFibAndCheck();
    395     }
    396   }
    397 
    398  private:
    399   v8::Isolate* isolate_;
    400 };
    401 
    402 
    403 // Use unlocker inside of a Locker, multiple threads.
    404 TEST(LockerUnlocker) {
    405 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
    406   const int kNThreads = 50;
    407 #else
    408   const int kNThreads = 100;
    409 #endif
    410   i::List<JoinableThread*> threads(kNThreads);
    411   v8::Isolate* isolate = v8::Isolate::New();
    412   for (int i = 0; i < kNThreads; i++) {
    413     threads.Add(new LockerUnlockerThread(isolate));
    414   }
    415   StartJoinAndDeleteThreads(threads);
    416   isolate->Dispose();
    417 }
    418 
    419 class LockTwiceAndUnlockThread : public JoinableThread {
    420  public:
    421   explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
    422     : JoinableThread("LockTwiceAndUnlockThread"),
    423       isolate_(isolate) {
    424   }
    425 
    426   virtual void Run() {
    427     v8::Locker lock(isolate_);
    428     v8::Isolate::Scope isolate_scope(isolate_);
    429     v8::HandleScope handle_scope(isolate_);
    430     v8::Local<v8::Context> context = v8::Context::New(isolate_);
    431     {
    432       v8::Context::Scope context_scope(context);
    433       CalcFibAndCheck();
    434     }
    435     {
    436       v8::Locker second_lock(isolate_);
    437       {
    438         LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
    439         isolate_->Exit();
    440         v8::Unlocker unlocker(isolate_);
    441         thread.Start();
    442         thread.Join();
    443       }
    444     }
    445     isolate_->Enter();
    446     {
    447       v8::Context::Scope context_scope(context);
    448       CalcFibAndCheck();
    449     }
    450   }
    451 
    452  private:
    453   v8::Isolate* isolate_;
    454 };
    455 
    456 
    457 // Use Unlocker inside two Lockers.
    458 TEST(LockTwiceAndUnlock) {
    459 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
    460   const int kNThreads = 50;
    461 #else
    462   const int kNThreads = 100;
    463 #endif
    464   i::List<JoinableThread*> threads(kNThreads);
    465   v8::Isolate* isolate = v8::Isolate::New();
    466   for (int i = 0; i < kNThreads; i++) {
    467     threads.Add(new LockTwiceAndUnlockThread(isolate));
    468   }
    469   StartJoinAndDeleteThreads(threads);
    470   isolate->Dispose();
    471 }
    472 
    473 class LockAndUnlockDifferentIsolatesThread : public JoinableThread {
    474  public:
    475   LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
    476                                        v8::Isolate* isolate2)
    477     : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
    478       isolate1_(isolate1),
    479       isolate2_(isolate2) {
    480   }
    481 
    482   virtual void Run() {
    483     i::SmartPointer<LockIsolateAndCalculateFibSharedContextThread> thread;
    484     v8::Locker lock1(isolate1_);
    485     CHECK(v8::Locker::IsLocked(isolate1_));
    486     CHECK(!v8::Locker::IsLocked(isolate2_));
    487     {
    488       v8::Isolate::Scope isolate_scope(isolate1_);
    489       v8::HandleScope handle_scope(isolate1_);
    490       v8::Handle<v8::Context> context1 = v8::Context::New(isolate1_);
    491       {
    492         v8::Context::Scope context_scope(context1);
    493         CalcFibAndCheck();
    494       }
    495       thread.Reset(new LockIsolateAndCalculateFibSharedContextThread(
    496           isolate1_, context1));
    497     }
    498     v8::Locker lock2(isolate2_);
    499     CHECK(v8::Locker::IsLocked(isolate1_));
    500     CHECK(v8::Locker::IsLocked(isolate2_));
    501     {
    502       v8::Isolate::Scope isolate_scope(isolate2_);
    503       v8::HandleScope handle_scope(isolate2_);
    504       v8::Handle<v8::Context> context2 = v8::Context::New(isolate2_);
    505       {
    506         v8::Context::Scope context_scope(context2);
    507         CalcFibAndCheck();
    508       }
    509       v8::Unlocker unlock1(isolate1_);
    510       CHECK(!v8::Locker::IsLocked(isolate1_));
    511       CHECK(v8::Locker::IsLocked(isolate2_));
    512       v8::Context::Scope context_scope(context2);
    513       thread->Start();
    514       CalcFibAndCheck();
    515       thread->Join();
    516     }
    517   }
    518 
    519  private:
    520   v8::Isolate* isolate1_;
    521   v8::Isolate* isolate2_;
    522 };
    523 
    524 
    525 // Lock two isolates and unlock one of them.
    526 TEST(LockAndUnlockDifferentIsolates) {
    527   v8::Isolate* isolate1 = v8::Isolate::New();
    528   v8::Isolate* isolate2 = v8::Isolate::New();
    529   LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2);
    530   thread.Start();
    531   thread.Join();
    532   isolate2->Dispose();
    533   isolate1->Dispose();
    534 }
    535 
    536 class LockUnlockLockThread : public JoinableThread {
    537  public:
    538   LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
    539     : JoinableThread("LockUnlockLockThread"),
    540       isolate_(isolate),
    541       context_(isolate, context) {
    542   }
    543 
    544   virtual void Run() {
    545     v8::Locker lock1(isolate_);
    546     CHECK(v8::Locker::IsLocked(isolate_));
    547     CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
    548     {
    549       v8::Isolate::Scope isolate_scope(isolate_);
    550       v8::HandleScope handle_scope(isolate_);
    551       v8::Local<v8::Context> context =
    552           v8::Local<v8::Context>::New(isolate_, context_);
    553       v8::Context::Scope context_scope(context);
    554       CalcFibAndCheck();
    555     }
    556     {
    557       v8::Unlocker unlock1(isolate_);
    558       CHECK(!v8::Locker::IsLocked(isolate_));
    559       CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
    560       {
    561         v8::Locker lock2(isolate_);
    562         v8::Isolate::Scope isolate_scope(isolate_);
    563         v8::HandleScope handle_scope(isolate_);
    564         CHECK(v8::Locker::IsLocked(isolate_));
    565         CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
    566         v8::Local<v8::Context> context =
    567             v8::Local<v8::Context>::New(isolate_, context_);
    568         v8::Context::Scope context_scope(context);
    569         CalcFibAndCheck();
    570       }
    571     }
    572   }
    573 
    574  private:
    575   v8::Isolate* isolate_;
    576   v8::Persistent<v8::Context> context_;
    577 };
    578 
    579 
    580 // Locker inside an Unlocker inside a Locker.
    581 TEST(LockUnlockLockMultithreaded) {
    582 #if V8_TARGET_ARCH_MIPS
    583   const int kNThreads = 50;
    584 #else
    585   const int kNThreads = 100;
    586 #endif
    587   v8::Isolate* isolate = v8::Isolate::New();
    588   i::List<JoinableThread*> threads(kNThreads);
    589   {
    590     v8::Locker locker_(isolate);
    591     v8::Isolate::Scope isolate_scope(isolate);
    592     v8::HandleScope handle_scope(isolate);
    593     v8::Handle<v8::Context> context = v8::Context::New(isolate);
    594     for (int i = 0; i < kNThreads; i++) {
    595       threads.Add(new LockUnlockLockThread(
    596           isolate, context));
    597     }
    598   }
    599   StartJoinAndDeleteThreads(threads);
    600   isolate->Dispose();
    601 }
    602 
    603 class LockUnlockLockDefaultIsolateThread : public JoinableThread {
    604  public:
    605   explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context)
    606       : JoinableThread("LockUnlockLockDefaultIsolateThread"),
    607         context_(CcTest::isolate(), context) {}
    608 
    609   virtual void Run() {
    610     v8::Locker lock1(CcTest::isolate());
    611     {
    612       v8::Isolate::Scope isolate_scope(CcTest::isolate());
    613       v8::HandleScope handle_scope(CcTest::isolate());
    614       v8::Local<v8::Context> context =
    615           v8::Local<v8::Context>::New(CcTest::isolate(), context_);
    616       v8::Context::Scope context_scope(context);
    617       CalcFibAndCheck();
    618     }
    619     {
    620       v8::Unlocker unlock1(CcTest::isolate());
    621       {
    622         v8::Locker lock2(CcTest::isolate());
    623         v8::Isolate::Scope isolate_scope(CcTest::isolate());
    624         v8::HandleScope handle_scope(CcTest::isolate());
    625         v8::Local<v8::Context> context =
    626             v8::Local<v8::Context>::New(CcTest::isolate(), context_);
    627         v8::Context::Scope context_scope(context);
    628         CalcFibAndCheck();
    629       }
    630     }
    631   }
    632 
    633  private:
    634   v8::Persistent<v8::Context> context_;
    635 };
    636 
    637 
    638 // Locker inside an Unlocker inside a Locker for default isolate.
    639 TEST(LockUnlockLockDefaultIsolateMultithreaded) {
    640 #if V8_TARGET_ARCH_MIPS
    641   const int kNThreads = 50;
    642 #else
    643   const int kNThreads = 100;
    644 #endif
    645   Local<v8::Context> context;
    646   i::List<JoinableThread*> threads(kNThreads);
    647   {
    648     v8::Locker locker_(CcTest::isolate());
    649     v8::Isolate::Scope isolate_scope(CcTest::isolate());
    650     v8::HandleScope handle_scope(CcTest::isolate());
    651     context = v8::Context::New(CcTest::isolate());
    652     for (int i = 0; i < kNThreads; i++) {
    653       threads.Add(new LockUnlockLockDefaultIsolateThread(context));
    654     }
    655   }
    656   StartJoinAndDeleteThreads(threads);
    657 }
    658 
    659 
    660 TEST(Regress1433) {
    661   for (int i = 0; i < 10; i++) {
    662     v8::Isolate* isolate = v8::Isolate::New();
    663     {
    664       v8::Locker lock(isolate);
    665       v8::Isolate::Scope isolate_scope(isolate);
    666       v8::HandleScope handle_scope(isolate);
    667       v8::Handle<Context> context = v8::Context::New(isolate);
    668       v8::Context::Scope context_scope(context);
    669       v8::Handle<String> source = v8::String::NewFromUtf8(isolate, "1+1");
    670       v8::Handle<Script> script = v8::Script::Compile(source);
    671       v8::Handle<Value> result = script->Run();
    672       v8::String::Utf8Value utf8(result);
    673     }
    674     isolate->Dispose();
    675   }
    676 }
    677 
    678 
    679 static const char* kSimpleExtensionSource =
    680   "(function Foo() {"
    681   "  return 4;"
    682   "})() ";
    683 
    684 class IsolateGenesisThread : public JoinableThread {
    685  public:
    686   IsolateGenesisThread(int count, const char* extension_names[])
    687     : JoinableThread("IsolateGenesisThread"),
    688       count_(count),
    689       extension_names_(extension_names)
    690   {}
    691 
    692   virtual void Run() {
    693     v8::Isolate* isolate = v8::Isolate::New();
    694     {
    695       v8::Isolate::Scope isolate_scope(isolate);
    696       CHECK(!i::Isolate::Current()->has_installed_extensions());
    697       v8::ExtensionConfiguration extensions(count_, extension_names_);
    698       v8::HandleScope handle_scope(isolate);
    699       v8::Context::New(isolate, &extensions);
    700       CHECK(i::Isolate::Current()->has_installed_extensions());
    701     }
    702     isolate->Dispose();
    703   }
    704  private:
    705   int count_;
    706   const char** extension_names_;
    707 };
    708 
    709 
    710 // Test installing extensions in separate isolates concurrently.
    711 // http://code.google.com/p/v8/issues/detail?id=1821
    712 TEST(ExtensionsRegistration) {
    713 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
    714   const int kNThreads = 10;
    715 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
    716   const int kNThreads = 4;
    717 #else
    718   const int kNThreads = 40;
    719 #endif
    720   v8::RegisterExtension(new v8::Extension("test0",
    721                                           kSimpleExtensionSource));
    722   v8::RegisterExtension(new v8::Extension("test1",
    723                                           kSimpleExtensionSource));
    724   v8::RegisterExtension(new v8::Extension("test2",
    725                                           kSimpleExtensionSource));
    726   v8::RegisterExtension(new v8::Extension("test3",
    727                                           kSimpleExtensionSource));
    728   v8::RegisterExtension(new v8::Extension("test4",
    729                                           kSimpleExtensionSource));
    730   v8::RegisterExtension(new v8::Extension("test5",
    731                                           kSimpleExtensionSource));
    732   v8::RegisterExtension(new v8::Extension("test6",
    733                                           kSimpleExtensionSource));
    734   v8::RegisterExtension(new v8::Extension("test7",
    735                                           kSimpleExtensionSource));
    736   const char* extension_names[] = { "test0", "test1",
    737                                     "test2", "test3", "test4",
    738                                     "test5", "test6", "test7" };
    739   i::List<JoinableThread*> threads(kNThreads);
    740   for (int i = 0; i < kNThreads; i++) {
    741     threads.Add(new IsolateGenesisThread(8, extension_names));
    742   }
    743   StartJoinAndDeleteThreads(threads);
    744 }
    745