1 // Copyright 2008 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 #ifndef CCTEST_H_
29 #define CCTEST_H_
30 
31 #include "include/libplatform/libplatform.h"
32 #include "src/isolate-inl.h"  // TODO(everyone): Make cctest IWYU.
33 #include "src/objects-inl.h"  // TODO(everyone): Make cctest IWYU.
34 #include "src/v8.h"
35 
36 #ifndef TEST
37 #define TEST(Name)                                                             \
38   static void Test##Name();                                                    \
39   CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true, true);  \
40   static void Test##Name()
41 #endif
42 
43 #ifndef UNINITIALIZED_TEST
44 #define UNINITIALIZED_TEST(Name)                                               \
45   static void Test##Name();                                                    \
46   CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true, false); \
47   static void Test##Name()
48 #endif
49 
50 #ifndef DEPENDENT_TEST
51 #define DEPENDENT_TEST(Name, Dep)                                              \
52   static void Test##Name();                                                    \
53   CcTest register_test_##Name(Test##Name, __FILE__, #Name, #Dep, true, true);  \
54   static void Test##Name()
55 #endif
56 
57 #ifndef UNINITIALIZED_DEPENDENT_TEST
58 #define UNINITIALIZED_DEPENDENT_TEST(Name, Dep)                                \
59   static void Test##Name();                                                    \
60   CcTest register_test_##Name(Test##Name, __FILE__, #Name, #Dep, true, false); \
61   static void Test##Name()
62 #endif
63 
64 #ifndef DISABLED_TEST
65 #define DISABLED_TEST(Name)                                                    \
66   static void Test##Name();                                                    \
67   CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, false, true); \
68   static void Test##Name()
69 #endif
70 
71 #define EXTENSION_LIST(V)                                                      \
72   V(GC_EXTENSION,       "v8/gc")                                               \
73   V(PRINT_EXTENSION,    "v8/print")                                            \
74   V(PROFILER_EXTENSION, "v8/profiler")                                         \
75   V(TRACE_EXTENSION,    "v8/trace")
76 
77 #define DEFINE_EXTENSION_ID(Name, Ident) Name##_ID,
78 enum CcTestExtensionIds {
79   EXTENSION_LIST(DEFINE_EXTENSION_ID)
80   kMaxExtensions
81 };
82 #undef DEFINE_EXTENSION_ID
83 
84 typedef v8::internal::EnumSet<CcTestExtensionIds> CcTestExtensionFlags;
85 #define DEFINE_EXTENSION_FLAG(Name, Ident)                               \
86   static const CcTestExtensionFlags Name(1 << Name##_ID);
87   static const CcTestExtensionFlags NO_EXTENSIONS(0);
88   static const CcTestExtensionFlags ALL_EXTENSIONS((1 << kMaxExtensions) - 1);
EXTENSION_LIST(DEFINE_EXTENSION_FLAG)89   EXTENSION_LIST(DEFINE_EXTENSION_FLAG)
90 #undef DEFINE_EXTENSION_FLAG
91 
92 
93 class CcTest {
94  public:
95   typedef void (TestFunction)();
96   CcTest(TestFunction* callback, const char* file, const char* name,
97          const char* dependency, bool enabled, bool initialize);
98   ~CcTest() { i::DeleteArray(file_); }
99   void Run();
100   static CcTest* last() { return last_; }
101   CcTest* prev() { return prev_; }
102   const char* file() { return file_; }
103   const char* name() { return name_; }
104   const char* dependency() { return dependency_; }
105   bool enabled() { return enabled_; }
106 
107   static v8::Isolate* isolate() {
108     CHECK(isolate_ != NULL);
109     v8::base::NoBarrier_Store(&isolate_used_, 1);
110     return isolate_;
111   }
112 
113   static i::Isolate* InitIsolateOnce() {
114     if (!initialize_called_) InitializeVM();
115     return i_isolate();
116   }
117 
118   static i::Isolate* i_isolate() {
119     return reinterpret_cast<i::Isolate*>(isolate());
120   }
121 
122   static i::Heap* heap() {
123     return i_isolate()->heap();
124   }
125 
126   static v8::base::RandomNumberGenerator* random_number_generator() {
127     return InitIsolateOnce()->random_number_generator();
128   }
129 
130   static v8::Local<v8::Object> global() {
131     return isolate()->GetCurrentContext()->Global();
132   }
133 
134   static v8::ArrayBuffer::Allocator* array_buffer_allocator() {
135     return allocator_;
136   }
137 
138   static void set_array_buffer_allocator(
139       v8::ArrayBuffer::Allocator* allocator) {
140     allocator_ = allocator;
141   }
142 
143   // TODO(dcarney): Remove.
144   // This must be called first in a test.
145   static void InitializeVM() {
146     CHECK(!v8::base::NoBarrier_Load(&isolate_used_));
147     CHECK(!initialize_called_);
148     initialize_called_ = true;
149     v8::HandleScope handle_scope(CcTest::isolate());
150     v8::Context::New(CcTest::isolate())->Enter();
151   }
152 
153   // Only for UNINITIALIZED_TESTs
154   static void DisableAutomaticDispose();
155 
156   // Helper function to configure a context.
157   // Must be in a HandleScope.
158   static v8::Local<v8::Context> NewContext(
159       CcTestExtensionFlags extensions,
160       v8::Isolate* isolate = CcTest::isolate());
161 
162   static void TearDown() {
163     if (isolate_ != NULL) isolate_->Dispose();
164   }
165 
166  private:
167   friend int main(int argc, char** argv);
168   TestFunction* callback_;
169   const char* file_;
170   const char* name_;
171   const char* dependency_;
172   bool enabled_;
173   bool initialize_;
174   CcTest* prev_;
175   static CcTest* last_;
176   static v8::ArrayBuffer::Allocator* allocator_;
177   static v8::Isolate* isolate_;
178   static bool initialize_called_;
179   static v8::base::Atomic32 isolate_used_;
180 };
181 
182 // Switches between all the Api tests using the threading support.
183 // In order to get a surprising but repeatable pattern of thread
184 // switching it has extra semaphores to control the order in which
185 // the tests alternate, not relying solely on the big V8 lock.
186 //
187 // A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
188 // callbacks.  This will have no effect when we are not running the
189 // thread fuzzing test.  In the thread fuzzing test it will
190 // pseudorandomly select a successor thread and switch execution
191 // to that thread, suspending the current test.
192 class ApiTestFuzzer: public v8::base::Thread {
193  public:
194   void CallTest();
195 
196   // The ApiTestFuzzer is also a Thread, so it has a Run method.
197   virtual void Run();
198 
199   enum PartOfTest { FIRST_PART,
200                     SECOND_PART,
201                     THIRD_PART,
202                     FOURTH_PART,
203                     LAST_PART = FOURTH_PART };
204 
205   static void SetUp(PartOfTest part);
206   static void RunAllTests();
207   static void TearDown();
208   // This method switches threads if we are running the Threading test.
209   // Otherwise it does nothing.
210   static void Fuzz();
211 
212  private:
ApiTestFuzzer(int num)213   explicit ApiTestFuzzer(int num)
214       : Thread(Options("ApiTestFuzzer")),
215         test_number_(num),
216         gate_(0),
217         active_(true) {}
~ApiTestFuzzer()218   ~ApiTestFuzzer() {}
219 
220   static bool fuzzing_;
221   static int tests_being_run_;
222   static int current_;
223   static int active_tests_;
224   static bool NextThread();
225   int test_number_;
226   v8::base::Semaphore gate_;
227   bool active_;
228   void ContextSwitch();
229   static int GetNextTestNumber();
230   static v8::base::Semaphore all_tests_done_;
231 };
232 
233 
234 #define THREADED_TEST(Name)                                          \
235   static void Test##Name();                                          \
236   RegisterThreadedTest register_##Name(Test##Name, #Name);           \
237   /* */ TEST(Name)
238 
239 
240 class RegisterThreadedTest {
241  public:
RegisterThreadedTest(CcTest::TestFunction * callback,const char * name)242   explicit RegisterThreadedTest(CcTest::TestFunction* callback,
243                                 const char* name)
244       : fuzzer_(NULL), callback_(callback), name_(name) {
245     prev_ = first_;
246     first_ = this;
247     count_++;
248   }
count()249   static int count() { return count_; }
nth(int i)250   static RegisterThreadedTest* nth(int i) {
251     CHECK(i < count());
252     RegisterThreadedTest* current = first_;
253     while (i > 0) {
254       i--;
255       current = current->prev_;
256     }
257     return current;
258   }
callback()259   CcTest::TestFunction* callback() { return callback_; }
260   ApiTestFuzzer* fuzzer_;
name()261   const char* name() { return name_; }
262 
263  private:
264   static RegisterThreadedTest* first_;
265   static int count_;
266   CcTest::TestFunction* callback_;
267   RegisterThreadedTest* prev_;
268   const char* name_;
269 };
270 
271 // A LocalContext holds a reference to a v8::Context.
272 class LocalContext {
273  public:
274   LocalContext(v8::Isolate* isolate, v8::ExtensionConfiguration* extensions = 0,
275                v8::Local<v8::ObjectTemplate> global_template =
276                    v8::Local<v8::ObjectTemplate>(),
277                v8::Local<v8::Value> global_object = v8::Local<v8::Value>()) {
278     Initialize(isolate, extensions, global_template, global_object);
279   }
280 
281   LocalContext(v8::ExtensionConfiguration* extensions = 0,
282                v8::Local<v8::ObjectTemplate> global_template =
283                    v8::Local<v8::ObjectTemplate>(),
284                v8::Local<v8::Value> global_object = v8::Local<v8::Value>()) {
285     Initialize(CcTest::isolate(), extensions, global_template, global_object);
286   }
287 
~LocalContext()288   virtual ~LocalContext() {
289     v8::HandleScope scope(isolate_);
290     v8::Local<v8::Context>::New(isolate_, context_)->Exit();
291     context_.Reset();
292   }
293 
294   v8::Context* operator->() {
295     return *reinterpret_cast<v8::Context**>(&context_);
296   }
297   v8::Context* operator*() { return operator->(); }
IsReady()298   bool IsReady() { return !context_.IsEmpty(); }
299 
local()300   v8::Local<v8::Context> local() {
301     return v8::Local<v8::Context>::New(isolate_, context_);
302   }
303 
304  private:
Initialize(v8::Isolate * isolate,v8::ExtensionConfiguration * extensions,v8::Local<v8::ObjectTemplate> global_template,v8::Local<v8::Value> global_object)305   void Initialize(v8::Isolate* isolate, v8::ExtensionConfiguration* extensions,
306                   v8::Local<v8::ObjectTemplate> global_template,
307                   v8::Local<v8::Value> global_object) {
308      v8::HandleScope scope(isolate);
309      v8::Local<v8::Context> context = v8::Context::New(isolate,
310                                                        extensions,
311                                                        global_template,
312                                                        global_object);
313      context_.Reset(isolate, context);
314      context->Enter();
315      // We can't do this later perhaps because of a fatal error.
316      isolate_ = isolate;
317   }
318 
319   v8::Persistent<v8::Context> context_;
320   v8::Isolate* isolate_;
321 };
322 
323 
AsciiToTwoByteString(const char * source)324 static inline uint16_t* AsciiToTwoByteString(const char* source) {
325   int array_length = i::StrLength(source) + 1;
326   uint16_t* converted = i::NewArray<uint16_t>(array_length);
327   for (int i = 0; i < array_length; i++) converted[i] = source[i];
328   return converted;
329 }
330 
331 
v8_num(double x)332 static inline v8::Local<v8::Value> v8_num(double x) {
333   return v8::Number::New(v8::Isolate::GetCurrent(), x);
334 }
335 
336 
v8_str(const char * x)337 static inline v8::Local<v8::String> v8_str(const char* x) {
338   return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x,
339                                  v8::NewStringType::kNormal)
340       .ToLocalChecked();
341 }
342 
343 
v8_str(v8::Isolate * isolate,const char * x)344 static inline v8::Local<v8::String> v8_str(v8::Isolate* isolate,
345                                            const char* x) {
346   return v8::String::NewFromUtf8(isolate, x, v8::NewStringType::kNormal)
347       .ToLocalChecked();
348 }
349 
350 
v8_symbol(const char * name)351 static inline v8::Local<v8::Symbol> v8_symbol(const char* name) {
352   return v8::Symbol::New(v8::Isolate::GetCurrent(), v8_str(name));
353 }
354 
355 
v8_compile(v8::Local<v8::String> x)356 static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
357   v8::Local<v8::Script> result;
358   if (v8::Script::Compile(v8::Isolate::GetCurrent()->GetCurrentContext(), x)
359           .ToLocal(&result)) {
360     return result;
361   }
362   return v8::Local<v8::Script>();
363 }
364 
365 
v8_compile(const char * x)366 static inline v8::Local<v8::Script> v8_compile(const char* x) {
367   return v8_compile(v8_str(x));
368 }
369 
370 
v8_run_int32value(v8::Local<v8::Script> script)371 static inline int32_t v8_run_int32value(v8::Local<v8::Script> script) {
372   v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
373   return script->Run(context).ToLocalChecked()->Int32Value(context).FromJust();
374 }
375 
376 
CompileWithOrigin(v8::Local<v8::String> source,v8::Local<v8::String> origin_url)377 static inline v8::Local<v8::Script> CompileWithOrigin(
378     v8::Local<v8::String> source, v8::Local<v8::String> origin_url) {
379   v8::ScriptOrigin origin(origin_url);
380   v8::ScriptCompiler::Source script_source(source, origin);
381   return v8::ScriptCompiler::Compile(
382              v8::Isolate::GetCurrent()->GetCurrentContext(), &script_source)
383       .ToLocalChecked();
384 }
385 
386 
CompileWithOrigin(v8::Local<v8::String> source,const char * origin_url)387 static inline v8::Local<v8::Script> CompileWithOrigin(
388     v8::Local<v8::String> source, const char* origin_url) {
389   return CompileWithOrigin(source, v8_str(origin_url));
390 }
391 
392 
CompileWithOrigin(const char * source,const char * origin_url)393 static inline v8::Local<v8::Script> CompileWithOrigin(const char* source,
394                                                       const char* origin_url) {
395   return CompileWithOrigin(v8_str(source), v8_str(origin_url));
396 }
397 
398 
399 // Helper functions that compile and run the source.
CompileRun(v8::Local<v8::Context> context,const char * source)400 static inline v8::MaybeLocal<v8::Value> CompileRun(
401     v8::Local<v8::Context> context, const char* source) {
402   return v8::Script::Compile(context, v8_str(source))
403       .ToLocalChecked()
404       ->Run(context);
405 }
406 
407 
CompileRunChecked(v8::Isolate * isolate,const char * source)408 static inline v8::Local<v8::Value> CompileRunChecked(v8::Isolate* isolate,
409                                                      const char* source) {
410   v8::Local<v8::String> source_string =
411       v8::String::NewFromUtf8(isolate, source, v8::NewStringType::kNormal)
412           .ToLocalChecked();
413   v8::Local<v8::Context> context = isolate->GetCurrentContext();
414   v8::Local<v8::Script> script =
415       v8::Script::Compile(context, source_string).ToLocalChecked();
416   return script->Run(context).ToLocalChecked();
417 }
418 
419 
CompileRun(v8::Local<v8::String> source)420 static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
421   v8::Local<v8::Value> result;
422   if (v8_compile(source)
423           ->Run(v8::Isolate::GetCurrent()->GetCurrentContext())
424           .ToLocal(&result)) {
425     return result;
426   }
427   return v8::Local<v8::Value>();
428 }
429 
430 
431 // Helper functions that compile and run the source.
CompileRun(const char * source)432 static inline v8::Local<v8::Value> CompileRun(const char* source) {
433   return CompileRun(v8_str(source));
434 }
435 
436 
CompileRun(v8::Local<v8::Context> context,v8::ScriptCompiler::Source * script_source,v8::ScriptCompiler::CompileOptions options)437 static inline v8::Local<v8::Value> CompileRun(
438     v8::Local<v8::Context> context, v8::ScriptCompiler::Source* script_source,
439     v8::ScriptCompiler::CompileOptions options) {
440   v8::Local<v8::Value> result;
441   if (v8::ScriptCompiler::Compile(context, script_source, options)
442           .ToLocalChecked()
443           ->Run(context)
444           .ToLocal(&result)) {
445     return result;
446   }
447   return v8::Local<v8::Value>();
448 }
449 
450 
ParserCacheCompileRun(const char * source)451 static inline v8::Local<v8::Value> ParserCacheCompileRun(const char* source) {
452   // Compile once just to get the preparse data, then compile the second time
453   // using the data.
454   v8::Isolate* isolate = v8::Isolate::GetCurrent();
455   v8::Local<v8::Context> context = isolate->GetCurrentContext();
456   v8::ScriptCompiler::Source script_source(v8_str(source));
457   v8::ScriptCompiler::Compile(context, &script_source,
458                               v8::ScriptCompiler::kProduceParserCache)
459       .ToLocalChecked();
460 
461   // Check whether we received cached data, and if so use it.
462   v8::ScriptCompiler::CompileOptions options =
463       script_source.GetCachedData() ? v8::ScriptCompiler::kConsumeParserCache
464                                     : v8::ScriptCompiler::kNoCompileOptions;
465 
466   return CompileRun(context, &script_source, options);
467 }
468 
469 
470 // Helper functions that compile and run the source with given origin.
CompileRunWithOrigin(const char * source,const char * origin_url,int line_number,int column_number)471 static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
472                                                         const char* origin_url,
473                                                         int line_number,
474                                                         int column_number) {
475   v8::Isolate* isolate = v8::Isolate::GetCurrent();
476   v8::Local<v8::Context> context = isolate->GetCurrentContext();
477   v8::ScriptOrigin origin(v8_str(origin_url),
478                           v8::Integer::New(isolate, line_number),
479                           v8::Integer::New(isolate, column_number));
480   v8::ScriptCompiler::Source script_source(v8_str(source), origin);
481   return CompileRun(context, &script_source,
482                     v8::ScriptCompiler::CompileOptions());
483 }
484 
485 
CompileRunWithOrigin(v8::Local<v8::String> source,const char * origin_url)486 static inline v8::Local<v8::Value> CompileRunWithOrigin(
487     v8::Local<v8::String> source, const char* origin_url) {
488   v8::Isolate* isolate = v8::Isolate::GetCurrent();
489   v8::Local<v8::Context> context = isolate->GetCurrentContext();
490   v8::ScriptCompiler::Source script_source(
491       source, v8::ScriptOrigin(v8_str(origin_url)));
492   return CompileRun(context, &script_source,
493                     v8::ScriptCompiler::CompileOptions());
494 }
495 
496 
CompileRunWithOrigin(const char * source,const char * origin_url)497 static inline v8::Local<v8::Value> CompileRunWithOrigin(
498     const char* source, const char* origin_url) {
499   return CompileRunWithOrigin(v8_str(source), origin_url);
500 }
501 
502 
503 
ExpectString(const char * code,const char * expected)504 static inline void ExpectString(const char* code, const char* expected) {
505   v8::Local<v8::Value> result = CompileRun(code);
506   CHECK(result->IsString());
507   v8::String::Utf8Value utf8(result);
508   CHECK_EQ(0, strcmp(expected, *utf8));
509 }
510 
511 
ExpectInt32(const char * code,int expected)512 static inline void ExpectInt32(const char* code, int expected) {
513   v8::Local<v8::Value> result = CompileRun(code);
514   CHECK(result->IsInt32());
515   CHECK_EQ(expected,
516            result->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext())
517                .FromJust());
518 }
519 
520 
ExpectBoolean(const char * code,bool expected)521 static inline void ExpectBoolean(const char* code, bool expected) {
522   v8::Local<v8::Value> result = CompileRun(code);
523   CHECK(result->IsBoolean());
524   CHECK_EQ(expected,
525            result->BooleanValue(v8::Isolate::GetCurrent()->GetCurrentContext())
526                .FromJust());
527 }
528 
529 
ExpectTrue(const char * code)530 static inline void ExpectTrue(const char* code) {
531   ExpectBoolean(code, true);
532 }
533 
534 
ExpectFalse(const char * code)535 static inline void ExpectFalse(const char* code) {
536   ExpectBoolean(code, false);
537 }
538 
539 
ExpectObject(const char * code,v8::Local<v8::Value> expected)540 static inline void ExpectObject(const char* code,
541                                 v8::Local<v8::Value> expected) {
542   v8::Local<v8::Value> result = CompileRun(code);
543   CHECK(result->SameValue(expected));
544 }
545 
546 
ExpectUndefined(const char * code)547 static inline void ExpectUndefined(const char* code) {
548   v8::Local<v8::Value> result = CompileRun(code);
549   CHECK(result->IsUndefined());
550 }
551 
552 
ExpectNull(const char * code)553 static inline void ExpectNull(const char* code) {
554   v8::Local<v8::Value> result = CompileRun(code);
555   CHECK(result->IsNull());
556 }
557 
558 
CheckDoubleEquals(double expected,double actual)559 static inline void CheckDoubleEquals(double expected, double actual) {
560   const double kEpsilon = 1e-10;
561   CHECK_LE(expected, actual + kEpsilon);
562   CHECK_GE(expected, actual - kEpsilon);
563 }
564 
565 
DummyDebugEventListener(const v8::Debug::EventDetails & event_details)566 static void DummyDebugEventListener(
567     const v8::Debug::EventDetails& event_details) {}
568 
569 
EnableDebugger(v8::Isolate * isolate)570 static inline void EnableDebugger(v8::Isolate* isolate) {
571   v8::Debug::SetDebugEventListener(isolate, &DummyDebugEventListener);
572 }
573 
574 
DisableDebugger(v8::Isolate * isolate)575 static inline void DisableDebugger(v8::Isolate* isolate) {
576   v8::Debug::SetDebugEventListener(isolate, nullptr);
577 }
578 
579 
EmptyMessageQueues(v8::Isolate * isolate)580 static inline void EmptyMessageQueues(v8::Isolate* isolate) {
581   while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(),
582                                        isolate)) {
583   }
584 }
585 
586 
587 class InitializedHandleScope {
588  public:
InitializedHandleScope()589   InitializedHandleScope()
590       : main_isolate_(CcTest::InitIsolateOnce()),
591         handle_scope_(main_isolate_) {}
592 
593   // Prefixing the below with main_ reduces a lot of naming clashes.
main_isolate()594   i::Isolate* main_isolate() { return main_isolate_; }
595 
596  private:
597   i::Isolate* main_isolate_;
598   i::HandleScope handle_scope_;
599 };
600 
601 
602 class HandleAndZoneScope : public InitializedHandleScope {
603  public:
HandleAndZoneScope()604   HandleAndZoneScope() {}
605 
606   // Prefixing the below with main_ reduces a lot of naming clashes.
main_zone()607   i::Zone* main_zone() { return &main_zone_; }
608 
609  private:
610   i::Zone main_zone_;
611 };
612 
613 #endif  // ifndef CCTEST_H_
614