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