cctest.cc 11.5 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_ = NULL;
51
bool CcTest::initialize_called_ = false;
52
v8::base::Atomic32 CcTest::isolate_used_ = 0;
53
v8::ArrayBuffer::Allocator* CcTest::allocator_ = NULL;
54 55
v8::Isolate* CcTest::isolate_ = NULL;

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 85
void CcTest::Run() {
  if (!initialize_) {
    CHECK(initialization_state_ != kInitialized);
86
    initialization_state_ = kUninitialized;
87
    CHECK(CcTest::isolate_ == NULL);
88
  } else {
89
    CHECK(initialization_state_ != kUninitialized);
90
    initialization_state_ = kInitialized;
91
    if (isolate_ == NULL) {
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 99
  }
  callback_();
  if (initialize_) {
100 101 102 103 104 105
    if (v8::Locker::IsActive()) {
      v8::Locker locker(isolate_);
      EmptyMessageQueues(isolate_);
    } else {
      EmptyMessageQueues(isolate_);
    }
106
    isolate_->Exit();
107 108 109
  }
}

110 111
i::Heap* CcTest::heap() { return i_isolate()->heap(); }

112 113 114 115
void CcTest::CollectGarbage(i::AllocationSpace space) {
  heap()->CollectGarbage(space, i::GarbageCollectionReason::kTesting);
}

116 117 118 119
void CcTest::CollectAllGarbage() {
  CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
}

120 121 122 123 124 125 126 127
void CcTest::CollectAllGarbage(int flags) {
  heap()->CollectAllGarbage(flags, i::GarbageCollectionReason::kTesting);
}

void CcTest::CollectAllAvailableGarbage() {
  heap()->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
}

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
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() {
  CHECK(!v8::base::NoBarrier_Load(&isolate_used_));
  CHECK(!initialize_called_);
  initialize_called_ = true;
  v8::HandleScope handle_scope(CcTest::isolate());
  v8::Context::New(CcTest::isolate())->Enter();
}

void CcTest::TearDown() {
  if (isolate_ != NULL) isolate_->Dispose();
}
147

148 149 150 151 152 153 154 155
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
156
    v8::ExtensionConfiguration config(extension_count, extension_names);
157
    v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
158 159
    CHECK(!context.IsEmpty());
    return context;
160 161 162
}


163
void CcTest::DisableAutomaticDispose() {
164
  CHECK_EQ(kUninitialized, initialization_state_);
165 166 167
  disable_automatic_dispose_ = true;
}

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
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_)) {}

InitializedHandleScope::~InitializedHandleScope() {}

HandleAndZoneScope::HandleAndZoneScope()
206
    : main_zone_(new i::Zone(&allocator_, ZONE_NAME)) {}
207 208

HandleAndZoneScope::~HandleAndZoneScope() {}
209

210 211 212
static void PrintTestList(CcTest* current) {
  if (current == NULL) return;
  PrintTestList(current->prev());
213
  printf("%s/%s\n", current->file(), current->name());
214 215 216
}


217
class CcTestArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
binji's avatar
binji committed
218
  virtual void* Allocate(size_t length) {
219
    void* data = AllocateUninitialized(length == 0 ? 1 : length);
binji's avatar
binji committed
220 221
    return data == NULL ? data : memset(data, 0, length);
  }
222 223 224
  virtual void* AllocateUninitialized(size_t length) {
    return malloc(length == 0 ? 1 : length);
  }
225 226 227
  virtual void Free(void* data, size_t length) { free(data); }
  // TODO(dslomov): Remove when v8:2823 is fixed.
  virtual void Free(void* data) { UNREACHABLE(); }
228 229 230
};


231 232 233 234 235 236 237
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");
}


238
int main(int argc, char* argv[]) {
239
#if V8_OS_WIN
240 241 242 243
  UINT new_flags =
      SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
  UINT existing_flags = SetErrorMode(new_flags);
  SetErrorMode(existing_flags | new_flags);
244
#if V8_CC_MSVC
245 246 247 248 249 250 251
  _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);
252 253
#endif  // V8_CC_MSVC
#endif  // V8_OS_WIN
254

255 256 257 258 259 260 261 262 263 264 265 266 267 268
  // 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");
    }
  }

269
  v8::V8::InitializeICUDefaultLocation(argv[0]);
270
  v8::Platform* platform = v8::platform::CreateDefaultPlatform();
271
  v8::V8::InitializePlatform(platform);
272
  v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
273
  v8::V8::Initialize();
vogelheim's avatar
vogelheim committed
274
  v8::V8::InitializeExternalStartupData(argv[0]);
275

eholk's avatar
eholk committed
276 277 278 279
  if (i::trap_handler::UseTrapHandler()) {
    v8::V8::RegisterDefaultSignalHandler();
  }

280
  CcTestArrayBufferAllocator array_buffer_allocator;
281
  CcTest::set_array_buffer_allocator(&array_buffer_allocator);
282

283 284 285 286 287 288 289
  i::PrintExtension print_extension;
  v8::RegisterExtension(&print_extension);
  i::ProfilerExtension profiler_extension;
  v8::RegisterExtension(&profiler_extension);
  i::TraceExtension trace_extension;
  v8::RegisterExtension(&trace_extension);

290 291 292 293 294 295 296
  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;
297

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

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

RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
int RegisterThreadedTest::count_ = 0;