test-lockers.cc 22.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Copyright 2007-2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <limits.h>

30 31
#include <memory>

32
#include "src/v8.h"
33

34
#include "src/api.h"
35
#include "src/base/platform/platform.h"
36 37 38
#include "src/compilation-cache.h"
#include "src/execution.h"
#include "src/isolate.h"
39
#include "src/objects-inl.h"
40 41 42
#include "src/unicode-inl.h"
#include "src/utils.h"
#include "test/cctest/cctest.h"
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

using ::v8::Context;
using ::v8::Extension;
using ::v8::Function;
using ::v8::HandleScope;
using ::v8::Local;
using ::v8::Object;
using ::v8::ObjectTemplate;
using ::v8::Persistent;
using ::v8::Script;
using ::v8::String;
using ::v8::Value;
using ::v8::V8;


// Migrating an isolate
59
class KangarooThread : public v8::base::Thread {
60
 public:
61
  KangarooThread(v8::Isolate* isolate, v8::Local<v8::Context> context)
62
      : Thread(Options("KangarooThread")),
63 64
        isolate_(isolate),
        context_(isolate, context) {}
65 66 67 68 69

  void Run() {
    {
      v8::Locker locker(isolate_);
      v8::Isolate::Scope isolate_scope(isolate_);
70
      CHECK_EQ(isolate_, v8::Isolate::GetCurrent());
71
      v8::HandleScope scope(isolate_);
72 73 74
      v8::Local<v8::Context> context =
          v8::Local<v8::Context>::New(isolate_, context_);
      v8::Context::Scope context_scope(context);
75 76
      Local<Value> v = CompileRun("getValue()");
      CHECK(v->IsNumber());
77
      CHECK_EQ(30, static_cast<int>(v->NumberValue(context).FromJust()));
78 79 80 81
    }
    {
      v8::Locker locker(isolate_);
      v8::Isolate::Scope isolate_scope(isolate_);
82
      v8::HandleScope scope(isolate_);
83 84 85
      v8::Local<v8::Context> context =
          v8::Local<v8::Context>::New(isolate_, context_);
      v8::Context::Scope context_scope(context);
86 87
      Local<Value> v = CompileRun("getValue()");
      CHECK(v->IsNumber());
88
      CHECK_EQ(30, static_cast<int>(v->NumberValue(context).FromJust()));
89 90 91 92 93 94 95 96 97
    }
    isolate_->Dispose();
  }

 private:
  v8::Isolate* isolate_;
  Persistent<v8::Context> context_;
};

98

99 100
// Migrates an isolate from one thread to another
TEST(KangarooIsolates) {
101 102 103
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate = v8::Isolate::New(create_params);
104
  std::unique_ptr<KangarooThread> thread1;
105 106 107
  {
    v8::Locker locker(isolate);
    v8::Isolate::Scope isolate_scope(isolate);
108
    v8::HandleScope handle_scope(isolate);
109
    v8::Local<v8::Context> context = v8::Context::New(isolate);
110
    v8::Context::Scope context_scope(context);
111
    CHECK_EQ(isolate, v8::Isolate::GetCurrent());
112
    CompileRun("function getValue() { return 30; }");
113
    thread1.reset(new KangarooThread(isolate, context));
114
  }
115 116
  thread1->Start();
  thread1->Join();
117 118
}

119

120
static void CalcFibAndCheck(v8::Local<v8::Context> context) {
121 122 123 124 125 126
  Local<Value> v = CompileRun("function fib(n) {"
                              "  if (n <= 2) return 1;"
                              "  return fib(n-1) + fib(n-2);"
                              "}"
                              "fib(10)");
  CHECK(v->IsNumber());
127
  CHECK_EQ(55, static_cast<int>(v->NumberValue(context).FromJust()));
128 129 130 131 132 133
}

class JoinableThread {
 public:
  explicit JoinableThread(const char* name)
    : name_(name),
134
      semaphore_(0),
135 136 137
      thread_(this) {
  }

138
  virtual ~JoinableThread() {}
139 140 141 142 143 144

  void Start() {
    thread_.Start();
  }

  void Join() {
145
    semaphore_.Wait();
146
    thread_.Join();
147 148 149
  }

  virtual void Run() = 0;
150

151
 private:
152
  class ThreadWithSemaphore : public v8::base::Thread {
153
   public:
154
    explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
155 156
        : Thread(Options(joinable_thread->name_)),
          joinable_thread_(joinable_thread) {}
157 158 159

    virtual void Run() {
      joinable_thread_->Run();
160
      joinable_thread_->semaphore_.Signal();
161 162 163 164 165 166 167
    }

   private:
    JoinableThread* joinable_thread_;
  };

  const char* name_;
168
  v8::base::Semaphore semaphore_;
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
  ThreadWithSemaphore thread_;

  friend class ThreadWithSemaphore;

  DISALLOW_COPY_AND_ASSIGN(JoinableThread);
};


class IsolateLockingThreadWithLocalContext : public JoinableThread {
 public:
  explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
    : JoinableThread("IsolateLockingThread"),
      isolate_(isolate) {
  }

  virtual void Run() {
    v8::Locker locker(isolate_);
    v8::Isolate::Scope isolate_scope(isolate_);
187
    v8::HandleScope handle_scope(isolate_);
188
    LocalContext local_context(isolate_);
189
    CHECK_EQ(isolate_, v8::Isolate::GetCurrent());
190
    CalcFibAndCheck(local_context.local());
191 192 193 194 195
  }
 private:
  v8::Isolate* isolate_;
};

196

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
static void StartJoinAndDeleteThreads(const i::List<JoinableThread*>& threads) {
  for (int i = 0; i < threads.length(); i++) {
    threads[i]->Start();
  }
  for (int i = 0; i < threads.length(); i++) {
    threads[i]->Join();
  }
  for (int i = 0; i < threads.length(); i++) {
    delete threads[i];
  }
}


// Run many threads all locking on the same isolate
TEST(IsolateLockingStress) {
212
  i::FLAG_always_opt = false;
213
#if V8_TARGET_ARCH_MIPS
214 215
  const int kNThreads = 50;
#else
216
  const int kNThreads = 100;
217
#endif
218
  i::List<JoinableThread*> threads(kNThreads);
219 220 221
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate = v8::Isolate::New(create_params);
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
  for (int i = 0; i < kNThreads; i++) {
    threads.Add(new IsolateLockingThreadWithLocalContext(isolate));
  }
  StartJoinAndDeleteThreads(threads);
  isolate->Dispose();
}


class IsolateNestedLockingThread : public JoinableThread {
 public:
  explicit IsolateNestedLockingThread(v8::Isolate* isolate)
    : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
  }
  virtual void Run() {
    v8::Locker lock(isolate_);
    v8::Isolate::Scope isolate_scope(isolate_);
238
    v8::HandleScope handle_scope(isolate_);
239
    LocalContext local_context(isolate_);
240 241
    {
      v8::Locker another_lock(isolate_);
242
      CalcFibAndCheck(local_context.local());
243 244 245
    }
    {
      v8::Locker another_lock(isolate_);
246
      CalcFibAndCheck(local_context.local());
247 248 249 250 251 252
    }
  }
 private:
  v8::Isolate* isolate_;
};

253

254 255
// Run  many threads with nested locks
TEST(IsolateNestedLocking) {
256
  i::FLAG_always_opt = false;
257
#if V8_TARGET_ARCH_MIPS
258 259
  const int kNThreads = 50;
#else
260
  const int kNThreads = 100;
261
#endif
262 263 264
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate = v8::Isolate::New(create_params);
265 266 267 268 269
  i::List<JoinableThread*> threads(kNThreads);
  for (int i = 0; i < kNThreads; i++) {
    threads.Add(new IsolateNestedLockingThread(isolate));
  }
  StartJoinAndDeleteThreads(threads);
270
  isolate->Dispose();
271 272 273 274 275 276 277 278 279 280 281 282 283 284
}


class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread {
 public:
  SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
                                          v8::Isolate* isolate2)
    : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
      isolate1_(isolate1), isolate2_(isolate2) {
  }

  virtual void Run() {
    v8::Locker lock(isolate1_);
    v8::Isolate::Scope isolate_scope(isolate1_);
285
    v8::HandleScope handle_scope(isolate1_);
286
    LocalContext local_context(isolate1_);
287 288 289

    IsolateLockingThreadWithLocalContext threadB(isolate2_);
    threadB.Start();
290
    CalcFibAndCheck(local_context.local());
291 292 293 294 295 296 297
    threadB.Join();
  }
 private:
  v8::Isolate* isolate1_;
  v8::Isolate* isolate2_;
};

298

299 300
// Run parallel threads that lock and access different isolates in parallel
TEST(SeparateIsolatesLocksNonexclusive) {
301
  i::FLAG_always_opt = false;
302
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_S390
303 304
  const int kNThreads = 50;
#else
305
  const int kNThreads = 100;
306
#endif
307 308 309 310
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate1 = v8::Isolate::New(create_params);
  v8::Isolate* isolate2 = v8::Isolate::New(create_params);
311 312 313 314 315 316 317 318 319 320 321 322 323
  i::List<JoinableThread*> threads(kNThreads);
  for (int i = 0; i < kNThreads; i++) {
    threads.Add(new SeparateIsolatesLocksNonexclusiveThread(isolate1,
                                                             isolate2));
  }
  StartJoinAndDeleteThreads(threads);
  isolate2->Dispose();
  isolate1->Dispose();
}

class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread {
 public:
  explicit LockIsolateAndCalculateFibSharedContextThread(
324 325 326 327
      v8::Isolate* isolate, v8::Local<v8::Context> context)
      : JoinableThread("LockIsolateAndCalculateFibThread"),
        isolate_(isolate),
        context_(isolate, context) {}
328 329 330 331

  virtual void Run() {
    v8::Locker lock(isolate_);
    v8::Isolate::Scope isolate_scope(isolate_);
332
    HandleScope handle_scope(isolate_);
333 334 335
    v8::Local<v8::Context> context =
        v8::Local<v8::Context>::New(isolate_, context_);
    v8::Context::Scope context_scope(context);
336
    CalcFibAndCheck(context);
337 338 339 340 341 342 343 344 345 346 347 348 349 350
  }
 private:
  v8::Isolate* isolate_;
  Persistent<v8::Context> context_;
};

class LockerUnlockerThread : public JoinableThread {
 public:
  explicit LockerUnlockerThread(v8::Isolate* isolate)
    : JoinableThread("LockerUnlockerThread"),
      isolate_(isolate) {
  }

  virtual void Run() {
351
    isolate_->DiscardThreadSpecificMetadata();  // No-op
352
    {
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
      v8::Locker lock(isolate_);
      v8::Isolate::Scope isolate_scope(isolate_);
      v8::HandleScope handle_scope(isolate_);
      v8::Local<v8::Context> context = v8::Context::New(isolate_);
      {
        v8::Context::Scope context_scope(context);
        CalcFibAndCheck(context);
      }
      {
        LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
        isolate_->Exit();
        v8::Unlocker unlocker(isolate_);
        thread.Start();
        thread.Join();
      }
      isolate_->Enter();
      {
        v8::Context::Scope context_scope(context);
        CalcFibAndCheck(context);
      }
373
    }
374 375
    isolate_->DiscardThreadSpecificMetadata();
    isolate_->DiscardThreadSpecificMetadata();  // No-op
376
  }
377

378 379 380 381
 private:
  v8::Isolate* isolate_;
};

382

383 384
// Use unlocker inside of a Locker, multiple threads.
TEST(LockerUnlocker) {
385
  i::FLAG_always_opt = false;
386
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_S390
387 388
  const int kNThreads = 50;
#else
389
  const int kNThreads = 100;
390
#endif
391
  i::List<JoinableThread*> threads(kNThreads);
392 393 394
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate = v8::Isolate::New(create_params);
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
  for (int i = 0; i < kNThreads; i++) {
    threads.Add(new LockerUnlockerThread(isolate));
  }
  StartJoinAndDeleteThreads(threads);
  isolate->Dispose();
}

class LockTwiceAndUnlockThread : public JoinableThread {
 public:
  explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
    : JoinableThread("LockTwiceAndUnlockThread"),
      isolate_(isolate) {
  }

  virtual void Run() {
    v8::Locker lock(isolate_);
    v8::Isolate::Scope isolate_scope(isolate_);
412
    v8::HandleScope handle_scope(isolate_);
413
    v8::Local<v8::Context> context = v8::Context::New(isolate_);
414 415
    {
      v8::Context::Scope context_scope(context);
416
      CalcFibAndCheck(context);
417 418 419 420
    }
    {
      v8::Locker second_lock(isolate_);
      {
421
        LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
422 423 424 425 426 427 428 429 430
        isolate_->Exit();
        v8::Unlocker unlocker(isolate_);
        thread.Start();
        thread.Join();
      }
    }
    isolate_->Enter();
    {
      v8::Context::Scope context_scope(context);
431
      CalcFibAndCheck(context);
432 433
    }
  }
434

435 436 437 438
 private:
  v8::Isolate* isolate_;
};

439

440 441
// Use Unlocker inside two Lockers.
TEST(LockTwiceAndUnlock) {
442
  i::FLAG_always_opt = false;
443
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_S390
444 445
  const int kNThreads = 50;
#else
446
  const int kNThreads = 100;
447
#endif
448
  i::List<JoinableThread*> threads(kNThreads);
449 450 451
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate = v8::Isolate::New(create_params);
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
  for (int i = 0; i < kNThreads; i++) {
    threads.Add(new LockTwiceAndUnlockThread(isolate));
  }
  StartJoinAndDeleteThreads(threads);
  isolate->Dispose();
}

class LockAndUnlockDifferentIsolatesThread : public JoinableThread {
 public:
  LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
                                       v8::Isolate* isolate2)
    : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
      isolate1_(isolate1),
      isolate2_(isolate2) {
  }

  virtual void Run() {
469
    std::unique_ptr<LockIsolateAndCalculateFibSharedContextThread> thread;
470 471 472 473 474
    v8::Locker lock1(isolate1_);
    CHECK(v8::Locker::IsLocked(isolate1_));
    CHECK(!v8::Locker::IsLocked(isolate2_));
    {
      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 482
      thread.reset(new LockIsolateAndCalculateFibSharedContextThread(isolate1_,
                                                                     context1));
483 484 485 486 487 488
    }
    v8::Locker lock2(isolate2_);
    CHECK(v8::Locker::IsLocked(isolate1_));
    CHECK(v8::Locker::IsLocked(isolate2_));
    {
      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 496 497 498
      }
      v8::Unlocker unlock1(isolate1_);
      CHECK(!v8::Locker::IsLocked(isolate1_));
      CHECK(v8::Locker::IsLocked(isolate2_));
      v8::Context::Scope context_scope(context2);
499
      thread->Start();
500
      CalcFibAndCheck(context2);
501
      thread->Join();
502 503
    }
  }
504

505 506 507 508 509
 private:
  v8::Isolate* isolate1_;
  v8::Isolate* isolate2_;
};

510

511 512
// Lock two isolates and unlock one of them.
TEST(LockAndUnlockDifferentIsolates) {
513 514 515 516
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate1 = v8::Isolate::New(create_params);
  v8::Isolate* isolate2 = v8::Isolate::New(create_params);
517 518 519 520 521 522 523 524 525
  LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2);
  thread.Start();
  thread.Join();
  isolate2->Dispose();
  isolate1->Dispose();
}

class LockUnlockLockThread : public JoinableThread {
 public:
526 527 528 529
  LockUnlockLockThread(v8::Isolate* isolate, v8::Local<v8::Context> context)
      : JoinableThread("LockUnlockLockThread"),
        isolate_(isolate),
        context_(isolate, context) {}
530 531 532 533

  virtual void Run() {
    v8::Locker lock1(isolate_);
    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 539 540
      v8::Local<v8::Context> context =
          v8::Local<v8::Context>::New(isolate_, context_);
      v8::Context::Scope context_scope(context);
541
      CalcFibAndCheck(context);
542 543 544 545
    }
    {
      v8::Unlocker unlock1(isolate_);
      CHECK(!v8::Locker::IsLocked(isolate_));
546
      CHECK(!v8::Locker::IsLocked(CcTest::isolate()));
547 548 549
      {
        v8::Locker lock2(isolate_);
        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 554 555
        v8::Local<v8::Context> context =
            v8::Local<v8::Context>::New(isolate_, context_);
        v8::Context::Scope context_scope(context);
556
        CalcFibAndCheck(context);
557 558 559 560 561 562 563 564 565
      }
    }
  }

 private:
  v8::Isolate* isolate_;
  v8::Persistent<v8::Context> context_;
};

566

567 568
// Locker inside an Unlocker inside a Locker.
TEST(LockUnlockLockMultithreaded) {
569
#if V8_TARGET_ARCH_MIPS
570 571
  const int kNThreads = 50;
#else
572
  const int kNThreads = 100;
573
#endif
574 575 576
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  v8::Isolate* isolate = v8::Isolate::New(create_params);
577
  i::List<JoinableThread*> threads(kNThreads);
578 579 580
  {
    v8::Locker locker_(isolate);
    v8::Isolate::Scope isolate_scope(isolate);
581
    v8::HandleScope handle_scope(isolate);
582
    v8::Local<v8::Context> context = v8::Context::New(isolate);
583 584
    for (int i = 0; i < kNThreads; i++) {
      threads.Add(new LockUnlockLockThread(
585
          isolate, context));
586
    }
587 588
  }
  StartJoinAndDeleteThreads(threads);
589
  isolate->Dispose();
590 591 592 593
}

class LockUnlockLockDefaultIsolateThread : public JoinableThread {
 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 623 624 625
      }
    }
  }

 private:
  v8::Persistent<v8::Context> context_;
};

626

627
// Locker inside an Unlocker inside a Locker for default isolate.
628
TEST(LockUnlockLockDefaultIsolateMultithreaded) {
629
#if V8_TARGET_ARCH_MIPS
630 631
  const int kNThreads = 50;
#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 640
    v8::HandleScope handle_scope(CcTest::isolate());
    context = v8::Context::New(CcTest::isolate());
641
    for (int i = 0; i < kNThreads; i++) {
642
      threads.Add(new LockUnlockLockDefaultIsolateThread(context));
643
    }
644 645 646
  }
  StartJoinAndDeleteThreads(threads);
}
647 648 649 650


TEST(Regress1433) {
  for (int i = 0; i < 10; i++) {
651 652 653
    v8::Isolate::CreateParams create_params;
    create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    v8::Isolate* isolate = v8::Isolate::New(create_params);
654 655 656
    {
      v8::Locker lock(isolate);
      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 661 662 663
      v8::Local<String> source = v8_str("1+1");
      v8::Local<Script> script =
          v8::Script::Compile(context, source).ToLocalChecked();
      v8::Local<Value> result = script->Run(context).ToLocalChecked();
664
      v8::String::Utf8Value utf8(result);
665 666 667 668
    }
    isolate->Dispose();
  }
}
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684


static const char* kSimpleExtensionSource =
  "(function Foo() {"
  "  return 4;"
  "})() ";

class IsolateGenesisThread : public JoinableThread {
 public:
  IsolateGenesisThread(int count, const char* extension_names[])
    : JoinableThread("IsolateGenesisThread"),
      count_(count),
      extension_names_(extension_names)
  {}

  virtual void Run() {
685 686 687
    v8::Isolate::CreateParams create_params;
    create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    v8::Isolate* isolate = v8::Isolate::New(create_params);
688 689 690
    {
      v8::Isolate::Scope isolate_scope(isolate);
      v8::ExtensionConfiguration extensions(count_, extension_names_);
691 692
      v8::HandleScope handle_scope(isolate);
      v8::Context::New(isolate, &extensions);
693 694 695
    }
    isolate->Dispose();
  }
696

697 698 699 700 701
 private:
  int count_;
  const char** extension_names_;
};

702

703 704 705
// Test installing extensions in separate isolates concurrently.
// http://code.google.com/p/v8/issues/detail?id=1821
TEST(ExtensionsRegistration) {
706
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
707
  const int kNThreads = 10;
708 709
#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
  const int kNThreads = 4;
710 711
#elif V8_TARGET_ARCH_S390 && V8_TARGET_ARCH_32_BIT
  const int kNThreads = 10;
712
#else
713
  const int kNThreads = 40;
714
#endif
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
  v8::RegisterExtension(new v8::Extension("test0",
                                          kSimpleExtensionSource));
  v8::RegisterExtension(new v8::Extension("test1",
                                          kSimpleExtensionSource));
  v8::RegisterExtension(new v8::Extension("test2",
                                          kSimpleExtensionSource));
  v8::RegisterExtension(new v8::Extension("test3",
                                          kSimpleExtensionSource));
  v8::RegisterExtension(new v8::Extension("test4",
                                          kSimpleExtensionSource));
  v8::RegisterExtension(new v8::Extension("test5",
                                          kSimpleExtensionSource));
  v8::RegisterExtension(new v8::Extension("test6",
                                          kSimpleExtensionSource));
  v8::RegisterExtension(new v8::Extension("test7",
                                          kSimpleExtensionSource));
  const char* extension_names[] = { "test0", "test1",
                                    "test2", "test3", "test4",
                                    "test5", "test6", "test7" };
  i::List<JoinableThread*> threads(kNThreads);
  for (int i = 0; i < kNThreads; i++) {
    threads.Add(new IsolateGenesisThread(8, extension_names));
  }
  StartJoinAndDeleteThreads(threads);
}