cctest.h 29 KB
Newer Older
1
// Copyright 2008 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef CCTEST_H_
#define CCTEST_H_

31 32
#include <memory>

33
#include "include/libplatform/libplatform.h"
34
#include "include/v8-platform.h"
35
#include "src/base/enum-set.h"
36
#include "src/codegen/register-configuration.h"
37
#include "src/debug/debug-interface.h"
38
#include "src/execution/isolate.h"
39
#include "src/execution/simulator.h"
40
#include "src/flags/flags.h"
41
#include "src/heap/factory.h"
42
#include "src/init/v8.h"
43
#include "src/objects/js-function.h"
44
#include "src/objects/objects.h"
45
#include "src/zone/accounting-allocator.h"
46

47 48 49 50 51 52 53 54 55
namespace v8 {
namespace base {

class RandomNumberGenerator;

}  // namespace base

namespace internal {

56 57
const auto GetRegConfig = RegisterConfiguration::Default;

58 59 60
class HandleScope;
class Zone;

61 62 63 64 65 66
namespace compiler {

class JSHeapBroker;

}  // namespace compiler

67 68 69 70
}  // namespace internal

}  // namespace v8

71
#ifndef TEST
72 73 74
#define TEST(Name)                                                      \
  static void Test##Name();                                             \
  CcTest register_test_##Name(Test##Name, __FILE__, #Name, true, true); \
75 76 77 78
  static void Test##Name()
#endif

#ifndef UNINITIALIZED_TEST
79 80 81
#define UNINITIALIZED_TEST(Name)                                         \
  static void Test##Name();                                              \
  CcTest register_test_##Name(Test##Name, __FILE__, #Name, true, false); \
82 83 84
  static void Test##Name()
#endif

85
#ifndef DISABLED_TEST
86 87 88
#define DISABLED_TEST(Name)                                              \
  static void Test##Name();                                              \
  CcTest register_test_##Name(Test##Name, __FILE__, #Name, false, true); \
89 90 91
  static void Test##Name()
#endif

92 93 94 95 96 97 98 99 100 101 102 103 104
// Similar to TEST, but used when test definitions appear as members of a
// (probably parameterized) class. This allows re-using the given tests multiple
// times. For this to work, the following conditions must hold:
//   1. The class has a template parameter named kTestFileName of type  char
//      const*, which is instantiated with __FILE__ at the *use site*, in order
//      to correctly associate the tests with the test suite using them.
//   2. To actually execute the tests, create an instance of the class
//      containing the MEMBER_TESTs.
#define MEMBER_TEST(Name)                                   \
  CcTest register_test_##Name =                             \
      CcTest(Test##Name, kTestFileName, #Name, true, true); \
  static void Test##Name()

105 106 107 108 109
#define EXTENSION_LIST(V)                                                      \
  V(GC_EXTENSION,       "v8/gc")                                               \
  V(PRINT_EXTENSION,    "v8/print")                                            \
  V(PROFILER_EXTENSION, "v8/profiler")                                         \
  V(TRACE_EXTENSION,    "v8/trace")
110 111

#define DEFINE_EXTENSION_ID(Name, Ident) Name##_ID,
112
enum CcTestExtensionId { EXTENSION_LIST(DEFINE_EXTENSION_ID) kMaxExtensions };
113 114
#undef DEFINE_EXTENSION_ID

115
using CcTestExtensionFlags = v8::base::EnumSet<CcTestExtensionId>;
116

117 118 119 120
#define DEFINE_EXTENSION_NAME(Name, Ident) Ident,
static constexpr const char* kExtensionName[kMaxExtensions] = {
    EXTENSION_LIST(DEFINE_EXTENSION_NAME)};
#undef DEFINE_EXTENSION_NAME
121

122 123
class CcTest {
 public:
124
  using TestFunction = void();
125
  CcTest(TestFunction* callback, const char* file, const char* name,
126
         bool enabled, bool initialize);
127
  ~CcTest() { i::DeleteArray(file_); }
128
  void Run();
129
  static CcTest* last() { return last_; }
130 131 132
  CcTest* prev() { return prev_; }
  const char* file() { return file_; }
  const char* name() { return name_; }
133
  bool enabled() { return enabled_; }
134

135
  static v8::Isolate* isolate() {
136
    CHECK_NOT_NULL(isolate_);
137
    v8::base::Relaxed_Store(&isolate_used_, 1);
138
    return isolate_;
139
  }
140

141 142 143 144 145
  static i::Isolate* InitIsolateOnce() {
    if (!initialize_called_) InitializeVM();
    return i_isolate();
  }

146
  static i::Isolate* i_isolate() {
147
    return reinterpret_cast<i::Isolate*>(isolate());
148 149
  }

150
  static i::Heap* heap();
151
  static i::ReadOnlyHeap* read_only_heap();
152

153 154
  static void AddGlobalFunction(v8::Local<v8::Context> env, const char* name,
                                v8::FunctionCallback callback);
155 156
  static void CollectGarbage(i::AllocationSpace space,
                             i::Isolate* isolate = nullptr);
157 158 159
  static void CollectAllGarbage(i::Isolate* isolate = nullptr);
  static void CollectAllAvailableGarbage(i::Isolate* isolate = nullptr);
  static void PreciseCollectAllGarbage(i::Isolate* isolate = nullptr);
160

161 162 163
  static i::Handle<i::String> MakeString(const char* str);
  static i::Handle<i::String> MakeName(const char* str, int suffix);

164
  static v8::base::RandomNumberGenerator* random_number_generator();
165

166
  static v8::Local<v8::Object> global();
167

168 169 170 171 172 173 174 175 176
  static v8::ArrayBuffer::Allocator* array_buffer_allocator() {
    return allocator_;
  }

  static void set_array_buffer_allocator(
      v8::ArrayBuffer::Allocator* allocator) {
    allocator_ = allocator;
  }

177 178
  // TODO(dcarney): Remove.
  // This must be called first in a test.
179
  static void InitializeVM();
180

181 182 183
  // Only for UNINITIALIZED_TESTs
  static void DisableAutomaticDispose();

184 185 186
  // Helper function to configure a context.
  // Must be in a HandleScope.
  static v8::Local<v8::Context> NewContext(
187 188 189 190 191
      v8::Isolate* isolate = CcTest::isolate()) {
    return NewContext({}, isolate);
  }
  static v8::Local<v8::Context> NewContext(
      CcTestExtensionFlags extension_flags,
192
      v8::Isolate* isolate = CcTest::isolate());
193 194 195 196 197
  static v8::Local<v8::Context> NewContext(
      std::initializer_list<CcTestExtensionId> extensions,
      v8::Isolate* isolate = CcTest::isolate()) {
    return NewContext(CcTestExtensionFlags{extensions}, isolate);
  }
198

199
  static void TearDown();
200

201
 private:
202
  friend int main(int argc, char** argv);
203 204 205
  TestFunction* callback_;
  const char* file_;
  const char* name_;
206
  bool enabled_;
207
  bool initialize_;
208
  CcTest* prev_;
209
  static CcTest* last_;
210
  static v8::ArrayBuffer::Allocator* allocator_;
211 212
  static v8::Isolate* isolate_;
  static bool initialize_called_;
213
  static v8::base::Atomic32 isolate_used_;
214 215
};

216 217 218 219 220 221 222 223 224 225
// Switches between all the Api tests using the threading support.
// In order to get a surprising but repeatable pattern of thread
// switching it has extra semaphores to control the order in which
// the tests alternate, not relying solely on the big V8 lock.
//
// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
// callbacks.  This will have no effect when we are not running the
// thread fuzzing test.  In the thread fuzzing test it will
// pseudorandomly select a successor thread and switch execution
// to that thread, suspending the current test.
226
class ApiTestFuzzer: public v8::base::Thread {
227 228 229 230
 public:
  void CallTest();

  // The ApiTestFuzzer is also a Thread, so it has a Run method.
231
  void Run() override;
232

233 234 235 236 237 238 239 240 241 242 243
  enum PartOfTest {
    FIRST_PART,
    SECOND_PART,
    THIRD_PART,
    FOURTH_PART,
    FIFTH_PART,
    SIXTH_PART,
    SEVENTH_PART,
    EIGHTH_PART,
    LAST_PART = EIGHTH_PART
  };
244

245
  static void SetUp(PartOfTest part);
246 247 248 249 250
  static void RunAllTests();
  static void TearDown();
  // This method switches threads if we are running the Threading test.
  // Otherwise it does nothing.
  static void Fuzz();
251

252
 private:
253
  explicit ApiTestFuzzer(int num)
254
      : Thread(Options("ApiTestFuzzer")),
255
        test_number_(num),
256
        gate_(0),
257
        active_(true) {}
258
  ~ApiTestFuzzer() override = default;
259

260 261 262 263 264 265
  static bool fuzzing_;
  static int tests_being_run_;
  static int current_;
  static int active_tests_;
  static bool NextThread();
  int test_number_;
266
  v8::base::Semaphore gate_;
267 268 269
  bool active_;
  void ContextSwitch();
  static int GetNextTestNumber();
270
  static v8::base::Semaphore all_tests_done_;
271 272 273 274 275 276 277 278 279 280 281 282
};


#define THREADED_TEST(Name)                                          \
  static void Test##Name();                                          \
  RegisterThreadedTest register_##Name(Test##Name, #Name);           \
  /* */ TEST(Name)

class RegisterThreadedTest {
 public:
  explicit RegisterThreadedTest(CcTest::TestFunction* callback,
                                const char* name)
283
      : fuzzer_(nullptr), callback_(callback), name_(name) {
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
    prev_ = first_;
    first_ = this;
    count_++;
  }
  static int count() { return count_; }
  static RegisterThreadedTest* nth(int i) {
    CHECK(i < count());
    RegisterThreadedTest* current = first_;
    while (i > 0) {
      i--;
      current = current->prev_;
    }
    return current;
  }
  CcTest::TestFunction* callback() { return callback_; }
  ApiTestFuzzer* fuzzer_;
  const char* name() { return name_; }

 private:
  static RegisterThreadedTest* first_;
  static int count_;
  CcTest::TestFunction* callback_;
  RegisterThreadedTest* prev_;
  const char* name_;
};

// A LocalContext holds a reference to a v8::Context.
class LocalContext {
 public:
313 314
  LocalContext(v8::Isolate* isolate,
               v8::ExtensionConfiguration* extensions = nullptr,
315 316 317
               v8::Local<v8::ObjectTemplate> global_template =
                   v8::Local<v8::ObjectTemplate>(),
               v8::Local<v8::Value> global_object = v8::Local<v8::Value>()) {
318 319 320
    Initialize(isolate, extensions, global_template, global_object);
  }

321
  LocalContext(v8::ExtensionConfiguration* extensions = nullptr,
322 323 324
               v8::Local<v8::ObjectTemplate> global_template =
                   v8::Local<v8::ObjectTemplate>(),
               v8::Local<v8::Value> global_object = v8::Local<v8::Value>()) {
325
    Initialize(CcTest::isolate(), extensions, global_template, global_object);
326 327
  }

328
  virtual ~LocalContext();
329

330 331 332 333
  v8::Context* operator->() {
    return *reinterpret_cast<v8::Context**>(&context_);
  }
  v8::Context* operator*() { return operator->(); }
334 335
  bool IsReady() { return !context_.IsEmpty(); }

336
  v8::Local<v8::Context> local() const {
337
    return v8::Local<v8::Context>::New(isolate_, context_);
338 339 340
  }

 private:
341 342
  void Initialize(v8::Isolate* isolate, v8::ExtensionConfiguration* extensions,
                  v8::Local<v8::ObjectTemplate> global_template,
343
                  v8::Local<v8::Value> global_object);
344

345
  v8::Persistent<v8::Context> context_;
346
  v8::Isolate* isolate_;
347 348
};

349 350

static inline uint16_t* AsciiToTwoByteString(const char* source) {
351
  size_t array_length = strlen(source) + 1;
352
  uint16_t* converted = i::NewArray<uint16_t>(array_length);
353
  for (size_t i = 0; i < array_length; i++) converted[i] = source[i];
354 355 356
  return converted;
}

357 358 359 360 361 362 363
template <typename T>
static inline i::Handle<T> GetGlobal(const char* name) {
  i::Isolate* isolate = CcTest::i_isolate();
  i::Handle<i::String> str_name =
      isolate->factory()->InternalizeUtf8String(name);

  i::Handle<i::Object> value =
364
      i::Object::GetProperty(isolate, isolate->global_object(), str_name)
365 366 367
          .ToHandleChecked();
  return i::Handle<T>::cast(value);
}
368

369 370 371 372
static inline v8::Local<v8::Boolean> v8_bool(bool val) {
  return v8::Boolean::New(v8::Isolate::GetCurrent(), val);
}

373
static inline v8::Local<v8::Value> v8_num(double x) {
374
  return v8::Number::New(v8::Isolate::GetCurrent(), x);
375 376
}

377 378 379
static inline v8::Local<v8::Integer> v8_int(int32_t x) {
  return v8::Integer::New(v8::Isolate::GetCurrent(), x);
}
380

381 382 383 384
static inline v8::Local<v8::BigInt> v8_bigint(int64_t x) {
  return v8::BigInt::New(v8::Isolate::GetCurrent(), x);
}

385
static inline v8::Local<v8::String> v8_str(const char* x) {
386
  return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x).ToLocalChecked();
387 388 389
}


390 391
static inline v8::Local<v8::String> v8_str(v8::Isolate* isolate,
                                           const char* x) {
392
  return v8::String::NewFromUtf8(isolate, x).ToLocalChecked();
393 394 395
}


396 397 398 399 400
static inline v8::Local<v8::Symbol> v8_symbol(const char* name) {
  return v8::Symbol::New(v8::Isolate::GetCurrent(), v8_str(name));
}


401 402
static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
  v8::Local<v8::Script> result;
403 404 405
  CHECK(v8::Script::Compile(v8::Isolate::GetCurrent()->GetCurrentContext(), x)
            .ToLocal(&result));
  return result;
406 407
}

408 409
static inline v8::Local<v8::Script> v8_compile(const char* x) {
  return v8_compile(v8_str(x));
410 411
}

412 413 414 415 416 417 418 419
static inline v8::MaybeLocal<v8::Script> v8_try_compile(
    v8::Local<v8::String> x) {
  return v8::Script::Compile(v8::Isolate::GetCurrent()->GetCurrentContext(), x);
}

static inline v8::MaybeLocal<v8::Script> v8_try_compile(const char* x) {
  return v8_try_compile(v8_str(x));
}
420

421 422 423 424 425
static inline int32_t v8_run_int32value(v8::Local<v8::Script> script) {
  v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
  return script->Run(context).ToLocalChecked()->Int32Value(context).FromJust();
}

426
static inline v8::Local<v8::Script> CompileWithOrigin(
427
    v8::Local<v8::String> source, v8::Local<v8::String> origin_url,
428
    bool is_shared_cross_origin) {
429 430
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::ScriptOrigin origin(isolate, origin_url, 0, 0, is_shared_cross_origin);
431
  v8::ScriptCompiler::Source script_source(source, origin);
432 433
  return v8::ScriptCompiler::Compile(isolate->GetCurrentContext(),
                                     &script_source)
434
      .ToLocalChecked();
435 436 437
}

static inline v8::Local<v8::Script> CompileWithOrigin(
438 439
    v8::Local<v8::String> source, const char* origin_url,
    bool is_shared_cross_origin) {
440
  return CompileWithOrigin(source, v8_str(origin_url), is_shared_cross_origin);
441 442
}

443 444 445
static inline v8::Local<v8::Script> CompileWithOrigin(
    const char* source, const char* origin_url, bool is_shared_cross_origin) {
  return CompileWithOrigin(v8_str(source), v8_str(origin_url),
446
                           is_shared_cross_origin);
447 448 449
}

// Helper functions that compile and run the source.
450 451 452 453 454 455 456 457
static inline v8::MaybeLocal<v8::Value> CompileRun(
    v8::Local<v8::Context> context, const char* source) {
  return v8::Script::Compile(context, v8_str(source))
      .ToLocalChecked()
      ->Run(context);
}


458 459 460
static inline v8::Local<v8::Value> CompileRunChecked(v8::Isolate* isolate,
                                                     const char* source) {
  v8::Local<v8::String> source_string =
461
      v8::String::NewFromUtf8(isolate, source).ToLocalChecked();
462 463 464 465 466 467 468
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
  v8::Local<v8::Script> script =
      v8::Script::Compile(context, source_string).ToLocalChecked();
  return script->Run(context).ToLocalChecked();
}


469 470 471 472 473 474 475 476
static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
  v8::Local<v8::Value> result;
  if (v8_compile(source)
          ->Run(v8::Isolate::GetCurrent()->GetCurrentContext())
          .ToLocal(&result)) {
    return result;
  }
  return v8::Local<v8::Value>();
477 478 479
}


480
// Helper functions that compile and run the source.
481 482
static inline v8::Local<v8::Value> CompileRun(const char* source) {
  return CompileRun(v8_str(source));
483 484 485
}


486 487 488 489 490 491 492 493 494 495 496
static inline v8::Local<v8::Value> CompileRun(
    v8::Local<v8::Context> context, v8::ScriptCompiler::Source* script_source,
    v8::ScriptCompiler::CompileOptions options) {
  v8::Local<v8::Value> result;
  if (v8::ScriptCompiler::Compile(context, script_source, options)
          .ToLocalChecked()
          ->Run(context)
          .ToLocal(&result)) {
    return result;
  }
  return v8::Local<v8::Value>();
497 498
}

499

500
// Helper functions that compile and run the source with given origin.
501 502 503 504
static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
                                                        const char* origin_url,
                                                        int line_number,
                                                        int column_number) {
505
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
506
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
507 508
  v8::ScriptOrigin origin(isolate, v8_str(origin_url), line_number,
                          column_number);
509
  v8::ScriptCompiler::Source script_source(v8_str(source), origin);
510 511
  return CompileRun(context, &script_source,
                    v8::ScriptCompiler::CompileOptions());
512 513 514 515
}


static inline v8::Local<v8::Value> CompileRunWithOrigin(
516
    v8::Local<v8::String> source, const char* origin_url) {
517 518
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
519
  v8::ScriptCompiler::Source script_source(
520
      source, v8::ScriptOrigin(isolate, v8_str(origin_url)));
521 522
  return CompileRun(context, &script_source,
                    v8::ScriptCompiler::CompileOptions());
523 524 525 526 527 528
}


static inline v8::Local<v8::Value> CompileRunWithOrigin(
    const char* source, const char* origin_url) {
  return CompileRunWithOrigin(v8_str(source), origin_url);
529 530
}

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
// Run a ScriptStreamingTask in a separate thread.
class StreamerThread : public v8::base::Thread {
 public:
  static void StartThreadForTaskAndJoin(
      v8::ScriptCompiler::ScriptStreamingTask* task) {
    StreamerThread thread(task);
    CHECK(thread.Start());
    thread.Join();
  }

  explicit StreamerThread(v8::ScriptCompiler::ScriptStreamingTask* task)
      : Thread(Thread::Options()), task_(task) {}

  void Run() override { task_->Run(); }

 private:
  v8::ScriptCompiler::ScriptStreamingTask* task_;
};

550 551
// Takes a JSFunction and runs it through the test version of the optimizing
// pipeline, allocating the temporary compilation artifacts in a given Zone.
552 553 554
// For possible {flags} values, look at OptimizedCompilationInfo::Flag.  If
// {out_broker} is not nullptr, returns the JSHeapBroker via that (transferring
// ownership to the caller).
555 556
i::Handle<i::JSFunction> Optimize(
    i::Handle<i::JSFunction> function, i::Zone* zone, i::Isolate* isolate,
557 558
    uint32_t flags,
    std::unique_ptr<i::compiler::JSHeapBroker>* out_broker = nullptr);
559 560 561 562

static inline void ExpectString(const char* code, const char* expected) {
  v8::Local<v8::Value> result = CompileRun(code);
  CHECK(result->IsString());
563
  v8::String::Utf8Value utf8(v8::Isolate::GetCurrent(), result);
564
  CHECK_EQ(0, strcmp(expected, *utf8));
565 566 567 568 569 570
}


static inline void ExpectInt32(const char* code, int expected) {
  v8::Local<v8::Value> result = CompileRun(code);
  CHECK(result->IsInt32());
571 572 573
  CHECK_EQ(expected,
           result->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext())
               .FromJust());
574 575 576 577 578 579
}


static inline void ExpectBoolean(const char* code, bool expected) {
  v8::Local<v8::Value> result = CompileRun(code);
  CHECK(result->IsBoolean());
580
  CHECK_EQ(expected, result->BooleanValue(v8::Isolate::GetCurrent()));
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
}


static inline void ExpectTrue(const char* code) {
  ExpectBoolean(code, true);
}


static inline void ExpectFalse(const char* code) {
  ExpectBoolean(code, false);
}


static inline void ExpectObject(const char* code,
                                v8::Local<v8::Value> expected) {
  v8::Local<v8::Value> result = CompileRun(code);
  CHECK(result->SameValue(expected));
}


static inline void ExpectUndefined(const char* code) {
  v8::Local<v8::Value> result = CompileRun(code);
  CHECK(result->IsUndefined());
}


607 608 609 610 611 612
static inline void ExpectNull(const char* code) {
  v8::Local<v8::Value> result = CompileRun(code);
  CHECK(result->IsNull());
}


613 614 615 616 617 618
static inline void CheckDoubleEquals(double expected, double actual) {
  const double kEpsilon = 1e-10;
  CHECK_LE(expected, actual + kEpsilon);
  CHECK_GE(expected, actual - kEpsilon);
}

619
static v8::debug::DebugDelegate dummy_delegate;
620

621
static inline void EnableDebugger(v8::Isolate* isolate) {
622
  v8::debug::SetDebugDelegate(isolate, &dummy_delegate);
623 624 625
}


626
static inline void DisableDebugger(v8::Isolate* isolate) {
627
  v8::debug::SetDebugDelegate(isolate, nullptr);
628
}
629 630


631 632
static inline void EmptyMessageQueues(v8::Isolate* isolate) {
  while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(),
633 634
                                       isolate)) {
  }
635 636
}

637
class InitializedHandleScopeImpl;
638

639
class V8_NODISCARD InitializedHandleScope {
640
 public:
641
  explicit InitializedHandleScope(i::Isolate* isolate = nullptr);
642
  ~InitializedHandleScope();
643 644 645 646 647 648

  // Prefixing the below with main_ reduces a lot of naming clashes.
  i::Isolate* main_isolate() { return main_isolate_; }

 private:
  i::Isolate* main_isolate_;
649
  std::unique_ptr<InitializedHandleScopeImpl> initialized_handle_scope_impl_;
650 651
};

652
class V8_NODISCARD HandleAndZoneScope : public InitializedHandleScope {
653
 public:
654
  explicit HandleAndZoneScope(bool support_zone_compression = false);
655
  ~HandleAndZoneScope();
656 657

  // Prefixing the below with main_ reduces a lot of naming clashes.
658
  i::Zone* main_zone() { return main_zone_.get(); }
659 660

 private:
661
  v8::internal::AccountingAllocator allocator_;
662
  std::unique_ptr<i::Zone> main_zone_;
663 664
};

665 666 667 668
class StaticOneByteResource : public v8::String::ExternalOneByteStringResource {
 public:
  explicit StaticOneByteResource(const char* data) : data_(data) {}

669
  ~StaticOneByteResource() override = default;
670

671
  const char* data() const override { return data_; }
672

673
  size_t length() const override { return strlen(data_); }
674 675 676 677 678

 private:
  const char* data_;
};

679
class V8_NODISCARD ManualGCScope {
680 681 682 683
 public:
  ManualGCScope()
      : flag_concurrent_marking_(i::FLAG_concurrent_marking),
        flag_concurrent_sweeping_(i::FLAG_concurrent_sweeping),
684 685
        flag_stress_concurrent_allocation_(
            i::FLAG_stress_concurrent_allocation),
686
        flag_stress_incremental_marking_(i::FLAG_stress_incremental_marking),
687 688 689
        flag_parallel_marking_(i::FLAG_parallel_marking),
        flag_detect_ineffective_gcs_near_heap_limit_(
            i::FLAG_detect_ineffective_gcs_near_heap_limit) {
690 691 692
    i::FLAG_concurrent_marking = false;
    i::FLAG_concurrent_sweeping = false;
    i::FLAG_stress_incremental_marking = false;
693
    i::FLAG_stress_concurrent_allocation = false;
694 695
    // Parallel marking has a dependency on concurrent marking.
    i::FLAG_parallel_marking = false;
696
    i::FLAG_detect_ineffective_gcs_near_heap_limit = false;
697 698 699 700
  }
  ~ManualGCScope() {
    i::FLAG_concurrent_marking = flag_concurrent_marking_;
    i::FLAG_concurrent_sweeping = flag_concurrent_sweeping_;
701
    i::FLAG_stress_concurrent_allocation = flag_stress_concurrent_allocation_;
702
    i::FLAG_stress_incremental_marking = flag_stress_incremental_marking_;
703
    i::FLAG_parallel_marking = flag_parallel_marking_;
704 705
    i::FLAG_detect_ineffective_gcs_near_heap_limit =
        flag_detect_ineffective_gcs_near_heap_limit_;
706 707 708 709 710
  }

 private:
  bool flag_concurrent_marking_;
  bool flag_concurrent_sweeping_;
711
  bool flag_stress_concurrent_allocation_;
712
  bool flag_stress_incremental_marking_;
713
  bool flag_parallel_marking_;
714
  bool flag_detect_ineffective_gcs_near_heap_limit_;
715 716
};

717 718 719 720 721
// This is an abstract base class that can be overridden to implement a test
// platform. It delegates all operations to a given platform at the time
// of construction.
class TestPlatform : public v8::Platform {
 public:
722 723 724
  TestPlatform(const TestPlatform&) = delete;
  TestPlatform& operator=(const TestPlatform&) = delete;

725
  // v8::Platform implementation.
726 727 728 729
  v8::PageAllocator* GetPageAllocator() override {
    return old_platform_->GetPageAllocator();
  }

730 731 732 733
  void OnCriticalMemoryPressure() override {
    old_platform_->OnCriticalMemoryPressure();
  }

734 735 736 737
  bool OnCriticalMemoryPressure(size_t length) override {
    return old_platform_->OnCriticalMemoryPressure(length);
  }

738 739 740 741
  int NumberOfWorkerThreads() override {
    return old_platform_->NumberOfWorkerThreads();
  }

742 743 744 745 746
  std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
      v8::Isolate* isolate) override {
    return old_platform_->GetForegroundTaskRunner(isolate);
  }

747 748
  void CallOnWorkerThread(std::unique_ptr<v8::Task> task) override {
    old_platform_->CallOnWorkerThread(std::move(task));
749 750
  }

751 752 753 754 755
  void CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task,
                                 double delay_in_seconds) override {
    old_platform_->CallDelayedOnWorkerThread(std::move(task), delay_in_seconds);
  }

756 757 758 759 760 761
  std::unique_ptr<v8::JobHandle> PostJob(
      v8::TaskPriority priority,
      std::unique_ptr<v8::JobTask> job_task) override {
    return old_platform_->PostJob(priority, std::move(job_task));
  }

762 763 764 765
  double MonotonicallyIncreasingTime() override {
    return old_platform_->MonotonicallyIncreasingTime();
  }

766 767 768 769
  double CurrentClockTimeMillis() override {
    return old_platform_->CurrentClockTimeMillis();
  }

770 771 772 773 774 775 776 777 778 779
  bool IdleTasksEnabled(v8::Isolate* isolate) override {
    return old_platform_->IdleTasksEnabled(isolate);
  }

  v8::TracingController* GetTracingController() override {
    return old_platform_->GetTracingController();
  }

 protected:
  TestPlatform() : old_platform_(i::V8::GetCurrentPlatform()) {}
780
  ~TestPlatform() override { i::V8::SetPlatformForTesting(old_platform_); }
781 782 783 784 785 786 787

  v8::Platform* old_platform() const { return old_platform_; }

 private:
  v8::Platform* old_platform_;
};

788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
#if defined(USE_SIMULATOR)
class SimulatorHelper {
 public:
  inline bool Init(v8::Isolate* isolate) {
    simulator_ = reinterpret_cast<v8::internal::Isolate*>(isolate)
                     ->thread_local_top()
                     ->simulator_;
    // Check if there is active simulator.
    return simulator_ != nullptr;
  }

  inline void FillRegisters(v8::RegisterState* state) {
#if V8_TARGET_ARCH_ARM
    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
    state->sp = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::sp));
    state->fp = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::r11));
    state->lr = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::lr));
#elif V8_TARGET_ARCH_ARM64
    if (simulator_->sp() == 0 || simulator_->fp() == 0) {
      // It's possible that the simulator is interrupted while it is updating
      // the sp or fp register. ARM64 simulator does this in two steps:
      // first setting it to zero and then setting it to a new value.
      // Bailout if sp/fp doesn't contain the new value.
      return;
    }
    state->pc = reinterpret_cast<void*>(simulator_->pc());
    state->sp = reinterpret_cast<void*>(simulator_->sp());
    state->fp = reinterpret_cast<void*>(simulator_->fp());
    state->lr = reinterpret_cast<void*>(simulator_->lr());
#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
    state->sp = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::sp));
    state->fp = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::fp));
#elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
    state->sp = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::sp));
    state->fp = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::fp));
    state->lr = reinterpret_cast<void*>(simulator_->get_lr());
#elif V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
    state->sp = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::sp));
    state->fp = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::fp));
    state->lr = reinterpret_cast<void*>(
        simulator_->get_register(v8::internal::Simulator::ra));
#endif
  }

 private:
  v8::internal::Simulator* simulator_;
};
#endif  // USE_SIMULATOR

849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
// The following should correspond to Chromium's kV8DOMWrapperTypeIndex and
// kV8DOMWrapperObjectIndex.
static const int kV8WrapperTypeIndex = 0;
static const int kV8WrapperObjectIndex = 1;

enum class ApiCheckerResult : uint8_t {
  kNotCalled = 0,
  kSlowCalled = 1 << 0,
  kFastCalled = 1 << 1,
};
using ApiCheckerResultFlags = v8::base::Flags<ApiCheckerResult>;
DEFINE_OPERATORS_FOR_FLAGS(ApiCheckerResultFlags)

bool IsValidUnwrapObject(v8::Object* object);

864
template <typename T>
865
T* GetInternalField(v8::Object* wrapper) {
866
  assert(kV8WrapperObjectIndex < wrapper->InternalFieldCount());
867
  return reinterpret_cast<T*>(
868
      wrapper->GetAlignedPointerFromInternalField(kV8WrapperObjectIndex));
869 870
}

871
#endif  // ifndef CCTEST_H_