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 #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);
     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();
    111   static CcTest* last() { return last_; }
    112   CcTest* prev() { return prev_; }
    113   const char* file() { return file_; }
    114   const char* name() { return name_; }
    115   const char* dependency() { return dependency_; }
    116   bool enabled() { return enabled_; }
    117 
    118   static v8::Isolate* isolate() {
    119     CHECK(isolate_ != NULL);
    120     isolate_used_ = true;
    121     return isolate_;
    122   }
    123 
    124   static i::Isolate* InitIsolateOnce() {
    125     if (!initialize_called_) InitializeVM();
    126     return i_isolate();
    127   }
    128 
    129   static i::Isolate* i_isolate() {
    130     return reinterpret_cast<i::Isolate*>(isolate());
    131   }
    132 
    133   static i::Heap* heap() {
    134     return i_isolate()->heap();
    135   }
    136 
    137   static TestHeap* test_heap() {
    138     return reinterpret_cast<TestHeap*>(i_isolate()->heap());
    139   }
    140 
    141   static v8::base::RandomNumberGenerator* random_number_generator() {
    142     return InitIsolateOnce()->random_number_generator();
    143   }
    144 
    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.
    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 
    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:
    218   explicit ApiTestFuzzer(int num)
    219       : Thread(Options("ApiTestFuzzer")),
    220         test_number_(num),
    221         gate_(0),
    222         active_(true) {}
    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:
    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   }
    254   static int count() { return count_; }
    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   }
    264   CcTest::TestFunction* callback() { return callback_; }
    265   ApiTestFuzzer* fuzzer_;
    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 
    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->(); }
    304   bool IsReady() { return !context_.IsEmpty(); }
    305 
    306   v8::Local<v8::Context> local() {
    307     return v8::Local<v8::Context>::New(isolate_, context_);
    308   }
    309 
    310  private:
    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 
    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 
    339 static inline v8::Local<v8::Value> v8_num(double x) {
    340   return v8::Number::New(v8::Isolate::GetCurrent(), x);
    341 }
    342 
    343 
    344 static inline v8::Local<v8::String> v8_str(const char* x) {
    345   return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x);
    346 }
    347 
    348 
    349 static inline v8::Local<v8::Script> v8_compile(const char* x) {
    350   return v8::Script::Compile(v8_str(x));
    351 }
    352 
    353 
    354 static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
    355   return v8::Script::Compile(x);
    356 }
    357 
    358 
    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 
    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 
    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.
    381 static inline v8::Local<v8::Value> CompileRun(const char* source) {
    382   return v8::Script::Compile(v8_str(source))->Run();
    383 }
    384 
    385 
    386 static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
    387   return v8::Script::Compile(source)->Run();
    388 }
    389 
    390 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    460 static inline void ExpectTrue(const char* code) {
    461   ExpectBoolean(code, true);
    462 }
    463 
    464 
    465 static inline void ExpectFalse(const char* code) {
    466   ExpectBoolean(code, false);
    467 }
    468 
    469 
    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 
    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.
    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.
    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.
    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:
    529   HeapObjectsTracker() {
    530     heap_profiler_ = i::Isolate::Current()->heap_profiler();
    531     CHECK_NE(NULL, heap_profiler_);
    532     heap_profiler_->StartHeapObjectsTracking(true);
    533   }
    534 
    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:
    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.
    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:
    563   HandleAndZoneScope() : main_zone_(main_isolate()) {}
    564 
    565   // Prefixing the below with main_ reduces a lot of naming clashes.
    566   i::Zone* main_zone() { return &main_zone_; }
    567 
    568  private:
    569   i::Zone main_zone_;
    570 };
    571 
    572 #endif  // ifndef CCTEST_H_
    573