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