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 "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);  \
     37   static void Test##Name()
     38 #endif
     39 
     40 #ifndef DEPENDENT_TEST
     41 #define DEPENDENT_TEST(Name, Dep)                                        \
     42   static void Test##Name();                                              \
     43   CcTest register_test_##Name(Test##Name, __FILE__, #Name, #Dep, true);  \
     44   static void Test##Name()
     45 #endif
     46 
     47 #ifndef DISABLED_TEST
     48 #define DISABLED_TEST(Name)                                              \
     49   static void Test##Name();                                              \
     50   CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, false); \
     51   static void Test##Name()
     52 #endif
     53 
     54 #define EXTENSION_LIST(V)                                                \
     55   V(GC_EXTENSION,    "v8/gc")                                            \
     56   V(PRINT_EXTENSION, "v8/print")                                         \
     57   V(TRACE_EXTENSION, "v8/trace")
     58 
     59 #define DEFINE_EXTENSION_ID(Name, Ident) Name##_ID,
     60 enum CcTestExtensionIds {
     61   EXTENSION_LIST(DEFINE_EXTENSION_ID)
     62   kMaxExtensions
     63 };
     64 #undef DEFINE_EXTENSION_ID
     65 
     66 typedef v8::internal::EnumSet<CcTestExtensionIds> CcTestExtensionFlags;
     67 #define DEFINE_EXTENSION_FLAG(Name, Ident)                               \
     68   static const CcTestExtensionFlags Name(1 << Name##_ID);
     69   static const CcTestExtensionFlags NO_EXTENSIONS(0);
     70   static const CcTestExtensionFlags ALL_EXTENSIONS((1 << kMaxExtensions) - 1);
     71   EXTENSION_LIST(DEFINE_EXTENSION_FLAG)
     72 #undef DEFINE_EXTENSION_FLAG
     73 
     74 class CcTest {
     75  public:
     76   typedef void (TestFunction)();
     77   CcTest(TestFunction* callback, const char* file, const char* name,
     78          const char* dependency, bool enabled);
     79   void Run() { callback_(); }
     80   static CcTest* last() { return last_; }
     81   CcTest* prev() { return prev_; }
     82   const char* file() { return file_; }
     83   const char* name() { return name_; }
     84   const char* dependency() { return dependency_; }
     85   bool enabled() { return enabled_; }
     86   static v8::Isolate* default_isolate() { return default_isolate_; }
     87 
     88   static v8::Handle<v8::Context> env() {
     89     return v8::Local<v8::Context>::New(default_isolate_, context_);
     90   }
     91 
     92   static v8::Isolate* isolate() { return default_isolate_; }
     93 
     94   // Helper function to initialize the VM.
     95   static void InitializeVM(CcTestExtensionFlags extensions = NO_EXTENSIONS);
     96 
     97  private:
     98   friend int main(int argc, char** argv);
     99   static void set_default_isolate(v8::Isolate* default_isolate) {
    100     default_isolate_ = default_isolate;
    101   }
    102   TestFunction* callback_;
    103   const char* file_;
    104   const char* name_;
    105   const char* dependency_;
    106   bool enabled_;
    107   CcTest* prev_;
    108   static CcTest* last_;
    109   static v8::Isolate* default_isolate_;
    110   static v8::Persistent<v8::Context> context_;
    111 };
    112 
    113 // Switches between all the Api tests using the threading support.
    114 // In order to get a surprising but repeatable pattern of thread
    115 // switching it has extra semaphores to control the order in which
    116 // the tests alternate, not relying solely on the big V8 lock.
    117 //
    118 // A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
    119 // callbacks.  This will have no effect when we are not running the
    120 // thread fuzzing test.  In the thread fuzzing test it will
    121 // pseudorandomly select a successor thread and switch execution
    122 // to that thread, suspending the current test.
    123 class ApiTestFuzzer: public v8::internal::Thread {
    124  public:
    125   void CallTest();
    126 
    127   // The ApiTestFuzzer is also a Thread, so it has a Run method.
    128   virtual void Run();
    129 
    130   enum PartOfTest { FIRST_PART,
    131                     SECOND_PART,
    132                     THIRD_PART,
    133                     FOURTH_PART,
    134                     LAST_PART = FOURTH_PART };
    135 
    136   static void SetUp(PartOfTest part);
    137   static void RunAllTests();
    138   static void TearDown();
    139   // This method switches threads if we are running the Threading test.
    140   // Otherwise it does nothing.
    141   static void Fuzz();
    142 
    143  private:
    144   explicit ApiTestFuzzer(int num)
    145       : Thread("ApiTestFuzzer"),
    146         test_number_(num),
    147         gate_(v8::internal::OS::CreateSemaphore(0)),
    148         active_(true) {
    149   }
    150   ~ApiTestFuzzer() { delete gate_; }
    151 
    152   static bool fuzzing_;
    153   static int tests_being_run_;
    154   static int current_;
    155   static int active_tests_;
    156   static bool NextThread();
    157   int test_number_;
    158   v8::internal::Semaphore* gate_;
    159   bool active_;
    160   void ContextSwitch();
    161   static int GetNextTestNumber();
    162   static v8::internal::Semaphore* all_tests_done_;
    163 };
    164 
    165 
    166 #define THREADED_TEST(Name)                                          \
    167   static void Test##Name();                                          \
    168   RegisterThreadedTest register_##Name(Test##Name, #Name);           \
    169   /* */ TEST(Name)
    170 
    171 
    172 class RegisterThreadedTest {
    173  public:
    174   explicit RegisterThreadedTest(CcTest::TestFunction* callback,
    175                                 const char* name)
    176       : fuzzer_(NULL), callback_(callback), name_(name) {
    177     prev_ = first_;
    178     first_ = this;
    179     count_++;
    180   }
    181   static int count() { return count_; }
    182   static RegisterThreadedTest* nth(int i) {
    183     CHECK(i < count());
    184     RegisterThreadedTest* current = first_;
    185     while (i > 0) {
    186       i--;
    187       current = current->prev_;
    188     }
    189     return current;
    190   }
    191   CcTest::TestFunction* callback() { return callback_; }
    192   ApiTestFuzzer* fuzzer_;
    193   const char* name() { return name_; }
    194 
    195  private:
    196   static RegisterThreadedTest* first_;
    197   static int count_;
    198   CcTest::TestFunction* callback_;
    199   RegisterThreadedTest* prev_;
    200   const char* name_;
    201 };
    202 
    203 // A LocalContext holds a reference to a v8::Context.
    204 class LocalContext {
    205  public:
    206   LocalContext(v8::ExtensionConfiguration* extensions = 0,
    207                v8::Handle<v8::ObjectTemplate> global_template =
    208                    v8::Handle<v8::ObjectTemplate>(),
    209                v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>()) {
    210     v8::Isolate* isolate = v8::Isolate::GetCurrent();
    211     v8::HandleScope scope(isolate);
    212     v8::Local<v8::Context> context = v8::Context::New(isolate,
    213                                                       extensions,
    214                                                       global_template,
    215                                                       global_object);
    216     context_.Reset(isolate, context);
    217     context->Enter();
    218     // We can't do this later perhaps because of a fatal error.
    219     isolate_ = context->GetIsolate();
    220   }
    221 
    222   virtual ~LocalContext() {
    223     v8::HandleScope scope(isolate_);
    224     v8::Local<v8::Context>::New(isolate_, context_)->Exit();
    225     context_.Dispose();
    226   }
    227 
    228   v8::Context* operator->() {
    229     return *reinterpret_cast<v8::Context**>(&context_);
    230   }
    231   v8::Context* operator*() { return operator->(); }
    232   bool IsReady() { return !context_.IsEmpty(); }
    233 
    234   v8::Local<v8::Context> local() {
    235     return v8::Local<v8::Context>::New(isolate_, context_);
    236   }
    237 
    238  private:
    239   v8::Persistent<v8::Context> context_;
    240   v8::Isolate* isolate_;
    241 };
    242 
    243 static inline v8::Local<v8::Value> v8_num(double x) {
    244   return v8::Number::New(x);
    245 }
    246 
    247 
    248 static inline v8::Local<v8::String> v8_str(const char* x) {
    249   return v8::String::New(x);
    250 }
    251 
    252 
    253 static inline v8::Local<v8::Script> v8_compile(const char* x) {
    254   return v8::Script::Compile(v8_str(x));
    255 }
    256 
    257 
    258 // Helper function that compiles and runs the source.
    259 static inline v8::Local<v8::Value> CompileRun(const char* source) {
    260   return v8::Script::Compile(v8::String::New(source))->Run();
    261 }
    262 
    263 
    264 // Helper function that compiles and runs the source with given origin.
    265 static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
    266                                                         const char* origin_url,
    267                                                         int line_number,
    268                                                         int column_number) {
    269   v8::ScriptOrigin origin(v8::String::New(origin_url),
    270                           v8::Integer::New(line_number),
    271                           v8::Integer::New(column_number));
    272   return v8::Script::Compile(v8::String::New(source), &origin)->Run();
    273 }
    274 
    275 
    276 // Pick a slightly different port to allow tests to be run in parallel.
    277 static inline int FlagDependentPortOffset() {
    278   return ::v8::internal::FLAG_crankshaft == false ? 100 :
    279          ::v8::internal::FLAG_always_opt ? 200 : 0;
    280 }
    281 
    282 
    283 // Helper function that simulates a full new-space in the heap.
    284 static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
    285   int new_linear_size = static_cast<int>(
    286       *space->allocation_limit_address() - *space->allocation_top_address());
    287   v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size);
    288   v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe);
    289   node->set_size(space->heap(), new_linear_size);
    290 }
    291 
    292 
    293 // Helper function that simulates a full old-space in the heap.
    294 static inline void SimulateFullSpace(v8::internal::PagedSpace* space) {
    295   int old_linear_size = static_cast<int>(space->limit() - space->top());
    296   space->Free(space->top(), old_linear_size);
    297   space->SetTop(space->limit(), space->limit());
    298   space->ResetFreeList();
    299   space->ClearStats();
    300 }
    301 
    302 
    303 #endif  // ifndef CCTEST_H_
    304