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