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