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