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
43using ::v8::AccessorInfo;
44using ::v8::Context;
45using ::v8::Extension;
46using ::v8::Function;
47using ::v8::HandleScope;
48using ::v8::Local;
49using ::v8::Object;
50using ::v8::ObjectTemplate;
51using ::v8::Persistent;
52using ::v8::Script;
53using ::v8::String;
54using ::v8::Value;
55using ::v8::V8;
56
57
58// Migrating an isolate
59class 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
97TEST(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
114static 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
124class 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
173class 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
192static 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
206TEST(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
221class 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
243TEST(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
257class 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
281TEST(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
296class 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
321TEST(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
339class 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
360class 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.
395TEST(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
410class 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.
448TEST(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
463class 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.
519TEST(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
529class 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.
569TEST(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
590class 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.
620TEST(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
640TEST(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
660static const char* kSimpleExtensionSource =
661  "(function Foo() {"
662  "  return 4;"
663  "})() ";
664
665class 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
692TEST(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