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