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
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.
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.
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"
45 using ::v8::Extension;
47 using ::v8::HandleScope;
50 using ::v8::ObjectTemplate;
51 using ::v8::Persistent;
58 // Migrating an isolate
59 class KangarooThread : public v8::base::Thread {
61 KangarooThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
62 : Thread(Options("KangarooThread")),
64 context_(isolate, context) {}
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()");
78 CHECK_EQ(30, static_cast<int>(v->NumberValue()));
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()");
89 CHECK_EQ(30, static_cast<int>(v->NumberValue()));
95 v8::Isolate* isolate_;
96 Persistent<v8::Context> context_;
100 // Migrates an isolate from one thread to another
101 TEST(KangarooIsolates) {
102 v8::Isolate* isolate = v8::Isolate::New();
103 i::SmartPointer<KangarooThread> thread1;
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));
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);"
126 CHECK(v->IsNumber());
127 CHECK_EQ(55, static_cast<int>(v->NumberValue()));
130 class JoinableThread {
132 explicit JoinableThread(const char* name)
138 virtual ~JoinableThread() {}
149 virtual void Run() = 0;
152 class ThreadWithSemaphore : public v8::base::Thread {
154 explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
155 : Thread(Options(joinable_thread->name_)),
156 joinable_thread_(joinable_thread) {}
159 joinable_thread_->Run();
160 joinable_thread_->semaphore_.Signal();
164 JoinableThread* joinable_thread_;
168 v8::base::Semaphore semaphore_;
169 ThreadWithSemaphore thread_;
171 friend class ThreadWithSemaphore;
173 DISALLOW_COPY_AND_ASSIGN(JoinableThread);
177 class IsolateLockingThreadWithLocalContext : public JoinableThread {
179 explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
180 : JoinableThread("IsolateLockingThread"),
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());
194 v8::Isolate* isolate_;
198 static void StartJoinAndDeleteThreads(const i::List<JoinableThread*>& threads) {
199 for (int i = 0; i < threads.length(); i++) {
202 for (int i = 0; i < threads.length(); i++) {
205 for (int i = 0; i < threads.length(); i++) {
211 // Run many threads all locking on the same isolate
212 TEST(IsolateLockingStress) {
213 #if V8_TARGET_ARCH_MIPS
214 const int kNThreads = 50;
216 const int kNThreads = 100;
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));
223 StartJoinAndDeleteThreads(threads);
228 class IsolateNestedLockingThread : public JoinableThread {
230 explicit IsolateNestedLockingThread(v8::Isolate* isolate)
231 : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
234 v8::Locker lock(isolate_);
235 v8::Isolate::Scope isolate_scope(isolate_);
236 v8::HandleScope handle_scope(isolate_);
237 LocalContext local_context(isolate_);
239 v8::Locker another_lock(isolate_);
243 v8::Locker another_lock(isolate_);
248 v8::Isolate* isolate_;
252 // Run many threads with nested locks
253 TEST(IsolateNestedLocking) {
254 #if V8_TARGET_ARCH_MIPS
255 const int kNThreads = 50;
257 const int kNThreads = 100;
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));
264 StartJoinAndDeleteThreads(threads);
269 class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread {
271 SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
272 v8::Isolate* isolate2)
273 : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
274 isolate1_(isolate1), isolate2_(isolate2) {
278 v8::Locker lock(isolate1_);
279 v8::Isolate::Scope isolate_scope(isolate1_);
280 v8::HandleScope handle_scope(isolate1_);
281 LocalContext local_context(isolate1_);
283 IsolateLockingThreadWithLocalContext threadB(isolate2_);
289 v8::Isolate* isolate1_;
290 v8::Isolate* isolate2_;
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;
299 const int kNThreads = 100;
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,
308 StartJoinAndDeleteThreads(threads);
313 class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread {
315 explicit LockIsolateAndCalculateFibSharedContextThread(
316 v8::Isolate* isolate, v8::Handle<v8::Context> context)
317 : JoinableThread("LockIsolateAndCalculateFibThread"),
319 context_(isolate, context) {
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);
332 v8::Isolate* isolate_;
333 Persistent<v8::Context> context_;
336 class LockerUnlockerThread : public JoinableThread {
338 explicit LockerUnlockerThread(v8::Isolate* isolate)
339 : JoinableThread("LockerUnlockerThread"),
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_);
349 v8::Context::Scope context_scope(context);
353 LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
355 v8::Unlocker unlocker(isolate_);
361 v8::Context::Scope context_scope(context);
367 v8::Isolate* isolate_;
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;
376 const int kNThreads = 100;
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));
383 StartJoinAndDeleteThreads(threads);
387 class LockTwiceAndUnlockThread : public JoinableThread {
389 explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
390 : JoinableThread("LockTwiceAndUnlockThread"),
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_);
400 v8::Context::Scope context_scope(context);
404 v8::Locker second_lock(isolate_);
406 LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
408 v8::Unlocker unlocker(isolate_);
415 v8::Context::Scope context_scope(context);
421 v8::Isolate* isolate_;
425 // Use Unlocker inside two Lockers.
426 TEST(LockTwiceAndUnlock) {
427 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
428 const int kNThreads = 50;
430 const int kNThreads = 100;
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));
437 StartJoinAndDeleteThreads(threads);
441 class LockAndUnlockDifferentIsolatesThread : public JoinableThread {
443 LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
444 v8::Isolate* isolate2)
445 : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
447 isolate2_(isolate2) {
451 i::SmartPointer<LockIsolateAndCalculateFibSharedContextThread> thread;
452 v8::Locker lock1(isolate1_);
453 CHECK(v8::Locker::IsLocked(isolate1_));
454 CHECK(!v8::Locker::IsLocked(isolate2_));
456 v8::Isolate::Scope isolate_scope(isolate1_);
457 v8::HandleScope handle_scope(isolate1_);
458 v8::Handle<v8::Context> context1 = v8::Context::New(isolate1_);
460 v8::Context::Scope context_scope(context1);
463 thread.Reset(new LockIsolateAndCalculateFibSharedContextThread(
464 isolate1_, context1));
466 v8::Locker lock2(isolate2_);
467 CHECK(v8::Locker::IsLocked(isolate1_));
468 CHECK(v8::Locker::IsLocked(isolate2_));
470 v8::Isolate::Scope isolate_scope(isolate2_);
471 v8::HandleScope handle_scope(isolate2_);
472 v8::Handle<v8::Context> context2 = v8::Context::New(isolate2_);
474 v8::Context::Scope context_scope(context2);
477 v8::Unlocker unlock1(isolate1_);
478 CHECK(!v8::Locker::IsLocked(isolate1_));
479 CHECK(v8::Locker::IsLocked(isolate2_));
480 v8::Context::Scope context_scope(context2);
488 v8::Isolate* isolate1_;
489 v8::Isolate* isolate2_;
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);
504 class LockUnlockLockThread : public JoinableThread {
506 LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
507 : JoinableThread("LockUnlockLockThread"),
509 context_(isolate, context) {
513 v8::Locker lock1(isolate_);
514 CHECK(v8::Locker::IsLocked(isolate_));
515 CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
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);
525 v8::Unlocker unlock1(isolate_);
526 CHECK(!v8::Locker::IsLocked(isolate_));
527 CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
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);
543 v8::Isolate* isolate_;
544 v8::Persistent<v8::Context> context_;
548 // Locker inside an Unlocker inside a Locker.
549 TEST(LockUnlockLockMultithreaded) {
550 #if V8_TARGET_ARCH_MIPS
551 const int kNThreads = 50;
553 const int kNThreads = 100;
555 v8::Isolate* isolate = v8::Isolate::New();
556 i::List<JoinableThread*> threads(kNThreads);
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(
567 StartJoinAndDeleteThreads(threads);
571 class LockUnlockLockDefaultIsolateThread : public JoinableThread {
573 explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context)
574 : JoinableThread("LockUnlockLockDefaultIsolateThread"),
575 context_(CcTest::isolate(), context) {}
578 v8::Locker lock1(CcTest::isolate());
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);
588 v8::Unlocker unlock1(CcTest::isolate());
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);
602 v8::Persistent<v8::Context> context_;
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;
611 const int kNThreads = 100;
613 Local<v8::Context> context;
614 i::List<JoinableThread*> threads(kNThreads);
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));
624 StartJoinAndDeleteThreads(threads);
629 for (int i = 0; i < 10; i++) {
630 v8::Isolate* isolate = v8::Isolate::New();
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);
647 static const char* kSimpleExtensionSource =
652 class IsolateGenesisThread : public JoinableThread {
654 IsolateGenesisThread(int count, const char* extension_names[])
655 : JoinableThread("IsolateGenesisThread"),
657 extension_names_(extension_names)
661 v8::Isolate* isolate = v8::Isolate::New();
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());
674 const char** extension_names_;
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;
686 const int kNThreads = 40;
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));
711 StartJoinAndDeleteThreads(threads);