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