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