cctest.cc 11.9 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
// 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.

28
#include "include/v8.h"
29
#include "test/cctest/cctest.h"
30

31
#include "include/libplatform/libplatform.h"
32
#include "src/debug/debug.h"
33
#include "src/objects-inl.h"
eholk's avatar
eholk committed
34
#include "src/trap-handler/trap-handler.h"
35 36 37
#include "test/cctest/print-extension.h"
#include "test/cctest/profiler-extension.h"
#include "test/cctest/trace-extension.h"
38

39
#if V8_OS_WIN
40
#include <windows.h>  // NOLINT
41
#if V8_CC_MSVC
42
#include <crtdbg.h>
43 44
#endif
#endif
45

46 47
enum InitializationState { kUnset, kUninitialized, kInitialized };
static InitializationState initialization_state_ = kUnset;
48
static bool disable_automatic_dispose_ = false;
49

50
CcTest* CcTest::last_ = nullptr;
51
bool CcTest::initialize_called_ = false;
52
v8::base::Atomic32 CcTest::isolate_used_ = 0;
53 54
v8::ArrayBuffer::Allocator* CcTest::allocator_ = nullptr;
v8::Isolate* CcTest::isolate_ = nullptr;
55

56
CcTest::CcTest(TestFunction* callback, const char* file, const char* name,
57 58 59 60 61 62
               bool enabled, bool initialize)
    : callback_(callback),
      name_(name),
      enabled_(enabled),
      initialize_(initialize),
      prev_(last_) {
63 64 65 66 67 68
  // Find the base name of this test (const_cast required on Windows).
  char *basename = strrchr(const_cast<char *>(file), '/');
  if (!basename) {
    basename = strrchr(const_cast<char *>(file), '\\');
  }
  if (!basename) {
69
    basename = v8::internal::StrDup(file);
70
  } else {
71
    basename = v8::internal::StrDup(basename + 1);
72 73 74 75 76 77
  }
  // Drop the extension, if there is one.
  char *extension = strrchr(basename, '.');
  if (extension) *extension = 0;
  // Install this test in the list of tests
  file_ = basename;
78 79
  prev_ = last_;
  last_ = this;
80 81 82
}


83 84
void CcTest::Run() {
  if (!initialize_) {
85
    CHECK_NE(initialization_state_, kInitialized);
86
    initialization_state_ = kUninitialized;
87
    CHECK_NULL(CcTest::isolate_);
88
  } else {
89
    CHECK_NE(initialization_state_, kUninitialized);
90
    initialization_state_ = kInitialized;
91
    if (isolate_ == nullptr) {
92 93 94
      v8::Isolate::CreateParams create_params;
      create_params.array_buffer_allocator = allocator_;
      isolate_ = v8::Isolate::New(create_params);
95
    }
96
    isolate_->Enter();
97
  }
98
  i::FLAG_cpu_profiler_logging = true;
99 100 101
#ifdef DEBUG
  const size_t active_isolates = i::Isolate::non_disposed_isolates();
#endif  // DEBUG
102
  callback_();
103 104 105 106 107 108 109
#ifdef DEBUG
  // This DCHECK ensures that all Isolates are properly disposed after finishing
  // the test. Stray Isolates lead to stray tasks in the platform which can
  // interact weirdly when swapping in new platforms (for testing) or during
  // shutdown.
  DCHECK_EQ(active_isolates, i::Isolate::non_disposed_isolates());
#endif  // DEBUG
110
  if (initialize_) {
111 112 113 114 115 116
    if (v8::Locker::IsActive()) {
      v8::Locker locker(isolate_);
      EmptyMessageQueues(isolate_);
    } else {
      EmptyMessageQueues(isolate_);
    }
117
    isolate_->Exit();
118 119 120
  }
}

121 122
i::Heap* CcTest::heap() { return i_isolate()->heap(); }

123 124 125 126
void CcTest::CollectGarbage(i::AllocationSpace space) {
  heap()->CollectGarbage(space, i::GarbageCollectionReason::kTesting);
}

127 128 129 130
void CcTest::CollectAllGarbage(i::Isolate* isolate) {
  i::Isolate* iso = isolate ? isolate : i_isolate();
  iso->heap()->CollectAllGarbage(i::Heap::kNoGCFlags,
                                 i::GarbageCollectionReason::kTesting);
131 132
}

133 134 135
void CcTest::CollectAllAvailableGarbage(i::Isolate* isolate) {
  i::Isolate* iso = isolate ? isolate : i_isolate();
  iso->heap()->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
136 137
}

138 139 140 141
void CcTest::PreciseCollectAllGarbage(i::Isolate* isolate) {
  i::Isolate* iso = isolate ? isolate : i_isolate();
  iso->heap()->PreciseCollectAllGarbage(i::Heap::kNoGCFlags,
                                        i::GarbageCollectionReason::kTesting);
142 143
}

144 145 146 147 148 149 150 151 152
v8::base::RandomNumberGenerator* CcTest::random_number_generator() {
  return InitIsolateOnce()->random_number_generator();
}

v8::Local<v8::Object> CcTest::global() {
  return isolate()->GetCurrentContext()->Global();
}

void CcTest::InitializeVM() {
153
  CHECK(!v8::base::Relaxed_Load(&isolate_used_));
154 155 156 157 158 159 160
  CHECK(!initialize_called_);
  initialize_called_ = true;
  v8::HandleScope handle_scope(CcTest::isolate());
  v8::Context::New(CcTest::isolate())->Enter();
}

void CcTest::TearDown() {
161
  if (isolate_ != nullptr) isolate_->Dispose();
162
}
163

164 165 166 167 168 169 170 171
v8::Local<v8::Context> CcTest::NewContext(CcTestExtensionFlags extensions,
                                          v8::Isolate* isolate) {
    const char* extension_names[kMaxExtensions];
    int extension_count = 0;
  #define CHECK_EXTENSION_FLAG(Name, Id) \
    if (extensions.Contains(Name##_ID)) extension_names[extension_count++] = Id;
    EXTENSION_LIST(CHECK_EXTENSION_FLAG)
  #undef CHECK_EXTENSION_FLAG
172
    v8::ExtensionConfiguration config(extension_count, extension_names);
173
    v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
174 175
    CHECK(!context.IsEmpty());
    return context;
176 177 178
}


179
void CcTest::DisableAutomaticDispose() {
180
  CHECK_EQ(kUninitialized, initialization_state_);
181 182 183
  disable_automatic_dispose_ = true;
}

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
LocalContext::~LocalContext() {
  v8::HandleScope scope(isolate_);
  v8::Local<v8::Context>::New(isolate_, context_)->Exit();
  context_.Reset();
}

void LocalContext::Initialize(v8::Isolate* isolate,
                              v8::ExtensionConfiguration* extensions,
                              v8::Local<v8::ObjectTemplate> global_template,
                              v8::Local<v8::Value> global_object) {
  v8::HandleScope scope(isolate);
  v8::Local<v8::Context> context =
      v8::Context::New(isolate, extensions, global_template, global_object);
  context_.Reset(isolate, context);
  context->Enter();
  // We can't do this later perhaps because of a fatal error.
  isolate_ = isolate;
}

// This indirection is needed because HandleScopes cannot be heap-allocated, and
// we don't want any unnecessary #includes in cctest.h.
class InitializedHandleScopeImpl {
 public:
  explicit InitializedHandleScopeImpl(i::Isolate* isolate)
      : handle_scope_(isolate) {}

 private:
  i::HandleScope handle_scope_;
};

InitializedHandleScope::InitializedHandleScope()
    : main_isolate_(CcTest::InitIsolateOnce()),
      initialized_handle_scope_impl_(
          new InitializedHandleScopeImpl(main_isolate_)) {}

219
InitializedHandleScope::~InitializedHandleScope() = default;
220 221

HandleAndZoneScope::HandleAndZoneScope()
222
    : main_zone_(new i::Zone(&allocator_, ZONE_NAME)) {}
223

224
HandleAndZoneScope::~HandleAndZoneScope() = default;
225

226
static void PrintTestList(CcTest* current) {
227
  if (current == nullptr) return;
228
  PrintTestList(current->prev());
229
  printf("%s/%s\n", current->file(), current->name());
230 231 232
}


233 234 235 236 237 238 239
static void SuggestTestHarness(int tests) {
  if (tests == 0) return;
  printf("Running multiple tests in sequence is deprecated and may cause "
         "bogus failure.  Consider using tools/run-tests.py instead.\n");
}


240
int main(int argc, char* argv[]) {
241
#if V8_OS_WIN
242 243 244 245
  UINT new_flags =
      SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
  UINT existing_flags = SetErrorMode(new_flags);
  SetErrorMode(existing_flags | new_flags);
246
#if V8_CC_MSVC
247 248 249 250 251 252 253
  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
  _set_error_mode(_OUT_TO_STDERR);
254 255
#endif  // V8_CC_MSVC
#endif  // V8_OS_WIN
256

257 258 259 260 261 262 263 264 265 266 267 268 269 270
  // hack to print cctest specific flags
  for (int i = 1; i < argc; i++) {
    char* arg = argv[i];
    if ((strcmp(arg, "--help") == 0) || (strcmp(arg, "-h") == 0)) {
      printf("Usage: %s [--list] [[V8_FLAGS] CCTEST]\n", argv[0]);
      printf("\n");
      printf("Options:\n");
      printf("  --list:   list all cctests\n");
      printf("  CCTEST:   cctest identfier returned by --list\n");
      printf("  D8_FLAGS: see d8 output below\n");
      printf("\n\n");
    }
  }

271
  v8::V8::InitializeICUDefaultLocation(argv[0]);
272 273
  std::unique_ptr<v8::Platform> platform(v8::platform::NewDefaultPlatform());
  v8::V8::InitializePlatform(platform.get());
274
  v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
275
  v8::V8::Initialize();
vogelheim's avatar
vogelheim committed
276
  v8::V8::InitializeExternalStartupData(argv[0]);
277

278 279 280
  if (V8_TRAP_HANDLER_SUPPORTED && i::FLAG_wasm_trap_handler) {
    constexpr bool use_default_signal_handler = true;
    CHECK(v8::V8::EnableWebAssemblyTrapHandler(use_default_signal_handler));
eholk's avatar
eholk committed
281 282
  }

283 284
  CcTest::set_array_buffer_allocator(
      v8::ArrayBuffer::Allocator::NewDefaultAllocator());
285

286 287 288 289 290 291 292
  i::PrintExtension print_extension;
  v8::RegisterExtension(&print_extension);
  i::ProfilerExtension profiler_extension;
  v8::RegisterExtension(&profiler_extension);
  i::TraceExtension trace_extension;
  v8::RegisterExtension(&trace_extension);

293 294 295 296 297 298 299
  int tests_run = 0;
  bool print_run_count = true;
  for (int i = 1; i < argc; i++) {
    char* arg = argv[i];
    if (strcmp(arg, "--list") == 0) {
      PrintTestList(CcTest::last());
      print_run_count = false;
300

301
    } else {
302
      char* arg_copy = v8::internal::StrDup(arg);
303 304 305 306 307
      char* testname = strchr(arg_copy, '/');
      if (testname) {
        // Split the string in two by nulling the slash and then run
        // exact matches.
        *testname = 0;
308 309 310
        char* file = arg_copy;
        char* name = testname + 1;
        CcTest* test = CcTest::last();
311
        while (test != nullptr) {
312 313 314
          if (test->enabled()
              && strcmp(test->file(), file) == 0
              && strcmp(test->name(), name) == 0) {
315
            SuggestTestHarness(tests_run++);
316 317 318 319 320
            test->Run();
          }
          test = test->prev();
        }

321 322
      } else {
        // Run all tests with the specified file or test name.
323 324
        char* file_or_name = arg_copy;
        CcTest* test = CcTest::last();
325
        while (test != nullptr) {
326 327 328
          if (test->enabled()
              && (strcmp(test->file(), file_or_name) == 0
                  || strcmp(test->name(), file_or_name) == 0)) {
329
            SuggestTestHarness(tests_run++);
330 331 332 333
            test->Run();
          }
          test = test->prev();
        }
334
      }
335
      v8::internal::DeleteArray<char>(arg_copy);
336
    }
337
  }
338 339
  if (print_run_count && tests_run != 1)
    printf("Ran %i tests.\n", tests_run);
340
  CcTest::TearDown();
341 342
  // TODO(svenpanne) See comment above.
  // if (!disable_automatic_dispose_) v8::V8::Dispose();
343
  v8::V8::ShutdownPlatform();
344
  return 0;
345
}
346

347
RegisterThreadedTest* RegisterThreadedTest::first_ = nullptr;
348
int RegisterThreadedTest::count_ = 0;