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