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/unicode-inl.h"
40 #include "src/utils.h"
41 #include "test/cctest/cctest.h"
44 using ::v8::Extension;
46 using ::v8::HandleScope;
49 using ::v8::ObjectTemplate;
50 using ::v8::Persistent;
57 // Migrating an isolate
58 class KangarooThread : public v8::base::Thread {
60 KangarooThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
61 : Thread(Options("KangarooThread")),
63 context_(isolate, context) {}
67 v8::Locker locker(isolate_);
68 v8::Isolate::Scope isolate_scope(isolate_);
69 CHECK_EQ(reinterpret_cast<v8::internal::Isolate*>(isolate_),
70 v8::internal::Isolate::Current());
71 v8::HandleScope scope(isolate_);
72 v8::Local<v8::Context> context =
73 v8::Local<v8::Context>::New(isolate_, context_);
74 v8::Context::Scope context_scope(context);
75 Local<Value> v = CompileRun("getValue()");
77 CHECK_EQ(30, static_cast<int>(v->NumberValue()));
80 v8::Locker locker(isolate_);
81 v8::Isolate::Scope isolate_scope(isolate_);
82 v8::HandleScope scope(isolate_);
83 v8::Local<v8::Context> context =
84 v8::Local<v8::Context>::New(isolate_, context_);
85 v8::Context::Scope context_scope(context);
86 Local<Value> v = CompileRun("getValue()");
88 CHECK_EQ(30, static_cast<int>(v->NumberValue()));
94 v8::Isolate* isolate_;
95 Persistent<v8::Context> context_;
99 // Migrates an isolate from one thread to another
100 TEST(KangarooIsolates) {
101 v8::Isolate* isolate = v8::Isolate::New();
102 i::SmartPointer<KangarooThread> thread1;
104 v8::Locker locker(isolate);
105 v8::Isolate::Scope isolate_scope(isolate);
106 v8::HandleScope handle_scope(isolate);
107 v8::Local<v8::Context> context = v8::Context::New(isolate);
108 v8::Context::Scope context_scope(context);
109 CHECK_EQ(reinterpret_cast<v8::internal::Isolate*>(isolate),
110 v8::internal::Isolate::Current());
111 CompileRun("function getValue() { return 30; }");
112 thread1.Reset(new KangarooThread(isolate, context));
119 static void CalcFibAndCheck() {
120 Local<Value> v = CompileRun("function fib(n) {"
121 " if (n <= 2) return 1;"
122 " return fib(n-1) + fib(n-2);"
125 CHECK(v->IsNumber());
126 CHECK_EQ(55, static_cast<int>(v->NumberValue()));
129 class JoinableThread {
131 explicit JoinableThread(const char* name)
137 virtual ~JoinableThread() {}
148 virtual void Run() = 0;
151 class ThreadWithSemaphore : public v8::base::Thread {
153 explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
154 : Thread(Options(joinable_thread->name_)),
155 joinable_thread_(joinable_thread) {}
158 joinable_thread_->Run();
159 joinable_thread_->semaphore_.Signal();
163 JoinableThread* joinable_thread_;
167 v8::base::Semaphore semaphore_;
168 ThreadWithSemaphore thread_;
170 friend class ThreadWithSemaphore;
172 DISALLOW_COPY_AND_ASSIGN(JoinableThread);
176 class IsolateLockingThreadWithLocalContext : public JoinableThread {
178 explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
179 : JoinableThread("IsolateLockingThread"),
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(reinterpret_cast<v8::internal::Isolate*>(isolate_),
189 v8::internal::Isolate::Current());
193 v8::Isolate* isolate_;
197 static void StartJoinAndDeleteThreads(const i::List<JoinableThread*>& threads) {
198 for (int i = 0; i < threads.length(); i++) {
201 for (int i = 0; i < threads.length(); i++) {
204 for (int i = 0; i < threads.length(); i++) {
210 // Run many threads all locking on the same isolate
211 TEST(IsolateLockingStress) {
212 #if V8_TARGET_ARCH_MIPS
213 const int kNThreads = 50;
215 const int kNThreads = 100;
217 i::List<JoinableThread*> threads(kNThreads);
218 v8::Isolate* isolate = v8::Isolate::New();
219 for (int i = 0; i < kNThreads; i++) {
220 threads.Add(new IsolateLockingThreadWithLocalContext(isolate));
222 StartJoinAndDeleteThreads(threads);
227 class IsolateNestedLockingThread : public JoinableThread {
229 explicit IsolateNestedLockingThread(v8::Isolate* isolate)
230 : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
233 v8::Locker lock(isolate_);
234 v8::Isolate::Scope isolate_scope(isolate_);
235 v8::HandleScope handle_scope(isolate_);
236 LocalContext local_context(isolate_);
238 v8::Locker another_lock(isolate_);
242 v8::Locker another_lock(isolate_);
247 v8::Isolate* isolate_;
251 // Run many threads with nested locks
252 TEST(IsolateNestedLocking) {
253 #if V8_TARGET_ARCH_MIPS
254 const int kNThreads = 50;
256 const int kNThreads = 100;
258 v8::Isolate* isolate = v8::Isolate::New();
259 i::List<JoinableThread*> threads(kNThreads);
260 for (int i = 0; i < kNThreads; i++) {
261 threads.Add(new IsolateNestedLockingThread(isolate));
263 StartJoinAndDeleteThreads(threads);
268 class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread {
270 SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
271 v8::Isolate* isolate2)
272 : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
273 isolate1_(isolate1), isolate2_(isolate2) {
277 v8::Locker lock(isolate1_);
278 v8::Isolate::Scope isolate_scope(isolate1_);
279 v8::HandleScope handle_scope(isolate1_);
280 LocalContext local_context(isolate1_);
282 IsolateLockingThreadWithLocalContext threadB(isolate2_);
288 v8::Isolate* isolate1_;
289 v8::Isolate* isolate2_;
293 // Run parallel threads that lock and access different isolates in parallel
294 TEST(SeparateIsolatesLocksNonexclusive) {
295 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
296 const int kNThreads = 50;
298 const int kNThreads = 100;
300 v8::Isolate* isolate1 = v8::Isolate::New();
301 v8::Isolate* isolate2 = v8::Isolate::New();
302 i::List<JoinableThread*> threads(kNThreads);
303 for (int i = 0; i < kNThreads; i++) {
304 threads.Add(new SeparateIsolatesLocksNonexclusiveThread(isolate1,
307 StartJoinAndDeleteThreads(threads);
312 class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread {
314 explicit LockIsolateAndCalculateFibSharedContextThread(
315 v8::Isolate* isolate, v8::Handle<v8::Context> context)
316 : JoinableThread("LockIsolateAndCalculateFibThread"),
318 context_(isolate, context) {
322 v8::Locker lock(isolate_);
323 v8::Isolate::Scope isolate_scope(isolate_);
324 HandleScope handle_scope(isolate_);
325 v8::Local<v8::Context> context =
326 v8::Local<v8::Context>::New(isolate_, context_);
327 v8::Context::Scope context_scope(context);
331 v8::Isolate* isolate_;
332 Persistent<v8::Context> context_;
335 class LockerUnlockerThread : public JoinableThread {
337 explicit LockerUnlockerThread(v8::Isolate* isolate)
338 : JoinableThread("LockerUnlockerThread"),
343 v8::Locker lock(isolate_);
344 v8::Isolate::Scope isolate_scope(isolate_);
345 v8::HandleScope handle_scope(isolate_);
346 v8::Local<v8::Context> context = v8::Context::New(isolate_);
348 v8::Context::Scope context_scope(context);
352 LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
354 v8::Unlocker unlocker(isolate_);
360 v8::Context::Scope context_scope(context);
366 v8::Isolate* isolate_;
370 // Use unlocker inside of a Locker, multiple threads.
371 TEST(LockerUnlocker) {
372 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
373 const int kNThreads = 50;
375 const int kNThreads = 100;
377 i::List<JoinableThread*> threads(kNThreads);
378 v8::Isolate* isolate = v8::Isolate::New();
379 for (int i = 0; i < kNThreads; i++) {
380 threads.Add(new LockerUnlockerThread(isolate));
382 StartJoinAndDeleteThreads(threads);
386 class LockTwiceAndUnlockThread : public JoinableThread {
388 explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
389 : JoinableThread("LockTwiceAndUnlockThread"),
394 v8::Locker lock(isolate_);
395 v8::Isolate::Scope isolate_scope(isolate_);
396 v8::HandleScope handle_scope(isolate_);
397 v8::Local<v8::Context> context = v8::Context::New(isolate_);
399 v8::Context::Scope context_scope(context);
403 v8::Locker second_lock(isolate_);
405 LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
407 v8::Unlocker unlocker(isolate_);
414 v8::Context::Scope context_scope(context);
420 v8::Isolate* isolate_;
424 // Use Unlocker inside two Lockers.
425 TEST(LockTwiceAndUnlock) {
426 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
427 const int kNThreads = 50;
429 const int kNThreads = 100;
431 i::List<JoinableThread*> threads(kNThreads);
432 v8::Isolate* isolate = v8::Isolate::New();
433 for (int i = 0; i < kNThreads; i++) {
434 threads.Add(new LockTwiceAndUnlockThread(isolate));
436 StartJoinAndDeleteThreads(threads);
440 class LockAndUnlockDifferentIsolatesThread : public JoinableThread {
442 LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
443 v8::Isolate* isolate2)
444 : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
446 isolate2_(isolate2) {
450 i::SmartPointer<LockIsolateAndCalculateFibSharedContextThread> thread;
451 v8::Locker lock1(isolate1_);
452 CHECK(v8::Locker::IsLocked(isolate1_));
453 CHECK(!v8::Locker::IsLocked(isolate2_));
455 v8::Isolate::Scope isolate_scope(isolate1_);
456 v8::HandleScope handle_scope(isolate1_);
457 v8::Handle<v8::Context> context1 = v8::Context::New(isolate1_);
459 v8::Context::Scope context_scope(context1);
462 thread.Reset(new LockIsolateAndCalculateFibSharedContextThread(
463 isolate1_, context1));
465 v8::Locker lock2(isolate2_);
466 CHECK(v8::Locker::IsLocked(isolate1_));
467 CHECK(v8::Locker::IsLocked(isolate2_));
469 v8::Isolate::Scope isolate_scope(isolate2_);
470 v8::HandleScope handle_scope(isolate2_);
471 v8::Handle<v8::Context> context2 = v8::Context::New(isolate2_);
473 v8::Context::Scope context_scope(context2);
476 v8::Unlocker unlock1(isolate1_);
477 CHECK(!v8::Locker::IsLocked(isolate1_));
478 CHECK(v8::Locker::IsLocked(isolate2_));
479 v8::Context::Scope context_scope(context2);
487 v8::Isolate* isolate1_;
488 v8::Isolate* isolate2_;
492 // Lock two isolates and unlock one of them.
493 TEST(LockAndUnlockDifferentIsolates) {
494 v8::Isolate* isolate1 = v8::Isolate::New();
495 v8::Isolate* isolate2 = v8::Isolate::New();
496 LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2);
503 class LockUnlockLockThread : public JoinableThread {
505 LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
506 : JoinableThread("LockUnlockLockThread"),
508 context_(isolate, context) {
512 v8::Locker lock1(isolate_);
513 CHECK(v8::Locker::IsLocked(isolate_));
514 CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
516 v8::Isolate::Scope isolate_scope(isolate_);
517 v8::HandleScope handle_scope(isolate_);
518 v8::Local<v8::Context> context =
519 v8::Local<v8::Context>::New(isolate_, context_);
520 v8::Context::Scope context_scope(context);
524 v8::Unlocker unlock1(isolate_);
525 CHECK(!v8::Locker::IsLocked(isolate_));
526 CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
528 v8::Locker lock2(isolate_);
529 v8::Isolate::Scope isolate_scope(isolate_);
530 v8::HandleScope handle_scope(isolate_);
531 CHECK(v8::Locker::IsLocked(isolate_));
532 CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
533 v8::Local<v8::Context> context =
534 v8::Local<v8::Context>::New(isolate_, context_);
535 v8::Context::Scope context_scope(context);
542 v8::Isolate* isolate_;
543 v8::Persistent<v8::Context> context_;
547 // Locker inside an Unlocker inside a Locker.
548 TEST(LockUnlockLockMultithreaded) {
549 #if V8_TARGET_ARCH_MIPS
550 const int kNThreads = 50;
552 const int kNThreads = 100;
554 v8::Isolate* isolate = v8::Isolate::New();
555 i::List<JoinableThread*> threads(kNThreads);
557 v8::Locker locker_(isolate);
558 v8::Isolate::Scope isolate_scope(isolate);
559 v8::HandleScope handle_scope(isolate);
560 v8::Handle<v8::Context> context = v8::Context::New(isolate);
561 for (int i = 0; i < kNThreads; i++) {
562 threads.Add(new LockUnlockLockThread(
566 StartJoinAndDeleteThreads(threads);
570 class LockUnlockLockDefaultIsolateThread : public JoinableThread {
572 explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context)
573 : JoinableThread("LockUnlockLockDefaultIsolateThread"),
574 context_(CcTest::isolate(), context) {}
577 v8::Locker lock1(CcTest::isolate());
579 v8::Isolate::Scope isolate_scope(CcTest::isolate());
580 v8::HandleScope handle_scope(CcTest::isolate());
581 v8::Local<v8::Context> context =
582 v8::Local<v8::Context>::New(CcTest::isolate(), context_);
583 v8::Context::Scope context_scope(context);
587 v8::Unlocker unlock1(CcTest::isolate());
589 v8::Locker lock2(CcTest::isolate());
590 v8::Isolate::Scope isolate_scope(CcTest::isolate());
591 v8::HandleScope handle_scope(CcTest::isolate());
592 v8::Local<v8::Context> context =
593 v8::Local<v8::Context>::New(CcTest::isolate(), context_);
594 v8::Context::Scope context_scope(context);
601 v8::Persistent<v8::Context> context_;
605 // Locker inside an Unlocker inside a Locker for default isolate.
606 TEST(LockUnlockLockDefaultIsolateMultithreaded) {
607 #if V8_TARGET_ARCH_MIPS
608 const int kNThreads = 50;
610 const int kNThreads = 100;
612 Local<v8::Context> context;
613 i::List<JoinableThread*> threads(kNThreads);
615 v8::Locker locker_(CcTest::isolate());
616 v8::Isolate::Scope isolate_scope(CcTest::isolate());
617 v8::HandleScope handle_scope(CcTest::isolate());
618 context = v8::Context::New(CcTest::isolate());
619 for (int i = 0; i < kNThreads; i++) {
620 threads.Add(new LockUnlockLockDefaultIsolateThread(context));
623 StartJoinAndDeleteThreads(threads);
628 for (int i = 0; i < 10; i++) {
629 v8::Isolate* isolate = v8::Isolate::New();
631 v8::Locker lock(isolate);
632 v8::Isolate::Scope isolate_scope(isolate);
633 v8::HandleScope handle_scope(isolate);
634 v8::Handle<Context> context = v8::Context::New(isolate);
635 v8::Context::Scope context_scope(context);
636 v8::Handle<String> source = v8::String::NewFromUtf8(isolate, "1+1");
637 v8::Handle<Script> script = v8::Script::Compile(source);
638 v8::Handle<Value> result = script->Run();
639 v8::String::Utf8Value utf8(result);
646 static const char* kSimpleExtensionSource =
651 class IsolateGenesisThread : public JoinableThread {
653 IsolateGenesisThread(int count, const char* extension_names[])
654 : JoinableThread("IsolateGenesisThread"),
656 extension_names_(extension_names)
660 v8::Isolate* isolate = v8::Isolate::New();
662 v8::Isolate::Scope isolate_scope(isolate);
663 CHECK(!i::Isolate::Current()->has_installed_extensions());
664 v8::ExtensionConfiguration extensions(count_, extension_names_);
665 v8::HandleScope handle_scope(isolate);
666 v8::Context::New(isolate, &extensions);
667 CHECK(i::Isolate::Current()->has_installed_extensions());
673 const char** extension_names_;
677 // Test installing extensions in separate isolates concurrently.
678 // http://code.google.com/p/v8/issues/detail?id=1821
679 TEST(ExtensionsRegistration) {
680 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
681 const int kNThreads = 10;
682 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
683 const int kNThreads = 4;
685 const int kNThreads = 40;
687 v8::RegisterExtension(new v8::Extension("test0",
688 kSimpleExtensionSource));
689 v8::RegisterExtension(new v8::Extension("test1",
690 kSimpleExtensionSource));
691 v8::RegisterExtension(new v8::Extension("test2",
692 kSimpleExtensionSource));
693 v8::RegisterExtension(new v8::Extension("test3",
694 kSimpleExtensionSource));
695 v8::RegisterExtension(new v8::Extension("test4",
696 kSimpleExtensionSource));
697 v8::RegisterExtension(new v8::Extension("test5",
698 kSimpleExtensionSource));
699 v8::RegisterExtension(new v8::Extension("test6",
700 kSimpleExtensionSource));
701 v8::RegisterExtension(new v8::Extension("test7",
702 kSimpleExtensionSource));
703 const char* extension_names[] = { "test0", "test1",
704 "test2", "test3", "test4",
705 "test5", "test6", "test7" };
706 i::List<JoinableThread*> threads(kNThreads);
707 for (int i = 0; i < kNThreads; i++) {
708 threads.Add(new IsolateGenesisThread(8, extension_names));
710 StartJoinAndDeleteThreads(threads);