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: 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 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 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 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: 126 explicit JoinableThread(const char* name) 127 : name_(name), 128 semaphore_(i::OS::CreateSemaphore(0)), 129 thread_(this) { 130 } 131 132 virtual ~JoinableThread() { 133 delete semaphore_; 134 } 135 136 void Start() { 137 thread_.Start(); 138 } 139 140 void Join() { 141 semaphore_->Wait(); 142 } 143 144 virtual void Run() = 0; 145 146 private: 147 class ThreadWithSemaphore : public i::Thread { 148 public: 149 explicit ThreadWithSemaphore(JoinableThread* joinable_thread) 150 : Thread(joinable_thread->name_), 151 joinable_thread_(joinable_thread) { 152 } 153 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: 175 explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate) 176 : JoinableThread("IsolateLockingThread"), 177 isolate_(isolate) { 178 } 179 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 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 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: 223 explicit IsolateNonlockingThread() 224 : JoinableThread("IsolateNonlockingThread") { 225 } 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; 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 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: 259 explicit IsolateNestedLockingThread(v8::Isolate* isolate) 260 : JoinableThread("IsolateNestedLocking"), isolate_(isolate) { 261 } 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 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: 298 SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1, 299 v8::Isolate* isolate2) 300 : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"), 301 isolate1_(isolate1), isolate2_(isolate2) { 302 } 303 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 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: 341 explicit LockIsolateAndCalculateFibSharedContextThread( 342 v8::Isolate* isolate, v8::Handle<v8::Context> context) 343 : JoinableThread("LockIsolateAndCalculateFibThread"), 344 isolate_(isolate), 345 context_(context) { 346 } 347 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: 362 explicit LockerUnlockerThread(v8::Isolate* isolate) 363 : JoinableThread("LockerUnlockerThread"), 364 isolate_(isolate) { 365 } 366 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. 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: 412 explicit LockTwiceAndUnlockThread(v8::Isolate* isolate) 413 : JoinableThread("LockTwiceAndUnlockThread"), 414 isolate_(isolate) { 415 } 416 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. 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: 465 LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1, 466 v8::Isolate* isolate2) 467 : JoinableThread("LockAndUnlockDifferentIsolatesThread"), 468 isolate1_(isolate1), 469 isolate2_(isolate2) { 470 } 471 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. 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: 531 LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context) 532 : JoinableThread("LockUnlockLockThread"), 533 isolate_(isolate), 534 context_(context) { 535 } 536 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. 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: 592 explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context) 593 : JoinableThread("LockUnlockLockDefaultIsolateThread"), 594 context_(context) { 595 } 596 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. 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 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: 667 IsolateGenesisThread(int count, const char* extension_names[]) 668 : JoinableThread("IsolateGenesisThread"), 669 count_(count), 670 extension_names_(extension_names) 671 {} 672 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 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