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 44using ::v8::Context; 45using ::v8::Extension; 46using ::v8::Function; 47using ::v8::HandleScope; 48using ::v8::Local; 49using ::v8::Object; 50using ::v8::ObjectTemplate; 51using ::v8::Persistent; 52using ::v8::Script; 53using ::v8::String; 54using ::v8::Value; 55using ::v8::V8; 56 57 58// Migrating an isolate 59class KangarooThread : public v8::internal::Thread { 60 public: 61 KangarooThread(v8::Isolate* isolate, v8::Handle<v8::Context> context) 62 : Thread("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 100TEST(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 118static 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 128class 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 i::Thread { 150 public: 151 explicit ThreadWithSemaphore(JoinableThread* joinable_thread) 152 : Thread(joinable_thread->name_), 153 joinable_thread_(joinable_thread) { 154 } 155 156 virtual void Run() { 157 joinable_thread_->Run(); 158 joinable_thread_->semaphore_.Signal(); 159 } 160 161 private: 162 JoinableThread* joinable_thread_; 163 }; 164 165 const char* name_; 166 i::Semaphore semaphore_; 167 ThreadWithSemaphore thread_; 168 169 friend class ThreadWithSemaphore; 170 171 DISALLOW_COPY_AND_ASSIGN(JoinableThread); 172}; 173 174 175class IsolateLockingThreadWithLocalContext : public JoinableThread { 176 public: 177 explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate) 178 : JoinableThread("IsolateLockingThread"), 179 isolate_(isolate) { 180 } 181 182 virtual void Run() { 183 v8::Locker locker(isolate_); 184 v8::Isolate::Scope isolate_scope(isolate_); 185 v8::HandleScope handle_scope(isolate_); 186 LocalContext local_context(isolate_); 187 CHECK_EQ(isolate_, v8::internal::Isolate::Current()); 188 CalcFibAndCheck(); 189 } 190 private: 191 v8::Isolate* isolate_; 192}; 193 194 195static void StartJoinAndDeleteThreads(const i::List<JoinableThread*>& threads) { 196 for (int i = 0; i < threads.length(); i++) { 197 threads[i]->Start(); 198 } 199 for (int i = 0; i < threads.length(); i++) { 200 threads[i]->Join(); 201 } 202 for (int i = 0; i < threads.length(); i++) { 203 delete threads[i]; 204 } 205} 206 207 208// Run many threads all locking on the same isolate 209TEST(IsolateLockingStress) { 210#if V8_TARGET_ARCH_MIPS 211 const int kNThreads = 50; 212#else 213 const int kNThreads = 100; 214#endif 215 i::List<JoinableThread*> threads(kNThreads); 216 v8::Isolate* isolate = v8::Isolate::New(); 217 for (int i = 0; i < kNThreads; i++) { 218 threads.Add(new IsolateLockingThreadWithLocalContext(isolate)); 219 } 220 StartJoinAndDeleteThreads(threads); 221 isolate->Dispose(); 222} 223 224class IsolateNonlockingThread : public JoinableThread { 225 public: 226 explicit IsolateNonlockingThread() 227 : JoinableThread("IsolateNonlockingThread") { 228 } 229 230 virtual void Run() { 231 v8::Isolate* isolate = v8::Isolate::New(); 232 { 233 v8::Isolate::Scope isolate_scope(isolate); 234 v8::HandleScope handle_scope(isolate); 235 v8::Handle<v8::Context> context = v8::Context::New(isolate); 236 v8::Context::Scope context_scope(context); 237 CHECK_EQ(isolate, v8::internal::Isolate::Current()); 238 CalcFibAndCheck(); 239 } 240 isolate->Dispose(); 241 } 242 private: 243}; 244 245 246// Run many threads each accessing its own isolate without locking 247TEST(MultithreadedParallelIsolates) { 248#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS 249 const int kNThreads = 10; 250#else 251 const int kNThreads = 50; 252#endif 253 i::List<JoinableThread*> threads(kNThreads); 254 for (int i = 0; i < kNThreads; i++) { 255 threads.Add(new IsolateNonlockingThread()); 256 } 257 StartJoinAndDeleteThreads(threads); 258} 259 260 261class IsolateNestedLockingThread : public JoinableThread { 262 public: 263 explicit IsolateNestedLockingThread(v8::Isolate* isolate) 264 : JoinableThread("IsolateNestedLocking"), isolate_(isolate) { 265 } 266 virtual void Run() { 267 v8::Locker lock(isolate_); 268 v8::Isolate::Scope isolate_scope(isolate_); 269 v8::HandleScope handle_scope(isolate_); 270 LocalContext local_context(isolate_); 271 { 272 v8::Locker another_lock(isolate_); 273 CalcFibAndCheck(); 274 } 275 { 276 v8::Locker another_lock(isolate_); 277 CalcFibAndCheck(); 278 } 279 } 280 private: 281 v8::Isolate* isolate_; 282}; 283 284 285// Run many threads with nested locks 286TEST(IsolateNestedLocking) { 287#if V8_TARGET_ARCH_MIPS 288 const int kNThreads = 50; 289#else 290 const int kNThreads = 100; 291#endif 292 v8::Isolate* isolate = v8::Isolate::New(); 293 i::List<JoinableThread*> threads(kNThreads); 294 for (int i = 0; i < kNThreads; i++) { 295 threads.Add(new IsolateNestedLockingThread(isolate)); 296 } 297 StartJoinAndDeleteThreads(threads); 298 isolate->Dispose(); 299} 300 301 302class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread { 303 public: 304 SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1, 305 v8::Isolate* isolate2) 306 : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"), 307 isolate1_(isolate1), isolate2_(isolate2) { 308 } 309 310 virtual void Run() { 311 v8::Locker lock(isolate1_); 312 v8::Isolate::Scope isolate_scope(isolate1_); 313 v8::HandleScope handle_scope(isolate1_); 314 LocalContext local_context(isolate1_); 315 316 IsolateLockingThreadWithLocalContext threadB(isolate2_); 317 threadB.Start(); 318 CalcFibAndCheck(); 319 threadB.Join(); 320 } 321 private: 322 v8::Isolate* isolate1_; 323 v8::Isolate* isolate2_; 324}; 325 326 327// Run parallel threads that lock and access different isolates in parallel 328TEST(SeparateIsolatesLocksNonexclusive) { 329#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS 330 const int kNThreads = 50; 331#else 332 const int kNThreads = 100; 333#endif 334 v8::Isolate* isolate1 = v8::Isolate::New(); 335 v8::Isolate* isolate2 = v8::Isolate::New(); 336 i::List<JoinableThread*> threads(kNThreads); 337 for (int i = 0; i < kNThreads; i++) { 338 threads.Add(new SeparateIsolatesLocksNonexclusiveThread(isolate1, 339 isolate2)); 340 } 341 StartJoinAndDeleteThreads(threads); 342 isolate2->Dispose(); 343 isolate1->Dispose(); 344} 345 346class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread { 347 public: 348 explicit LockIsolateAndCalculateFibSharedContextThread( 349 v8::Isolate* isolate, v8::Handle<v8::Context> context) 350 : JoinableThread("LockIsolateAndCalculateFibThread"), 351 isolate_(isolate), 352 context_(isolate, context) { 353 } 354 355 virtual void Run() { 356 v8::Locker lock(isolate_); 357 v8::Isolate::Scope isolate_scope(isolate_); 358 HandleScope handle_scope(isolate_); 359 v8::Local<v8::Context> context = 360 v8::Local<v8::Context>::New(isolate_, context_); 361 v8::Context::Scope context_scope(context); 362 CalcFibAndCheck(); 363 } 364 private: 365 v8::Isolate* isolate_; 366 Persistent<v8::Context> context_; 367}; 368 369class LockerUnlockerThread : public JoinableThread { 370 public: 371 explicit LockerUnlockerThread(v8::Isolate* isolate) 372 : JoinableThread("LockerUnlockerThread"), 373 isolate_(isolate) { 374 } 375 376 virtual void Run() { 377 v8::Locker lock(isolate_); 378 v8::Isolate::Scope isolate_scope(isolate_); 379 v8::HandleScope handle_scope(isolate_); 380 v8::Local<v8::Context> context = v8::Context::New(isolate_); 381 { 382 v8::Context::Scope context_scope(context); 383 CalcFibAndCheck(); 384 } 385 { 386 LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context); 387 isolate_->Exit(); 388 v8::Unlocker unlocker(isolate_); 389 thread.Start(); 390 thread.Join(); 391 } 392 isolate_->Enter(); 393 { 394 v8::Context::Scope context_scope(context); 395 CalcFibAndCheck(); 396 } 397 } 398 399 private: 400 v8::Isolate* isolate_; 401}; 402 403 404// Use unlocker inside of a Locker, multiple threads. 405TEST(LockerUnlocker) { 406#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS 407 const int kNThreads = 50; 408#else 409 const int kNThreads = 100; 410#endif 411 i::List<JoinableThread*> threads(kNThreads); 412 v8::Isolate* isolate = v8::Isolate::New(); 413 for (int i = 0; i < kNThreads; i++) { 414 threads.Add(new LockerUnlockerThread(isolate)); 415 } 416 StartJoinAndDeleteThreads(threads); 417 isolate->Dispose(); 418} 419 420class LockTwiceAndUnlockThread : public JoinableThread { 421 public: 422 explicit LockTwiceAndUnlockThread(v8::Isolate* isolate) 423 : JoinableThread("LockTwiceAndUnlockThread"), 424 isolate_(isolate) { 425 } 426 427 virtual void Run() { 428 v8::Locker lock(isolate_); 429 v8::Isolate::Scope isolate_scope(isolate_); 430 v8::HandleScope handle_scope(isolate_); 431 v8::Local<v8::Context> context = v8::Context::New(isolate_); 432 { 433 v8::Context::Scope context_scope(context); 434 CalcFibAndCheck(); 435 } 436 { 437 v8::Locker second_lock(isolate_); 438 { 439 LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context); 440 isolate_->Exit(); 441 v8::Unlocker unlocker(isolate_); 442 thread.Start(); 443 thread.Join(); 444 } 445 } 446 isolate_->Enter(); 447 { 448 v8::Context::Scope context_scope(context); 449 CalcFibAndCheck(); 450 } 451 } 452 453 private: 454 v8::Isolate* isolate_; 455}; 456 457 458// Use Unlocker inside two Lockers. 459TEST(LockTwiceAndUnlock) { 460#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS 461 const int kNThreads = 50; 462#else 463 const int kNThreads = 100; 464#endif 465 i::List<JoinableThread*> threads(kNThreads); 466 v8::Isolate* isolate = v8::Isolate::New(); 467 for (int i = 0; i < kNThreads; i++) { 468 threads.Add(new LockTwiceAndUnlockThread(isolate)); 469 } 470 StartJoinAndDeleteThreads(threads); 471 isolate->Dispose(); 472} 473 474class LockAndUnlockDifferentIsolatesThread : public JoinableThread { 475 public: 476 LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1, 477 v8::Isolate* isolate2) 478 : JoinableThread("LockAndUnlockDifferentIsolatesThread"), 479 isolate1_(isolate1), 480 isolate2_(isolate2) { 481 } 482 483 virtual void Run() { 484 i::SmartPointer<LockIsolateAndCalculateFibSharedContextThread> thread; 485 v8::Locker lock1(isolate1_); 486 CHECK(v8::Locker::IsLocked(isolate1_)); 487 CHECK(!v8::Locker::IsLocked(isolate2_)); 488 { 489 v8::Isolate::Scope isolate_scope(isolate1_); 490 v8::HandleScope handle_scope(isolate1_); 491 v8::Handle<v8::Context> context1 = v8::Context::New(isolate1_); 492 { 493 v8::Context::Scope context_scope(context1); 494 CalcFibAndCheck(); 495 } 496 thread.Reset(new LockIsolateAndCalculateFibSharedContextThread( 497 isolate1_, context1)); 498 } 499 v8::Locker lock2(isolate2_); 500 CHECK(v8::Locker::IsLocked(isolate1_)); 501 CHECK(v8::Locker::IsLocked(isolate2_)); 502 { 503 v8::Isolate::Scope isolate_scope(isolate2_); 504 v8::HandleScope handle_scope(isolate2_); 505 v8::Handle<v8::Context> context2 = v8::Context::New(isolate2_); 506 { 507 v8::Context::Scope context_scope(context2); 508 CalcFibAndCheck(); 509 } 510 v8::Unlocker unlock1(isolate1_); 511 CHECK(!v8::Locker::IsLocked(isolate1_)); 512 CHECK(v8::Locker::IsLocked(isolate2_)); 513 v8::Context::Scope context_scope(context2); 514 thread->Start(); 515 CalcFibAndCheck(); 516 thread->Join(); 517 } 518 } 519 520 private: 521 v8::Isolate* isolate1_; 522 v8::Isolate* isolate2_; 523}; 524 525 526// Lock two isolates and unlock one of them. 527TEST(LockAndUnlockDifferentIsolates) { 528 v8::Isolate* isolate1 = v8::Isolate::New(); 529 v8::Isolate* isolate2 = v8::Isolate::New(); 530 LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2); 531 thread.Start(); 532 thread.Join(); 533 isolate2->Dispose(); 534 isolate1->Dispose(); 535} 536 537class LockUnlockLockThread : public JoinableThread { 538 public: 539 LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context) 540 : JoinableThread("LockUnlockLockThread"), 541 isolate_(isolate), 542 context_(isolate, context) { 543 } 544 545 virtual void Run() { 546 v8::Locker lock1(isolate_); 547 CHECK(v8::Locker::IsLocked(isolate_)); 548 CHECK(!v8::Locker::IsLocked(CcTest::isolate())); 549 { 550 v8::Isolate::Scope isolate_scope(isolate_); 551 v8::HandleScope handle_scope(isolate_); 552 v8::Local<v8::Context> context = 553 v8::Local<v8::Context>::New(isolate_, context_); 554 v8::Context::Scope context_scope(context); 555 CalcFibAndCheck(); 556 } 557 { 558 v8::Unlocker unlock1(isolate_); 559 CHECK(!v8::Locker::IsLocked(isolate_)); 560 CHECK(!v8::Locker::IsLocked(CcTest::isolate())); 561 { 562 v8::Locker lock2(isolate_); 563 v8::Isolate::Scope isolate_scope(isolate_); 564 v8::HandleScope handle_scope(isolate_); 565 CHECK(v8::Locker::IsLocked(isolate_)); 566 CHECK(!v8::Locker::IsLocked(CcTest::isolate())); 567 v8::Local<v8::Context> context = 568 v8::Local<v8::Context>::New(isolate_, context_); 569 v8::Context::Scope context_scope(context); 570 CalcFibAndCheck(); 571 } 572 } 573 } 574 575 private: 576 v8::Isolate* isolate_; 577 v8::Persistent<v8::Context> context_; 578}; 579 580 581// Locker inside an Unlocker inside a Locker. 582TEST(LockUnlockLockMultithreaded) { 583#if V8_TARGET_ARCH_MIPS 584 const int kNThreads = 50; 585#else 586 const int kNThreads = 100; 587#endif 588 v8::Isolate* isolate = v8::Isolate::New(); 589 i::List<JoinableThread*> threads(kNThreads); 590 { 591 v8::Locker locker_(isolate); 592 v8::Isolate::Scope isolate_scope(isolate); 593 v8::HandleScope handle_scope(isolate); 594 v8::Handle<v8::Context> context = v8::Context::New(isolate); 595 for (int i = 0; i < kNThreads; i++) { 596 threads.Add(new LockUnlockLockThread( 597 isolate, context)); 598 } 599 } 600 StartJoinAndDeleteThreads(threads); 601 isolate->Dispose(); 602} 603 604class LockUnlockLockDefaultIsolateThread : public JoinableThread { 605 public: 606 explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context) 607 : JoinableThread("LockUnlockLockDefaultIsolateThread"), 608 context_(CcTest::isolate(), context) {} 609 610 virtual void Run() { 611 v8::Locker lock1(CcTest::isolate()); 612 { 613 v8::Isolate::Scope isolate_scope(CcTest::isolate()); 614 v8::HandleScope handle_scope(CcTest::isolate()); 615 v8::Local<v8::Context> context = 616 v8::Local<v8::Context>::New(CcTest::isolate(), context_); 617 v8::Context::Scope context_scope(context); 618 CalcFibAndCheck(); 619 } 620 { 621 v8::Unlocker unlock1(CcTest::isolate()); 622 { 623 v8::Locker lock2(CcTest::isolate()); 624 v8::Isolate::Scope isolate_scope(CcTest::isolate()); 625 v8::HandleScope handle_scope(CcTest::isolate()); 626 v8::Local<v8::Context> context = 627 v8::Local<v8::Context>::New(CcTest::isolate(), context_); 628 v8::Context::Scope context_scope(context); 629 CalcFibAndCheck(); 630 } 631 } 632 } 633 634 private: 635 v8::Persistent<v8::Context> context_; 636}; 637 638 639// Locker inside an Unlocker inside a Locker for default isolate. 640TEST(LockUnlockLockDefaultIsolateMultithreaded) { 641#if V8_TARGET_ARCH_MIPS 642 const int kNThreads = 50; 643#else 644 const int kNThreads = 100; 645#endif 646 Local<v8::Context> context; 647 i::List<JoinableThread*> threads(kNThreads); 648 { 649 v8::Locker locker_(CcTest::isolate()); 650 v8::Isolate::Scope isolate_scope(CcTest::isolate()); 651 v8::HandleScope handle_scope(CcTest::isolate()); 652 context = v8::Context::New(CcTest::isolate()); 653 for (int i = 0; i < kNThreads; i++) { 654 threads.Add(new LockUnlockLockDefaultIsolateThread(context)); 655 } 656 } 657 StartJoinAndDeleteThreads(threads); 658} 659 660 661TEST(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::NewFromUtf8(isolate, "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 680static const char* kSimpleExtensionSource = 681 "(function Foo() {" 682 " return 4;" 683 "})() "; 684 685class 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 713TEST(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