Line data Source code
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 : #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"
34 : #include "src/trap-handler/trap-handler.h"
35 : #include "test/cctest/print-extension.h"
36 : #include "test/cctest/profiler-extension.h"
37 : #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 : #endif
44 : #endif
45 :
46 : enum InitializationState { kUnset, kUninitialized, kInitialized };
47 : 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 : v8::ArrayBuffer::Allocator* CcTest::allocator_ = nullptr;
54 : v8::Isolate* CcTest::isolate_ = nullptr;
55 :
56 101868810 : CcTest::CcTest(TestFunction* callback, const char* file, const char* name,
57 : bool enabled, bool initialize)
58 : : callback_(callback),
59 : name_(name),
60 : enabled_(enabled),
61 : initialize_(initialize),
62 101868810 : prev_(last_) {
63 : // Find the base name of this test (const_cast required on Windows).
64 : char *basename = strrchr(const_cast<char *>(file), '/');
65 101868810 : if (!basename) {
66 : basename = strrchr(const_cast<char *>(file), '\\');
67 : }
68 101868810 : if (!basename) {
69 0 : basename = v8::internal::StrDup(file);
70 : } else {
71 101868810 : basename = v8::internal::StrDup(basename + 1);
72 : }
73 : // Drop the extension, if there is one.
74 : char *extension = strrchr(basename, '.');
75 101868810 : if (extension) *extension = 0;
76 : // Install this test in the list of tests
77 101868810 : file_ = basename;
78 101868810 : prev_ = last_;
79 101868810 : last_ = this;
80 101868810 : }
81 :
82 :
83 23717 : void CcTest::Run() {
84 23717 : if (!initialize_) {
85 192 : CHECK_NE(initialization_state_, kInitialized);
86 192 : initialization_state_ = kUninitialized;
87 192 : CHECK_NULL(CcTest::isolate_);
88 : } else {
89 23525 : CHECK_NE(initialization_state_, kUninitialized);
90 23525 : initialization_state_ = kInitialized;
91 23525 : if (isolate_ == nullptr) {
92 : v8::Isolate::CreateParams create_params;
93 23525 : create_params.array_buffer_allocator = allocator_;
94 23525 : isolate_ = v8::Isolate::New(create_params);
95 : }
96 23525 : isolate_->Enter();
97 : }
98 : #ifdef DEBUG
99 : const size_t active_isolates = i::Isolate::non_disposed_isolates();
100 : #endif // DEBUG
101 23717 : callback_();
102 : #ifdef DEBUG
103 : // This DCHECK ensures that all Isolates are properly disposed after finishing
104 : // the test. Stray Isolates lead to stray tasks in the platform which can
105 : // interact weirdly when swapping in new platforms (for testing) or during
106 : // shutdown.
107 : DCHECK_EQ(active_isolates, i::Isolate::non_disposed_isolates());
108 : #endif // DEBUG
109 23699 : if (initialize_) {
110 23507 : if (v8::Locker::IsActive()) {
111 124 : v8::Locker locker(isolate_);
112 124 : EmptyMessageQueues(isolate_);
113 : } else {
114 23383 : EmptyMessageQueues(isolate_);
115 : }
116 23507 : isolate_->Exit();
117 : }
118 23699 : }
119 :
120 652986 : i::Heap* CcTest::heap() { return i_isolate()->heap(); }
121 :
122 2366 : void CcTest::CollectGarbage(i::AllocationSpace space) {
123 2366 : heap()->CollectGarbage(space, i::GarbageCollectionReason::kTesting);
124 2366 : }
125 :
126 3090 : void CcTest::CollectAllGarbage() {
127 3090 : CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
128 3090 : }
129 :
130 3728 : void CcTest::CollectAllGarbage(int flags) {
131 3728 : heap()->CollectAllGarbage(flags, i::GarbageCollectionReason::kTesting);
132 3728 : }
133 :
134 301 : void CcTest::CollectAllAvailableGarbage() {
135 301 : heap()->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
136 301 : }
137 :
138 29 : v8::base::RandomNumberGenerator* CcTest::random_number_generator() {
139 29 : return InitIsolateOnce()->random_number_generator();
140 : }
141 :
142 7899 : v8::Local<v8::Object> CcTest::global() {
143 15798 : return isolate()->GetCurrentContext()->Global();
144 : }
145 :
146 14949 : void CcTest::InitializeVM() {
147 14949 : CHECK(!v8::base::Relaxed_Load(&isolate_used_));
148 14949 : CHECK(!initialize_called_);
149 14949 : initialize_called_ = true;
150 14949 : v8::HandleScope handle_scope(CcTest::isolate());
151 29898 : v8::Context::New(CcTest::isolate())->Enter();
152 14949 : }
153 :
154 0 : void CcTest::TearDown() {
155 23700 : if (isolate_ != nullptr) isolate_->Dispose();
156 0 : }
157 :
158 88 : v8::Local<v8::Context> CcTest::NewContext(CcTestExtensionFlags extensions,
159 : v8::Isolate* isolate) {
160 : const char* extension_names[kMaxExtensions];
161 : int extension_count = 0;
162 : #define CHECK_EXTENSION_FLAG(Name, Id) \
163 : if (extensions.Contains(Name##_ID)) extension_names[extension_count++] = Id;
164 352 : EXTENSION_LIST(CHECK_EXTENSION_FLAG)
165 : #undef CHECK_EXTENSION_FLAG
166 : v8::ExtensionConfiguration config(extension_count, extension_names);
167 88 : v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
168 88 : CHECK(!context.IsEmpty());
169 88 : return context;
170 : }
171 :
172 :
173 5 : void CcTest::DisableAutomaticDispose() {
174 5 : CHECK_EQ(kUninitialized, initialization_state_);
175 5 : disable_automatic_dispose_ = true;
176 5 : }
177 :
178 9733 : LocalContext::~LocalContext() {
179 9733 : v8::HandleScope scope(isolate_);
180 19466 : v8::Local<v8::Context>::New(isolate_, context_)->Exit();
181 9733 : context_.Reset();
182 9733 : }
183 :
184 9733 : void LocalContext::Initialize(v8::Isolate* isolate,
185 : v8::ExtensionConfiguration* extensions,
186 : v8::Local<v8::ObjectTemplate> global_template,
187 : v8::Local<v8::Value> global_object) {
188 9733 : v8::HandleScope scope(isolate);
189 : v8::Local<v8::Context> context =
190 9733 : v8::Context::New(isolate, extensions, global_template, global_object);
191 : context_.Reset(isolate, context);
192 9733 : context->Enter();
193 : // We can't do this later perhaps because of a fatal error.
194 9733 : isolate_ = isolate;
195 9733 : }
196 :
197 : // This indirection is needed because HandleScopes cannot be heap-allocated, and
198 : // we don't want any unnecessary #includes in cctest.h.
199 : class InitializedHandleScopeImpl {
200 : public:
201 : explicit InitializedHandleScopeImpl(i::Isolate* isolate)
202 : : handle_scope_(isolate) {}
203 :
204 : private:
205 : i::HandleScope handle_scope_;
206 : };
207 :
208 447909 : InitializedHandleScope::InitializedHandleScope()
209 447909 : : main_isolate_(CcTest::InitIsolateOnce()),
210 : initialized_handle_scope_impl_(
211 895818 : new InitializedHandleScopeImpl(main_isolate_)) {}
212 :
213 4104 : InitializedHandleScope::~InitializedHandleScope() {}
214 :
215 445857 : HandleAndZoneScope::HandleAndZoneScope()
216 891714 : : main_zone_(new i::Zone(&allocator_, ZONE_NAME)) {}
217 :
218 1337571 : HandleAndZoneScope::~HandleAndZoneScope() {}
219 :
220 12886 : static void PrintTestList(CcTest* current) {
221 8592 : if (current == nullptr) return;
222 4295 : PrintTestList(current->prev());
223 : printf("%s/%s\n", current->file(), current->name());
224 : }
225 :
226 :
227 : static void SuggestTestHarness(int tests) {
228 23717 : if (tests == 0) return;
229 : printf("Running multiple tests in sequence is deprecated and may cause "
230 : "bogus failure. Consider using tools/run-tests.py instead.\n");
231 : }
232 :
233 :
234 23718 : int main(int argc, char* argv[]) {
235 : #if V8_OS_WIN
236 : UINT new_flags =
237 : SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
238 : UINT existing_flags = SetErrorMode(new_flags);
239 : SetErrorMode(existing_flags | new_flags);
240 : #if V8_CC_MSVC
241 : _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
242 : _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
243 : _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
244 : _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
245 : _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
246 : _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
247 : _set_error_mode(_OUT_TO_STDERR);
248 : #endif // V8_CC_MSVC
249 : #endif // V8_OS_WIN
250 :
251 : // hack to print cctest specific flags
252 129522 : for (int i = 1; i < argc; i++) {
253 105804 : char* arg = argv[i];
254 105804 : if ((strcmp(arg, "--help") == 0) || (strcmp(arg, "-h") == 0)) {
255 0 : printf("Usage: %s [--list] [[V8_FLAGS] CCTEST]\n", argv[0]);
256 : printf("\n");
257 : printf("Options:\n");
258 : printf(" --list: list all cctests\n");
259 : printf(" CCTEST: cctest identfier returned by --list\n");
260 : printf(" D8_FLAGS: see d8 output below\n");
261 : printf("\n\n");
262 : }
263 : }
264 :
265 23718 : v8::V8::InitializeICUDefaultLocation(argv[0]);
266 23718 : v8::Platform* platform = v8::platform::CreateDefaultPlatform();
267 23718 : v8::V8::InitializePlatform(platform);
268 23718 : v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
269 23718 : v8::V8::Initialize();
270 23718 : v8::V8::InitializeExternalStartupData(argv[0]);
271 :
272 23718 : if (i::trap_handler::UseTrapHandler()) {
273 2475 : v8::V8::RegisterDefaultSignalHandler();
274 : }
275 :
276 : CcTest::set_array_buffer_allocator(
277 23718 : v8::ArrayBuffer::Allocator::NewDefaultAllocator());
278 :
279 23718 : i::PrintExtension print_extension;
280 23718 : v8::RegisterExtension(&print_extension);
281 23718 : i::ProfilerExtension profiler_extension;
282 23718 : v8::RegisterExtension(&profiler_extension);
283 23718 : i::TraceExtension trace_extension;
284 23718 : v8::RegisterExtension(&trace_extension);
285 :
286 : int tests_run = 0;
287 : bool print_run_count = true;
288 54137 : for (int i = 1; i < argc; i++) {
289 30437 : char* arg = argv[i];
290 30437 : if (strcmp(arg, "--list") == 0) {
291 1 : PrintTestList(CcTest::last());
292 : print_run_count = false;
293 :
294 : } else {
295 30436 : char* arg_copy = v8::internal::StrDup(arg);
296 : char* testname = strchr(arg_copy, '/');
297 30436 : if (testname) {
298 : // Split the string in two by nulling the slash and then run
299 : // exact matches.
300 23717 : *testname = 0;
301 : char* file = arg_copy;
302 23717 : char* name = testname + 1;
303 310128259 : CcTest* test = CcTest::last();
304 101888117 : while (test != nullptr) {
305 101840701 : if (test->enabled()
306 101840701 : && strcmp(test->file(), file) == 0
307 106446875 : && strcmp(test->name(), name) == 0) {
308 23717 : SuggestTestHarness(tests_run++);
309 23717 : test->Run();
310 : }
311 : test = test->prev();
312 : }
313 :
314 : } else {
315 : // Run all tests with the specified file or test name.
316 : char* file_or_name = arg_copy;
317 115432420 : CcTest* test = CcTest::last();
318 28871543 : while (test != nullptr) {
319 28858105 : if (test->enabled()
320 57716210 : && (strcmp(test->file(), file_or_name) == 0
321 28858105 : || strcmp(test->name(), file_or_name) == 0)) {
322 0 : SuggestTestHarness(tests_run++);
323 0 : test->Run();
324 : }
325 : test = test->prev();
326 : }
327 : }
328 : v8::internal::DeleteArray<char>(arg_copy);
329 : }
330 : }
331 23700 : if (print_run_count && tests_run != 1)
332 : printf("Ran %i tests.\n", tests_run);
333 : CcTest::TearDown();
334 : // TODO(svenpanne) See comment above.
335 : // if (!disable_automatic_dispose_) v8::V8::Dispose();
336 23700 : v8::V8::ShutdownPlatform();
337 23700 : delete platform;
338 : return 0;
339 : }
340 :
341 : RegisterThreadedTest* RegisterThreadedTest::first_ = nullptr;
342 71154 : int RegisterThreadedTest::count_ = 0;
|