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 162257662 : 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 162257662 : prev_(last_) {
63 : // Find the base name of this test (const_cast required on Windows).
64 : char *basename = strrchr(const_cast<char *>(file), '/');
65 162257662 : if (!basename) {
66 : basename = strrchr(const_cast<char *>(file), '\\');
67 : }
68 162257662 : if (!basename) {
69 0 : basename = v8::internal::StrDup(file);
70 : } else {
71 162257662 : basename = v8::internal::StrDup(basename + 1);
72 : }
73 : // Drop the extension, if there is one.
74 : char *extension = strrchr(basename, '.');
75 162257662 : if (extension) *extension = 0;
76 : // Install this test in the list of tests
77 162257662 : file_ = basename;
78 162257662 : prev_ = last_;
79 162257662 : last_ = this;
80 162257662 : }
81 :
82 :
83 28335 : void CcTest::Run() {
84 28335 : if (!initialize_) {
85 376 : CHECK_NE(initialization_state_, kInitialized);
86 376 : initialization_state_ = kUninitialized;
87 376 : CHECK_NULL(CcTest::isolate_);
88 : } else {
89 27959 : CHECK_NE(initialization_state_, kUninitialized);
90 27959 : initialization_state_ = kInitialized;
91 27959 : if (isolate_ == nullptr) {
92 : v8::Isolate::CreateParams create_params;
93 27959 : create_params.array_buffer_allocator = allocator_;
94 27959 : isolate_ = v8::Isolate::New(create_params);
95 : }
96 27959 : isolate_->Enter();
97 : }
98 : #ifdef DEBUG
99 : const size_t active_isolates = i::Isolate::non_disposed_isolates();
100 : #endif // DEBUG
101 28335 : 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 28320 : if (initialize_) {
110 27944 : if (v8::Locker::IsActive()) {
111 143 : v8::Locker locker(isolate_);
112 143 : EmptyMessageQueues(isolate_);
113 : } else {
114 27801 : EmptyMessageQueues(isolate_);
115 : }
116 27944 : isolate_->Exit();
117 : }
118 28320 : }
119 :
120 649302 : i::Heap* CcTest::heap() { return i_isolate()->heap(); }
121 :
122 2439 : void CcTest::CollectGarbage(i::AllocationSpace space) {
123 2439 : heap()->CollectGarbage(space, i::GarbageCollectionReason::kTesting);
124 2439 : }
125 :
126 4076 : void CcTest::CollectAllGarbage(i::Isolate* isolate) {
127 4076 : i::Isolate* iso = isolate ? isolate : i_isolate();
128 : iso->heap()->CollectAllGarbage(i::Heap::kNoGCFlags,
129 4076 : i::GarbageCollectionReason::kTesting);
130 4076 : }
131 :
132 352 : void CcTest::CollectAllAvailableGarbage(i::Isolate* isolate) {
133 352 : i::Isolate* iso = isolate ? isolate : i_isolate();
134 352 : iso->heap()->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
135 352 : }
136 :
137 173 : void CcTest::PreciseCollectAllGarbage(i::Isolate* isolate) {
138 173 : i::Isolate* iso = isolate ? isolate : i_isolate();
139 : iso->heap()->PreciseCollectAllGarbage(i::Heap::kNoGCFlags,
140 173 : i::GarbageCollectionReason::kTesting);
141 173 : }
142 :
143 55 : v8::base::RandomNumberGenerator* CcTest::random_number_generator() {
144 55 : return InitIsolateOnce()->random_number_generator();
145 : }
146 :
147 6932 : v8::Local<v8::Object> CcTest::global() {
148 13864 : return isolate()->GetCurrentContext()->Global();
149 : }
150 :
151 18886 : void CcTest::InitializeVM() {
152 18886 : CHECK(!v8::base::Relaxed_Load(&isolate_used_));
153 18886 : CHECK(!initialize_called_);
154 18886 : initialize_called_ = true;
155 18886 : v8::HandleScope handle_scope(CcTest::isolate());
156 37772 : v8::Context::New(CcTest::isolate())->Enter();
157 18886 : }
158 :
159 0 : void CcTest::TearDown() {
160 28322 : if (isolate_ != nullptr) isolate_->Dispose();
161 0 : }
162 :
163 78 : v8::Local<v8::Context> CcTest::NewContext(CcTestExtensionFlags extension_flags,
164 : v8::Isolate* isolate) {
165 : const char* extension_names[kMaxExtensions];
166 : int extension_count = 0;
167 390 : for (int i = 0; i < kMaxExtensions; ++i) {
168 312 : if (!extension_flags.contains(static_cast<CcTestExtensionId>(i))) continue;
169 83 : extension_names[extension_count] = kExtensionName[i];
170 83 : ++extension_count;
171 : }
172 : v8::ExtensionConfiguration config(extension_count, extension_names);
173 78 : v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
174 78 : CHECK(!context.IsEmpty());
175 78 : return context;
176 : }
177 :
178 5 : void CcTest::DisableAutomaticDispose() {
179 5 : CHECK_EQ(kUninitialized, initialization_state_);
180 5 : disable_automatic_dispose_ = true;
181 5 : }
182 :
183 12285 : LocalContext::~LocalContext() {
184 12285 : v8::HandleScope scope(isolate_);
185 24570 : v8::Local<v8::Context>::New(isolate_, context_)->Exit();
186 12285 : context_.Reset();
187 12285 : }
188 :
189 12285 : void LocalContext::Initialize(v8::Isolate* isolate,
190 : v8::ExtensionConfiguration* extensions,
191 : v8::Local<v8::ObjectTemplate> global_template,
192 : v8::Local<v8::Value> global_object) {
193 12285 : v8::HandleScope scope(isolate);
194 : v8::Local<v8::Context> context =
195 12285 : v8::Context::New(isolate, extensions, global_template, global_object);
196 : context_.Reset(isolate, context);
197 12285 : context->Enter();
198 : // We can't do this later perhaps because of a fatal error.
199 12285 : isolate_ = isolate;
200 12285 : }
201 :
202 : // This indirection is needed because HandleScopes cannot be heap-allocated, and
203 : // we don't want any unnecessary #includes in cctest.h.
204 : class InitializedHandleScopeImpl {
205 : public:
206 : explicit InitializedHandleScopeImpl(i::Isolate* isolate)
207 : : handle_scope_(isolate) {}
208 :
209 : private:
210 : i::HandleScope handle_scope_;
211 : };
212 :
213 1759035 : InitializedHandleScope::InitializedHandleScope()
214 1759035 : : main_isolate_(CcTest::InitIsolateOnce()),
215 : initialized_handle_scope_impl_(
216 3518070 : new InitializedHandleScopeImpl(main_isolate_)) {}
217 :
218 : InitializedHandleScope::~InitializedHandleScope() = default;
219 :
220 1756750 : HandleAndZoneScope::HandleAndZoneScope()
221 3513500 : : main_zone_(new i::Zone(&allocator_, ZONE_NAME)) {}
222 :
223 : HandleAndZoneScope::~HandleAndZoneScope() = default;
224 :
225 34358 : static void PrintTestList(CcTest* current) {
226 22908 : if (current == nullptr) return;
227 11452 : PrintTestList(current->prev());
228 : printf("%s/%s\n", current->file(), current->name());
229 : }
230 :
231 :
232 : static void SuggestTestHarness(int tests) {
233 28335 : if (tests == 0) return;
234 : printf("Running multiple tests in sequence is deprecated and may cause "
235 : "bogus failure. Consider using tools/run-tests.py instead.\n");
236 : }
237 :
238 :
239 28337 : int main(int argc, char* argv[]) {
240 : #if V8_OS_WIN
241 : UINT new_flags =
242 : SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
243 : UINT existing_flags = SetErrorMode(new_flags);
244 : SetErrorMode(existing_flags | new_flags);
245 : #if V8_CC_MSVC
246 : _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
247 : _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
248 : _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
249 : _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
250 : _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
251 : _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
252 : _set_error_mode(_OUT_TO_STDERR);
253 : #endif // V8_CC_MSVC
254 : #endif // V8_OS_WIN
255 :
256 : // hack to print cctest specific flags
257 141653 : for (int i = 1; i < argc; i++) {
258 113316 : char* arg = argv[i];
259 113316 : if ((strcmp(arg, "--help") == 0) || (strcmp(arg, "-h") == 0)) {
260 0 : printf("Usage: %s [--list] [[V8_FLAGS] CCTEST]\n", argv[0]);
261 : printf("\n");
262 : printf("Options:\n");
263 : printf(" --list: list all cctests\n");
264 : printf(" CCTEST: cctest identfier returned by --list\n");
265 : printf(" D8_FLAGS: see d8 output below\n");
266 : printf("\n\n");
267 : }
268 : }
269 :
270 28337 : v8::V8::InitializeICUDefaultLocation(argv[0]);
271 56674 : std::unique_ptr<v8::Platform> platform(v8::platform::NewDefaultPlatform());
272 28337 : v8::V8::InitializePlatform(platform.get());
273 28337 : v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
274 28337 : v8::V8::Initialize();
275 28337 : v8::V8::InitializeExternalStartupData(argv[0]);
276 :
277 28337 : if (V8_TRAP_HANDLER_SUPPORTED && i::FLAG_wasm_trap_handler) {
278 : constexpr bool use_default_signal_handler = true;
279 28337 : CHECK(v8::V8::EnableWebAssemblyTrapHandler(use_default_signal_handler));
280 : }
281 :
282 : CcTest::set_array_buffer_allocator(
283 28337 : v8::ArrayBuffer::Allocator::NewDefaultAllocator());
284 :
285 28337 : i::PrintExtension print_extension;
286 28337 : v8::RegisterExtension(&print_extension);
287 28337 : i::ProfilerExtension profiler_extension;
288 28337 : v8::RegisterExtension(&profiler_extension);
289 28337 : i::TraceExtension trace_extension;
290 28337 : v8::RegisterExtension(&trace_extension);
291 :
292 : int tests_run = 0;
293 : bool print_run_count = true;
294 67976 : for (int i = 1; i < argc; i++) {
295 39654 : char* arg = argv[i];
296 39654 : if (strcmp(arg, "--list") == 0) {
297 2 : PrintTestList(CcTest::last());
298 : print_run_count = false;
299 :
300 : } else {
301 39652 : char* arg_copy = v8::internal::StrDup(arg);
302 : char* testname = strchr(arg_copy, '/');
303 39652 : if (testname) {
304 : // Split the string in two by nulling the slash and then run
305 : // exact matches.
306 28335 : *testname = 0;
307 : char* file = arg_copy;
308 28335 : char* name = testname + 1;
309 495110722 : CcTest* test = CcTest::last();
310 162282165 : while (test != nullptr) {
311 162225510 : if (test->enabled()
312 162225510 : && strcmp(test->file(), file) == 0
313 170659717 : && strcmp(test->name(), name) == 0) {
314 28335 : SuggestTestHarness(tests_run++);
315 28335 : test->Run();
316 : }
317 : test = test->prev();
318 : }
319 :
320 : } else {
321 : // Run all tests with the specified file or test name.
322 : char* file_or_name = arg_copy;
323 259204568 : CcTest* test = CcTest::last();
324 64823776 : while (test != nullptr) {
325 64801142 : if (test->enabled()
326 129602284 : && (strcmp(test->file(), file_or_name) == 0
327 64801142 : || strcmp(test->name(), file_or_name) == 0)) {
328 0 : SuggestTestHarness(tests_run++);
329 0 : test->Run();
330 : }
331 : test = test->prev();
332 : }
333 : }
334 : v8::internal::DeleteArray<char>(arg_copy);
335 : }
336 : }
337 28322 : if (print_run_count && tests_run != 1)
338 : printf("Ran %i tests.\n", tests_run);
339 : CcTest::TearDown();
340 : // TODO(svenpanne) See comment above.
341 : // if (!disable_automatic_dispose_) v8::V8::Dispose();
342 28322 : v8::V8::ShutdownPlatform();
343 : return 0;
344 : }
345 :
346 : RegisterThreadedTest* RegisterThreadedTest::first_ = nullptr;
347 85011 : int RegisterThreadedTest::count_ = 0;
|