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
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, v8::Handle<v8::Context> context)
62      : Thread("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
100TEST(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
118static 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
128class 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 i::Thread {
150   public:
151    explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
152      : Thread(joinable_thread->name_),
153        joinable_thread_(joinable_thread) {
154    }
155
156    virtual void Run() {
157      joinable_thread_->Run();
158      joinable_thread_->semaphore_.Signal();
159    }
160
161   private:
162    JoinableThread* joinable_thread_;
163  };
164
165  const char* name_;
166  i::Semaphore semaphore_;
167  ThreadWithSemaphore thread_;
168
169  friend class ThreadWithSemaphore;
170
171  DISALLOW_COPY_AND_ASSIGN(JoinableThread);
172};
173
174
175class IsolateLockingThreadWithLocalContext : public JoinableThread {
176 public:
177  explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
178    : JoinableThread("IsolateLockingThread"),
179      isolate_(isolate) {
180  }
181
182  virtual void Run() {
183    v8::Locker locker(isolate_);
184    v8::Isolate::Scope isolate_scope(isolate_);
185    v8::HandleScope handle_scope(isolate_);
186    LocalContext local_context(isolate_);
187    CHECK_EQ(isolate_, v8::internal::Isolate::Current());
188    CalcFibAndCheck();
189  }
190 private:
191  v8::Isolate* isolate_;
192};
193
194
195static void StartJoinAndDeleteThreads(const i::List<JoinableThread*>& threads) {
196  for (int i = 0; i < threads.length(); i++) {
197    threads[i]->Start();
198  }
199  for (int i = 0; i < threads.length(); i++) {
200    threads[i]->Join();
201  }
202  for (int i = 0; i < threads.length(); i++) {
203    delete threads[i];
204  }
205}
206
207
208// Run many threads all locking on the same isolate
209TEST(IsolateLockingStress) {
210#if V8_TARGET_ARCH_MIPS
211  const int kNThreads = 50;
212#else
213  const int kNThreads = 100;
214#endif
215  i::List<JoinableThread*> threads(kNThreads);
216  v8::Isolate* isolate = v8::Isolate::New();
217  for (int i = 0; i < kNThreads; i++) {
218    threads.Add(new IsolateLockingThreadWithLocalContext(isolate));
219  }
220  StartJoinAndDeleteThreads(threads);
221  isolate->Dispose();
222}
223
224class IsolateNonlockingThread : public JoinableThread {
225 public:
226  explicit IsolateNonlockingThread()
227    : JoinableThread("IsolateNonlockingThread") {
228  }
229
230  virtual void Run() {
231    v8::Isolate* isolate = v8::Isolate::New();
232    {
233      v8::Isolate::Scope isolate_scope(isolate);
234      v8::HandleScope handle_scope(isolate);
235      v8::Handle<v8::Context> context = v8::Context::New(isolate);
236      v8::Context::Scope context_scope(context);
237      CHECK_EQ(isolate, v8::internal::Isolate::Current());
238      CalcFibAndCheck();
239    }
240    isolate->Dispose();
241  }
242 private:
243};
244
245
246// Run many threads each accessing its own isolate without locking
247TEST(MultithreadedParallelIsolates) {
248#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
249  const int kNThreads = 10;
250#else
251  const int kNThreads = 50;
252#endif
253  i::List<JoinableThread*> threads(kNThreads);
254  for (int i = 0; i < kNThreads; i++) {
255    threads.Add(new IsolateNonlockingThread());
256  }
257  StartJoinAndDeleteThreads(threads);
258}
259
260
261class IsolateNestedLockingThread : public JoinableThread {
262 public:
263  explicit IsolateNestedLockingThread(v8::Isolate* isolate)
264    : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
265  }
266  virtual void Run() {
267    v8::Locker lock(isolate_);
268    v8::Isolate::Scope isolate_scope(isolate_);
269    v8::HandleScope handle_scope(isolate_);
270    LocalContext local_context(isolate_);
271    {
272      v8::Locker another_lock(isolate_);
273      CalcFibAndCheck();
274    }
275    {
276      v8::Locker another_lock(isolate_);
277      CalcFibAndCheck();
278    }
279  }
280 private:
281  v8::Isolate* isolate_;
282};
283
284
285// Run  many threads with nested locks
286TEST(IsolateNestedLocking) {
287#if V8_TARGET_ARCH_MIPS
288  const int kNThreads = 50;
289#else
290  const int kNThreads = 100;
291#endif
292  v8::Isolate* isolate = v8::Isolate::New();
293  i::List<JoinableThread*> threads(kNThreads);
294  for (int i = 0; i < kNThreads; i++) {
295    threads.Add(new IsolateNestedLockingThread(isolate));
296  }
297  StartJoinAndDeleteThreads(threads);
298  isolate->Dispose();
299}
300
301
302class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread {
303 public:
304  SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
305                                          v8::Isolate* isolate2)
306    : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
307      isolate1_(isolate1), isolate2_(isolate2) {
308  }
309
310  virtual void Run() {
311    v8::Locker lock(isolate1_);
312    v8::Isolate::Scope isolate_scope(isolate1_);
313    v8::HandleScope handle_scope(isolate1_);
314    LocalContext local_context(isolate1_);
315
316    IsolateLockingThreadWithLocalContext threadB(isolate2_);
317    threadB.Start();
318    CalcFibAndCheck();
319    threadB.Join();
320  }
321 private:
322  v8::Isolate* isolate1_;
323  v8::Isolate* isolate2_;
324};
325
326
327// Run parallel threads that lock and access different isolates in parallel
328TEST(SeparateIsolatesLocksNonexclusive) {
329#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
330  const int kNThreads = 50;
331#else
332  const int kNThreads = 100;
333#endif
334  v8::Isolate* isolate1 = v8::Isolate::New();
335  v8::Isolate* isolate2 = v8::Isolate::New();
336  i::List<JoinableThread*> threads(kNThreads);
337  for (int i = 0; i < kNThreads; i++) {
338    threads.Add(new SeparateIsolatesLocksNonexclusiveThread(isolate1,
339                                                             isolate2));
340  }
341  StartJoinAndDeleteThreads(threads);
342  isolate2->Dispose();
343  isolate1->Dispose();
344}
345
346class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread {
347 public:
348  explicit LockIsolateAndCalculateFibSharedContextThread(
349      v8::Isolate* isolate, v8::Handle<v8::Context> context)
350    : JoinableThread("LockIsolateAndCalculateFibThread"),
351      isolate_(isolate),
352      context_(isolate, context) {
353  }
354
355  virtual void Run() {
356    v8::Locker lock(isolate_);
357    v8::Isolate::Scope isolate_scope(isolate_);
358    HandleScope handle_scope(isolate_);
359    v8::Local<v8::Context> context =
360        v8::Local<v8::Context>::New(isolate_, context_);
361    v8::Context::Scope context_scope(context);
362    CalcFibAndCheck();
363  }
364 private:
365  v8::Isolate* isolate_;
366  Persistent<v8::Context> context_;
367};
368
369class LockerUnlockerThread : public JoinableThread {
370 public:
371  explicit LockerUnlockerThread(v8::Isolate* isolate)
372    : JoinableThread("LockerUnlockerThread"),
373      isolate_(isolate) {
374  }
375
376  virtual void Run() {
377    v8::Locker lock(isolate_);
378    v8::Isolate::Scope isolate_scope(isolate_);
379    v8::HandleScope handle_scope(isolate_);
380    v8::Local<v8::Context> context = v8::Context::New(isolate_);
381    {
382      v8::Context::Scope context_scope(context);
383      CalcFibAndCheck();
384    }
385    {
386      LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
387      isolate_->Exit();
388      v8::Unlocker unlocker(isolate_);
389      thread.Start();
390      thread.Join();
391    }
392    isolate_->Enter();
393    {
394      v8::Context::Scope context_scope(context);
395      CalcFibAndCheck();
396    }
397  }
398
399 private:
400  v8::Isolate* isolate_;
401};
402
403
404// Use unlocker inside of a Locker, multiple threads.
405TEST(LockerUnlocker) {
406#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
407  const int kNThreads = 50;
408#else
409  const int kNThreads = 100;
410#endif
411  i::List<JoinableThread*> threads(kNThreads);
412  v8::Isolate* isolate = v8::Isolate::New();
413  for (int i = 0; i < kNThreads; i++) {
414    threads.Add(new LockerUnlockerThread(isolate));
415  }
416  StartJoinAndDeleteThreads(threads);
417  isolate->Dispose();
418}
419
420class LockTwiceAndUnlockThread : public JoinableThread {
421 public:
422  explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
423    : JoinableThread("LockTwiceAndUnlockThread"),
424      isolate_(isolate) {
425  }
426
427  virtual void Run() {
428    v8::Locker lock(isolate_);
429    v8::Isolate::Scope isolate_scope(isolate_);
430    v8::HandleScope handle_scope(isolate_);
431    v8::Local<v8::Context> context = v8::Context::New(isolate_);
432    {
433      v8::Context::Scope context_scope(context);
434      CalcFibAndCheck();
435    }
436    {
437      v8::Locker second_lock(isolate_);
438      {
439        LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
440        isolate_->Exit();
441        v8::Unlocker unlocker(isolate_);
442        thread.Start();
443        thread.Join();
444      }
445    }
446    isolate_->Enter();
447    {
448      v8::Context::Scope context_scope(context);
449      CalcFibAndCheck();
450    }
451  }
452
453 private:
454  v8::Isolate* isolate_;
455};
456
457
458// Use Unlocker inside two Lockers.
459TEST(LockTwiceAndUnlock) {
460#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
461  const int kNThreads = 50;
462#else
463  const int kNThreads = 100;
464#endif
465  i::List<JoinableThread*> threads(kNThreads);
466  v8::Isolate* isolate = v8::Isolate::New();
467  for (int i = 0; i < kNThreads; i++) {
468    threads.Add(new LockTwiceAndUnlockThread(isolate));
469  }
470  StartJoinAndDeleteThreads(threads);
471  isolate->Dispose();
472}
473
474class LockAndUnlockDifferentIsolatesThread : public JoinableThread {
475 public:
476  LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
477                                       v8::Isolate* isolate2)
478    : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
479      isolate1_(isolate1),
480      isolate2_(isolate2) {
481  }
482
483  virtual void Run() {
484    i::SmartPointer<LockIsolateAndCalculateFibSharedContextThread> thread;
485    v8::Locker lock1(isolate1_);
486    CHECK(v8::Locker::IsLocked(isolate1_));
487    CHECK(!v8::Locker::IsLocked(isolate2_));
488    {
489      v8::Isolate::Scope isolate_scope(isolate1_);
490      v8::HandleScope handle_scope(isolate1_);
491      v8::Handle<v8::Context> context1 = v8::Context::New(isolate1_);
492      {
493        v8::Context::Scope context_scope(context1);
494        CalcFibAndCheck();
495      }
496      thread.Reset(new LockIsolateAndCalculateFibSharedContextThread(
497          isolate1_, context1));
498    }
499    v8::Locker lock2(isolate2_);
500    CHECK(v8::Locker::IsLocked(isolate1_));
501    CHECK(v8::Locker::IsLocked(isolate2_));
502    {
503      v8::Isolate::Scope isolate_scope(isolate2_);
504      v8::HandleScope handle_scope(isolate2_);
505      v8::Handle<v8::Context> context2 = v8::Context::New(isolate2_);
506      {
507        v8::Context::Scope context_scope(context2);
508        CalcFibAndCheck();
509      }
510      v8::Unlocker unlock1(isolate1_);
511      CHECK(!v8::Locker::IsLocked(isolate1_));
512      CHECK(v8::Locker::IsLocked(isolate2_));
513      v8::Context::Scope context_scope(context2);
514      thread->Start();
515      CalcFibAndCheck();
516      thread->Join();
517    }
518  }
519
520 private:
521  v8::Isolate* isolate1_;
522  v8::Isolate* isolate2_;
523};
524
525
526// Lock two isolates and unlock one of them.
527TEST(LockAndUnlockDifferentIsolates) {
528  v8::Isolate* isolate1 = v8::Isolate::New();
529  v8::Isolate* isolate2 = v8::Isolate::New();
530  LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2);
531  thread.Start();
532  thread.Join();
533  isolate2->Dispose();
534  isolate1->Dispose();
535}
536
537class LockUnlockLockThread : public JoinableThread {
538 public:
539  LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
540    : JoinableThread("LockUnlockLockThread"),
541      isolate_(isolate),
542      context_(isolate, context) {
543  }
544
545  virtual void Run() {
546    v8::Locker lock1(isolate_);
547    CHECK(v8::Locker::IsLocked(isolate_));
548    CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
549    {
550      v8::Isolate::Scope isolate_scope(isolate_);
551      v8::HandleScope handle_scope(isolate_);
552      v8::Local<v8::Context> context =
553          v8::Local<v8::Context>::New(isolate_, context_);
554      v8::Context::Scope context_scope(context);
555      CalcFibAndCheck();
556    }
557    {
558      v8::Unlocker unlock1(isolate_);
559      CHECK(!v8::Locker::IsLocked(isolate_));
560      CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
561      {
562        v8::Locker lock2(isolate_);
563        v8::Isolate::Scope isolate_scope(isolate_);
564        v8::HandleScope handle_scope(isolate_);
565        CHECK(v8::Locker::IsLocked(isolate_));
566        CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
567        v8::Local<v8::Context> context =
568            v8::Local<v8::Context>::New(isolate_, context_);
569        v8::Context::Scope context_scope(context);
570        CalcFibAndCheck();
571      }
572    }
573  }
574
575 private:
576  v8::Isolate* isolate_;
577  v8::Persistent<v8::Context> context_;
578};
579
580
581// Locker inside an Unlocker inside a Locker.
582TEST(LockUnlockLockMultithreaded) {
583#if V8_TARGET_ARCH_MIPS
584  const int kNThreads = 50;
585#else
586  const int kNThreads = 100;
587#endif
588  v8::Isolate* isolate = v8::Isolate::New();
589  i::List<JoinableThread*> threads(kNThreads);
590  {
591    v8::Locker locker_(isolate);
592    v8::Isolate::Scope isolate_scope(isolate);
593    v8::HandleScope handle_scope(isolate);
594    v8::Handle<v8::Context> context = v8::Context::New(isolate);
595    for (int i = 0; i < kNThreads; i++) {
596      threads.Add(new LockUnlockLockThread(
597          isolate, context));
598    }
599  }
600  StartJoinAndDeleteThreads(threads);
601  isolate->Dispose();
602}
603
604class LockUnlockLockDefaultIsolateThread : public JoinableThread {
605 public:
606  explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context)
607      : JoinableThread("LockUnlockLockDefaultIsolateThread"),
608        context_(CcTest::isolate(), context) {}
609
610  virtual void Run() {
611    v8::Locker lock1(CcTest::isolate());
612    {
613      v8::Isolate::Scope isolate_scope(CcTest::isolate());
614      v8::HandleScope handle_scope(CcTest::isolate());
615      v8::Local<v8::Context> context =
616          v8::Local<v8::Context>::New(CcTest::isolate(), context_);
617      v8::Context::Scope context_scope(context);
618      CalcFibAndCheck();
619    }
620    {
621      v8::Unlocker unlock1(CcTest::isolate());
622      {
623        v8::Locker lock2(CcTest::isolate());
624        v8::Isolate::Scope isolate_scope(CcTest::isolate());
625        v8::HandleScope handle_scope(CcTest::isolate());
626        v8::Local<v8::Context> context =
627            v8::Local<v8::Context>::New(CcTest::isolate(), context_);
628        v8::Context::Scope context_scope(context);
629        CalcFibAndCheck();
630      }
631    }
632  }
633
634 private:
635  v8::Persistent<v8::Context> context_;
636};
637
638
639// Locker inside an Unlocker inside a Locker for default isolate.
640TEST(LockUnlockLockDefaultIsolateMultithreaded) {
641#if V8_TARGET_ARCH_MIPS
642  const int kNThreads = 50;
643#else
644  const int kNThreads = 100;
645#endif
646  Local<v8::Context> context;
647  i::List<JoinableThread*> threads(kNThreads);
648  {
649    v8::Locker locker_(CcTest::isolate());
650    v8::Isolate::Scope isolate_scope(CcTest::isolate());
651    v8::HandleScope handle_scope(CcTest::isolate());
652    context = v8::Context::New(CcTest::isolate());
653    for (int i = 0; i < kNThreads; i++) {
654      threads.Add(new LockUnlockLockDefaultIsolateThread(context));
655    }
656  }
657  StartJoinAndDeleteThreads(threads);
658}
659
660
661TEST(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::NewFromUtf8(isolate, "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
680static const char* kSimpleExtensionSource =
681  "(function Foo() {"
682  "  return 4;"
683  "})() ";
684
685class 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
713TEST(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