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