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