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