c909a02125e4f918b0d23907d313033cdba618c9
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-lockers.cc
1 // Copyright 2007-2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <limits.h>
29
30 #include "src/v8.h"
31
32 #include "src/api.h"
33 #include "src/base/platform/platform.h"
34 #include "src/compilation-cache.h"
35 #include "src/execution.h"
36 #include "src/isolate.h"
37 #include "src/parser.h"
38 #include "src/smart-pointers.h"
39 #include "src/snapshot.h"
40 #include "src/unicode-inl.h"
41 #include "src/utils.h"
42 #include "test/cctest/cctest.h"
43
44 using ::v8::Context;
45 using ::v8::Extension;
46 using ::v8::Function;
47 using ::v8::HandleScope;
48 using ::v8::Local;
49 using ::v8::Object;
50 using ::v8::ObjectTemplate;
51 using ::v8::Persistent;
52 using ::v8::Script;
53 using ::v8::String;
54 using ::v8::Value;
55 using ::v8::V8;
56
57
58 // Migrating an isolate
59 class KangarooThread : public v8::base::Thread {
60  public:
61   KangarooThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
62       : Thread(Options("KangarooThread")),
63         isolate_(isolate),
64         context_(isolate, context) {}
65
66   void Run() {
67     {
68       v8::Locker locker(isolate_);
69       v8::Isolate::Scope isolate_scope(isolate_);
70       CHECK_EQ(reinterpret_cast<v8::internal::Isolate*>(isolate_),
71                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(reinterpret_cast<v8::internal::Isolate*>(isolate),
111              v8::internal::Isolate::Current());
112     CompileRun("function getValue() { return 30; }");
113     thread1.Reset(new KangarooThread(isolate, context));
114   }
115   thread1->Start();
116   thread1->Join();
117 }
118
119
120 static void CalcFibAndCheck() {
121   Local<Value> v = CompileRun("function fib(n) {"
122                               "  if (n <= 2) return 1;"
123                               "  return fib(n-1) + fib(n-2);"
124                               "}"
125                               "fib(10)");
126   CHECK(v->IsNumber());
127   CHECK_EQ(55, static_cast<int>(v->NumberValue()));
128 }
129
130 class JoinableThread {
131  public:
132   explicit JoinableThread(const char* name)
133     : name_(name),
134       semaphore_(0),
135       thread_(this) {
136   }
137
138   virtual ~JoinableThread() {}
139
140   void Start() {
141     thread_.Start();
142   }
143
144   void Join() {
145     semaphore_.Wait();
146     thread_.Join();
147   }
148
149   virtual void Run() = 0;
150
151  private:
152   class ThreadWithSemaphore : public v8::base::Thread {
153    public:
154     explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
155         : Thread(Options(joinable_thread->name_)),
156           joinable_thread_(joinable_thread) {}
157
158     virtual void Run() {
159       joinable_thread_->Run();
160       joinable_thread_->semaphore_.Signal();
161     }
162
163    private:
164     JoinableThread* joinable_thread_;
165   };
166
167   const char* name_;
168   v8::base::Semaphore semaphore_;
169   ThreadWithSemaphore thread_;
170
171   friend class ThreadWithSemaphore;
172
173   DISALLOW_COPY_AND_ASSIGN(JoinableThread);
174 };
175
176
177 class IsolateLockingThreadWithLocalContext : public JoinableThread {
178  public:
179   explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
180     : JoinableThread("IsolateLockingThread"),
181       isolate_(isolate) {
182   }
183
184   virtual void Run() {
185     v8::Locker locker(isolate_);
186     v8::Isolate::Scope isolate_scope(isolate_);
187     v8::HandleScope handle_scope(isolate_);
188     LocalContext local_context(isolate_);
189     CHECK_EQ(reinterpret_cast<v8::internal::Isolate*>(isolate_),
190              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
228 class IsolateNestedLockingThread : public JoinableThread {
229  public:
230   explicit IsolateNestedLockingThread(v8::Isolate* isolate)
231     : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
232   }
233   virtual void Run() {
234     v8::Locker lock(isolate_);
235     v8::Isolate::Scope isolate_scope(isolate_);
236     v8::HandleScope handle_scope(isolate_);
237     LocalContext local_context(isolate_);
238     {
239       v8::Locker another_lock(isolate_);
240       CalcFibAndCheck();
241     }
242     {
243       v8::Locker another_lock(isolate_);
244       CalcFibAndCheck();
245     }
246   }
247  private:
248   v8::Isolate* isolate_;
249 };
250
251
252 // Run  many threads with nested locks
253 TEST(IsolateNestedLocking) {
254 #if V8_TARGET_ARCH_MIPS
255   const int kNThreads = 50;
256 #else
257   const int kNThreads = 100;
258 #endif
259   v8::Isolate* isolate = v8::Isolate::New();
260   i::List<JoinableThread*> threads(kNThreads);
261   for (int i = 0; i < kNThreads; i++) {
262     threads.Add(new IsolateNestedLockingThread(isolate));
263   }
264   StartJoinAndDeleteThreads(threads);
265   isolate->Dispose();
266 }
267
268
269 class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread {
270  public:
271   SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
272                                           v8::Isolate* isolate2)
273     : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
274       isolate1_(isolate1), isolate2_(isolate2) {
275   }
276
277   virtual void Run() {
278     v8::Locker lock(isolate1_);
279     v8::Isolate::Scope isolate_scope(isolate1_);
280     v8::HandleScope handle_scope(isolate1_);
281     LocalContext local_context(isolate1_);
282
283     IsolateLockingThreadWithLocalContext threadB(isolate2_);
284     threadB.Start();
285     CalcFibAndCheck();
286     threadB.Join();
287   }
288  private:
289   v8::Isolate* isolate1_;
290   v8::Isolate* isolate2_;
291 };
292
293
294 // Run parallel threads that lock and access different isolates in parallel
295 TEST(SeparateIsolatesLocksNonexclusive) {
296 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
297   const int kNThreads = 50;
298 #else
299   const int kNThreads = 100;
300 #endif
301   v8::Isolate* isolate1 = v8::Isolate::New();
302   v8::Isolate* isolate2 = v8::Isolate::New();
303   i::List<JoinableThread*> threads(kNThreads);
304   for (int i = 0; i < kNThreads; i++) {
305     threads.Add(new SeparateIsolatesLocksNonexclusiveThread(isolate1,
306                                                              isolate2));
307   }
308   StartJoinAndDeleteThreads(threads);
309   isolate2->Dispose();
310   isolate1->Dispose();
311 }
312
313 class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread {
314  public:
315   explicit LockIsolateAndCalculateFibSharedContextThread(
316       v8::Isolate* isolate, v8::Handle<v8::Context> context)
317     : JoinableThread("LockIsolateAndCalculateFibThread"),
318       isolate_(isolate),
319       context_(isolate, context) {
320   }
321
322   virtual void Run() {
323     v8::Locker lock(isolate_);
324     v8::Isolate::Scope isolate_scope(isolate_);
325     HandleScope handle_scope(isolate_);
326     v8::Local<v8::Context> context =
327         v8::Local<v8::Context>::New(isolate_, context_);
328     v8::Context::Scope context_scope(context);
329     CalcFibAndCheck();
330   }
331  private:
332   v8::Isolate* isolate_;
333   Persistent<v8::Context> context_;
334 };
335
336 class LockerUnlockerThread : public JoinableThread {
337  public:
338   explicit LockerUnlockerThread(v8::Isolate* isolate)
339     : JoinableThread("LockerUnlockerThread"),
340       isolate_(isolate) {
341   }
342
343   virtual void Run() {
344     v8::Locker lock(isolate_);
345     v8::Isolate::Scope isolate_scope(isolate_);
346     v8::HandleScope handle_scope(isolate_);
347     v8::Local<v8::Context> context = v8::Context::New(isolate_);
348     {
349       v8::Context::Scope context_scope(context);
350       CalcFibAndCheck();
351     }
352     {
353       LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
354       isolate_->Exit();
355       v8::Unlocker unlocker(isolate_);
356       thread.Start();
357       thread.Join();
358     }
359     isolate_->Enter();
360     {
361       v8::Context::Scope context_scope(context);
362       CalcFibAndCheck();
363     }
364   }
365
366  private:
367   v8::Isolate* isolate_;
368 };
369
370
371 // Use unlocker inside of a Locker, multiple threads.
372 TEST(LockerUnlocker) {
373 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
374   const int kNThreads = 50;
375 #else
376   const int kNThreads = 100;
377 #endif
378   i::List<JoinableThread*> threads(kNThreads);
379   v8::Isolate* isolate = v8::Isolate::New();
380   for (int i = 0; i < kNThreads; i++) {
381     threads.Add(new LockerUnlockerThread(isolate));
382   }
383   StartJoinAndDeleteThreads(threads);
384   isolate->Dispose();
385 }
386
387 class LockTwiceAndUnlockThread : public JoinableThread {
388  public:
389   explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
390     : JoinableThread("LockTwiceAndUnlockThread"),
391       isolate_(isolate) {
392   }
393
394   virtual void Run() {
395     v8::Locker lock(isolate_);
396     v8::Isolate::Scope isolate_scope(isolate_);
397     v8::HandleScope handle_scope(isolate_);
398     v8::Local<v8::Context> context = v8::Context::New(isolate_);
399     {
400       v8::Context::Scope context_scope(context);
401       CalcFibAndCheck();
402     }
403     {
404       v8::Locker second_lock(isolate_);
405       {
406         LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
407         isolate_->Exit();
408         v8::Unlocker unlocker(isolate_);
409         thread.Start();
410         thread.Join();
411       }
412     }
413     isolate_->Enter();
414     {
415       v8::Context::Scope context_scope(context);
416       CalcFibAndCheck();
417     }
418   }
419
420  private:
421   v8::Isolate* isolate_;
422 };
423
424
425 // Use Unlocker inside two Lockers.
426 TEST(LockTwiceAndUnlock) {
427 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
428   const int kNThreads = 50;
429 #else
430   const int kNThreads = 100;
431 #endif
432   i::List<JoinableThread*> threads(kNThreads);
433   v8::Isolate* isolate = v8::Isolate::New();
434   for (int i = 0; i < kNThreads; i++) {
435     threads.Add(new LockTwiceAndUnlockThread(isolate));
436   }
437   StartJoinAndDeleteThreads(threads);
438   isolate->Dispose();
439 }
440
441 class LockAndUnlockDifferentIsolatesThread : public JoinableThread {
442  public:
443   LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
444                                        v8::Isolate* isolate2)
445     : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
446       isolate1_(isolate1),
447       isolate2_(isolate2) {
448   }
449
450   virtual void Run() {
451     i::SmartPointer<LockIsolateAndCalculateFibSharedContextThread> thread;
452     v8::Locker lock1(isolate1_);
453     CHECK(v8::Locker::IsLocked(isolate1_));
454     CHECK(!v8::Locker::IsLocked(isolate2_));
455     {
456       v8::Isolate::Scope isolate_scope(isolate1_);
457       v8::HandleScope handle_scope(isolate1_);
458       v8::Handle<v8::Context> context1 = v8::Context::New(isolate1_);
459       {
460         v8::Context::Scope context_scope(context1);
461         CalcFibAndCheck();
462       }
463       thread.Reset(new LockIsolateAndCalculateFibSharedContextThread(
464           isolate1_, context1));
465     }
466     v8::Locker lock2(isolate2_);
467     CHECK(v8::Locker::IsLocked(isolate1_));
468     CHECK(v8::Locker::IsLocked(isolate2_));
469     {
470       v8::Isolate::Scope isolate_scope(isolate2_);
471       v8::HandleScope handle_scope(isolate2_);
472       v8::Handle<v8::Context> context2 = v8::Context::New(isolate2_);
473       {
474         v8::Context::Scope context_scope(context2);
475         CalcFibAndCheck();
476       }
477       v8::Unlocker unlock1(isolate1_);
478       CHECK(!v8::Locker::IsLocked(isolate1_));
479       CHECK(v8::Locker::IsLocked(isolate2_));
480       v8::Context::Scope context_scope(context2);
481       thread->Start();
482       CalcFibAndCheck();
483       thread->Join();
484     }
485   }
486
487  private:
488   v8::Isolate* isolate1_;
489   v8::Isolate* isolate2_;
490 };
491
492
493 // Lock two isolates and unlock one of them.
494 TEST(LockAndUnlockDifferentIsolates) {
495   v8::Isolate* isolate1 = v8::Isolate::New();
496   v8::Isolate* isolate2 = v8::Isolate::New();
497   LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2);
498   thread.Start();
499   thread.Join();
500   isolate2->Dispose();
501   isolate1->Dispose();
502 }
503
504 class LockUnlockLockThread : public JoinableThread {
505  public:
506   LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
507     : JoinableThread("LockUnlockLockThread"),
508       isolate_(isolate),
509       context_(isolate, context) {
510   }
511
512   virtual void Run() {
513     v8::Locker lock1(isolate_);
514     CHECK(v8::Locker::IsLocked(isolate_));
515     CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
516     {
517       v8::Isolate::Scope isolate_scope(isolate_);
518       v8::HandleScope handle_scope(isolate_);
519       v8::Local<v8::Context> context =
520           v8::Local<v8::Context>::New(isolate_, context_);
521       v8::Context::Scope context_scope(context);
522       CalcFibAndCheck();
523     }
524     {
525       v8::Unlocker unlock1(isolate_);
526       CHECK(!v8::Locker::IsLocked(isolate_));
527       CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
528       {
529         v8::Locker lock2(isolate_);
530         v8::Isolate::Scope isolate_scope(isolate_);
531         v8::HandleScope handle_scope(isolate_);
532         CHECK(v8::Locker::IsLocked(isolate_));
533         CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
534         v8::Local<v8::Context> context =
535             v8::Local<v8::Context>::New(isolate_, context_);
536         v8::Context::Scope context_scope(context);
537         CalcFibAndCheck();
538       }
539     }
540   }
541
542  private:
543   v8::Isolate* isolate_;
544   v8::Persistent<v8::Context> context_;
545 };
546
547
548 // Locker inside an Unlocker inside a Locker.
549 TEST(LockUnlockLockMultithreaded) {
550 #if V8_TARGET_ARCH_MIPS
551   const int kNThreads = 50;
552 #else
553   const int kNThreads = 100;
554 #endif
555   v8::Isolate* isolate = v8::Isolate::New();
556   i::List<JoinableThread*> threads(kNThreads);
557   {
558     v8::Locker locker_(isolate);
559     v8::Isolate::Scope isolate_scope(isolate);
560     v8::HandleScope handle_scope(isolate);
561     v8::Handle<v8::Context> context = v8::Context::New(isolate);
562     for (int i = 0; i < kNThreads; i++) {
563       threads.Add(new LockUnlockLockThread(
564           isolate, context));
565     }
566   }
567   StartJoinAndDeleteThreads(threads);
568   isolate->Dispose();
569 }
570
571 class LockUnlockLockDefaultIsolateThread : public JoinableThread {
572  public:
573   explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context)
574       : JoinableThread("LockUnlockLockDefaultIsolateThread"),
575         context_(CcTest::isolate(), context) {}
576
577   virtual void Run() {
578     v8::Locker lock1(CcTest::isolate());
579     {
580       v8::Isolate::Scope isolate_scope(CcTest::isolate());
581       v8::HandleScope handle_scope(CcTest::isolate());
582       v8::Local<v8::Context> context =
583           v8::Local<v8::Context>::New(CcTest::isolate(), context_);
584       v8::Context::Scope context_scope(context);
585       CalcFibAndCheck();
586     }
587     {
588       v8::Unlocker unlock1(CcTest::isolate());
589       {
590         v8::Locker lock2(CcTest::isolate());
591         v8::Isolate::Scope isolate_scope(CcTest::isolate());
592         v8::HandleScope handle_scope(CcTest::isolate());
593         v8::Local<v8::Context> context =
594             v8::Local<v8::Context>::New(CcTest::isolate(), context_);
595         v8::Context::Scope context_scope(context);
596         CalcFibAndCheck();
597       }
598     }
599   }
600
601  private:
602   v8::Persistent<v8::Context> context_;
603 };
604
605
606 // Locker inside an Unlocker inside a Locker for default isolate.
607 TEST(LockUnlockLockDefaultIsolateMultithreaded) {
608 #if V8_TARGET_ARCH_MIPS
609   const int kNThreads = 50;
610 #else
611   const int kNThreads = 100;
612 #endif
613   Local<v8::Context> context;
614   i::List<JoinableThread*> threads(kNThreads);
615   {
616     v8::Locker locker_(CcTest::isolate());
617     v8::Isolate::Scope isolate_scope(CcTest::isolate());
618     v8::HandleScope handle_scope(CcTest::isolate());
619     context = v8::Context::New(CcTest::isolate());
620     for (int i = 0; i < kNThreads; i++) {
621       threads.Add(new LockUnlockLockDefaultIsolateThread(context));
622     }
623   }
624   StartJoinAndDeleteThreads(threads);
625 }
626
627
628 TEST(Regress1433) {
629   for (int i = 0; i < 10; i++) {
630     v8::Isolate* isolate = v8::Isolate::New();
631     {
632       v8::Locker lock(isolate);
633       v8::Isolate::Scope isolate_scope(isolate);
634       v8::HandleScope handle_scope(isolate);
635       v8::Handle<Context> context = v8::Context::New(isolate);
636       v8::Context::Scope context_scope(context);
637       v8::Handle<String> source = v8::String::NewFromUtf8(isolate, "1+1");
638       v8::Handle<Script> script = v8::Script::Compile(source);
639       v8::Handle<Value> result = script->Run();
640       v8::String::Utf8Value utf8(result);
641     }
642     isolate->Dispose();
643   }
644 }
645
646
647 static const char* kSimpleExtensionSource =
648   "(function Foo() {"
649   "  return 4;"
650   "})() ";
651
652 class IsolateGenesisThread : public JoinableThread {
653  public:
654   IsolateGenesisThread(int count, const char* extension_names[])
655     : JoinableThread("IsolateGenesisThread"),
656       count_(count),
657       extension_names_(extension_names)
658   {}
659
660   virtual void Run() {
661     v8::Isolate* isolate = v8::Isolate::New();
662     {
663       v8::Isolate::Scope isolate_scope(isolate);
664       CHECK(!i::Isolate::Current()->has_installed_extensions());
665       v8::ExtensionConfiguration extensions(count_, extension_names_);
666       v8::HandleScope handle_scope(isolate);
667       v8::Context::New(isolate, &extensions);
668       CHECK(i::Isolate::Current()->has_installed_extensions());
669     }
670     isolate->Dispose();
671   }
672  private:
673   int count_;
674   const char** extension_names_;
675 };
676
677
678 // Test installing extensions in separate isolates concurrently.
679 // http://code.google.com/p/v8/issues/detail?id=1821
680 TEST(ExtensionsRegistration) {
681 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
682   const int kNThreads = 10;
683 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
684   const int kNThreads = 4;
685 #else
686   const int kNThreads = 40;
687 #endif
688   v8::RegisterExtension(new v8::Extension("test0",
689                                           kSimpleExtensionSource));
690   v8::RegisterExtension(new v8::Extension("test1",
691                                           kSimpleExtensionSource));
692   v8::RegisterExtension(new v8::Extension("test2",
693                                           kSimpleExtensionSource));
694   v8::RegisterExtension(new v8::Extension("test3",
695                                           kSimpleExtensionSource));
696   v8::RegisterExtension(new v8::Extension("test4",
697                                           kSimpleExtensionSource));
698   v8::RegisterExtension(new v8::Extension("test5",
699                                           kSimpleExtensionSource));
700   v8::RegisterExtension(new v8::Extension("test6",
701                                           kSimpleExtensionSource));
702   v8::RegisterExtension(new v8::Extension("test7",
703                                           kSimpleExtensionSource));
704   const char* extension_names[] = { "test0", "test1",
705                                     "test2", "test3", "test4",
706                                     "test5", "test6", "test7" };
707   i::List<JoinableThread*> threads(kNThreads);
708   for (int i = 0; i < kNThreads; i++) {
709     threads.Add(new IsolateGenesisThread(8, extension_names));
710   }
711   StartJoinAndDeleteThreads(threads);
712 }