• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
KangarooThread(v8::Isolate * isolate,v8::Handle<v8::Context> context,int value)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 
Run()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
TEST(KangarooIsolates)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 
CalcFibAndCheck()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:
JoinableThread(const char * name)126   explicit JoinableThread(const char* name)
127     : name_(name),
128       semaphore_(i::OS::CreateSemaphore(0)),
129       thread_(this) {
130   }
131 
~JoinableThread()132   virtual ~JoinableThread() {
133     delete semaphore_;
134   }
135 
Start()136   void Start() {
137     thread_.Start();
138   }
139 
Join()140   void Join() {
141     semaphore_->Wait();
142   }
143 
144   virtual void Run() = 0;
145 
146  private:
147   class ThreadWithSemaphore : public i::Thread {
148    public:
ThreadWithSemaphore(JoinableThread * joinable_thread)149     explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
150       : Thread(joinable_thread->name_),
151         joinable_thread_(joinable_thread) {
152     }
153 
Run()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:
IsolateLockingThreadWithLocalContext(v8::Isolate * isolate)175   explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
176     : JoinableThread("IsolateLockingThread"),
177       isolate_(isolate) {
178   }
179 
Run()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 
StartJoinAndDeleteThreads(const i::List<JoinableThread * > & threads)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
TEST(IsolateLockingStress)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:
IsolateNonlockingThread()223   explicit IsolateNonlockingThread()
224     : JoinableThread("IsolateNonlockingThread") {
225   }
226 
Run()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
TEST(MultithreadedParallelIsolates)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:
IsolateNestedLockingThread(v8::Isolate * isolate)259   explicit IsolateNestedLockingThread(v8::Isolate* isolate)
260     : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
261   }
Run()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
TEST(IsolateNestedLocking)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:
SeparateIsolatesLocksNonexclusiveThread(v8::Isolate * isolate1,v8::Isolate * isolate2)298   SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
299                                           v8::Isolate* isolate2)
300     : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
301       isolate1_(isolate1), isolate2_(isolate2) {
302   }
303 
Run()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
TEST(SeparateIsolatesLocksNonexclusive)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:
LockIsolateAndCalculateFibSharedContextThread(v8::Isolate * isolate,v8::Handle<v8::Context> context)341   explicit LockIsolateAndCalculateFibSharedContextThread(
342       v8::Isolate* isolate, v8::Handle<v8::Context> context)
343     : JoinableThread("LockIsolateAndCalculateFibThread"),
344       isolate_(isolate),
345       context_(context) {
346   }
347 
Run()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:
LockerUnlockerThread(v8::Isolate * isolate)362   explicit LockerUnlockerThread(v8::Isolate* isolate)
363     : JoinableThread("LockerUnlockerThread"),
364       isolate_(isolate) {
365   }
366 
Run()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.
TEST(LockerUnlocker)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:
LockTwiceAndUnlockThread(v8::Isolate * isolate)412   explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
413     : JoinableThread("LockTwiceAndUnlockThread"),
414       isolate_(isolate) {
415   }
416 
Run()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.
TEST(LockTwiceAndUnlock)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:
LockAndUnlockDifferentIsolatesThread(v8::Isolate * isolate1,v8::Isolate * isolate2)465   LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
466                                        v8::Isolate* isolate2)
467     : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
468       isolate1_(isolate1),
469       isolate2_(isolate2) {
470   }
471 
Run()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.
TEST(LockAndUnlockDifferentIsolates)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:
LockUnlockLockThread(v8::Isolate * isolate,v8::Handle<v8::Context> context)531   LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
532     : JoinableThread("LockUnlockLockThread"),
533       isolate_(isolate),
534       context_(context) {
535   }
536 
Run()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.
TEST(LockUnlockLockMultithreaded)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:
LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context)592   explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context)
593     : JoinableThread("LockUnlockLockDefaultIsolateThread"),
594       context_(context) {
595   }
596 
Run()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.
TEST(LockUnlockLockDefaultIsolateMultithreaded)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 
TEST(Regress1433)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:
IsolateGenesisThread(int count,const char * extension_names[])667   IsolateGenesisThread(int count, const char* extension_names[])
668     : JoinableThread("IsolateGenesisThread"),
669       count_(count),
670       extension_names_(extension_names)
671   {}
672 
Run()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
TEST(ExtensionsRegistration)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