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