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/compiler.h"
33 : #include "src/compiler/pipeline.h"
34 : #include "src/debug/debug.h"
35 : #include "src/objects-inl.h"
36 : #include "src/optimized-compilation-info.h"
37 : #include "src/trap-handler/trap-handler.h"
38 : #include "test/cctest/print-extension.h"
39 : #include "test/cctest/profiler-extension.h"
40 : #include "test/cctest/trace-extension.h"
41 :
42 : #if V8_OS_WIN
43 : #include <windows.h> // NOLINT
44 : #if V8_CC_MSVC
45 : #include <crtdbg.h>
46 : #endif
47 : #endif
48 :
49 : enum InitializationState { kUnset, kUninitialized, kInitialized };
50 : static InitializationState initialization_state_ = kUnset;
51 : static bool disable_automatic_dispose_ = false;
52 :
53 : CcTest* CcTest::last_ = nullptr;
54 : bool CcTest::initialize_called_ = false;
55 : v8::base::Atomic32 CcTest::isolate_used_ = 0;
56 : v8::ArrayBuffer::Allocator* CcTest::allocator_ = nullptr;
57 : v8::Isolate* CcTest::isolate_ = nullptr;
58 :
59 160499975 : CcTest::CcTest(TestFunction* callback, const char* file, const char* name,
60 : bool enabled, bool initialize)
61 : : callback_(callback),
62 : name_(name),
63 : enabled_(enabled),
64 : initialize_(initialize),
65 160499975 : prev_(last_) {
66 : // Find the base name of this test (const_cast required on Windows).
67 : char *basename = strrchr(const_cast<char *>(file), '/');
68 160499975 : if (!basename) {
69 : basename = strrchr(const_cast<char *>(file), '\\');
70 : }
71 160499975 : if (!basename) {
72 0 : basename = v8::internal::StrDup(file);
73 : } else {
74 160499975 : basename = v8::internal::StrDup(basename + 1);
75 : }
76 : // Drop the extension, if there is one.
77 : char *extension = strrchr(basename, '.');
78 160499975 : if (extension) *extension = 0;
79 : // Install this test in the list of tests
80 160499975 : file_ = basename;
81 160499975 : prev_ = last_;
82 160499975 : last_ = this;
83 160499975 : }
84 :
85 :
86 26630 : void CcTest::Run() {
87 26630 : if (!initialize_) {
88 521 : CHECK_NE(initialization_state_, kInitialized);
89 521 : initialization_state_ = kUninitialized;
90 521 : CHECK_NULL(CcTest::isolate_);
91 : } else {
92 26109 : CHECK_NE(initialization_state_, kUninitialized);
93 26109 : initialization_state_ = kInitialized;
94 26109 : if (isolate_ == nullptr) {
95 : v8::Isolate::CreateParams create_params;
96 26109 : create_params.array_buffer_allocator = allocator_;
97 26109 : isolate_ = v8::Isolate::New(create_params);
98 : }
99 26109 : isolate_->Enter();
100 : }
101 : #ifdef DEBUG
102 : const size_t active_isolates = i::Isolate::non_disposed_isolates();
103 : #endif // DEBUG
104 26630 : callback_();
105 : #ifdef DEBUG
106 : // This DCHECK ensures that all Isolates are properly disposed after finishing
107 : // the test. Stray Isolates lead to stray tasks in the platform which can
108 : // interact weirdly when swapping in new platforms (for testing) or during
109 : // shutdown.
110 : DCHECK_EQ(active_isolates, i::Isolate::non_disposed_isolates());
111 : #endif // DEBUG
112 26615 : if (initialize_) {
113 26094 : if (v8::Locker::IsActive()) {
114 286 : v8::Locker locker(isolate_);
115 143 : EmptyMessageQueues(isolate_);
116 : } else {
117 25951 : EmptyMessageQueues(isolate_);
118 : }
119 26094 : isolate_->Exit();
120 : }
121 26615 : }
122 :
123 179422 : i::Heap* CcTest::heap() { return i_isolate()->heap(); }
124 :
125 2462 : void CcTest::CollectGarbage(i::AllocationSpace space) {
126 2462 : heap()->CollectGarbage(space, i::GarbageCollectionReason::kTesting);
127 2462 : }
128 :
129 3941 : void CcTest::CollectAllGarbage(i::Isolate* isolate) {
130 3941 : i::Isolate* iso = isolate ? isolate : i_isolate();
131 : iso->heap()->CollectAllGarbage(i::Heap::kNoGCFlags,
132 3941 : i::GarbageCollectionReason::kTesting);
133 3941 : }
134 :
135 327 : void CcTest::CollectAllAvailableGarbage(i::Isolate* isolate) {
136 327 : i::Isolate* iso = isolate ? isolate : i_isolate();
137 327 : iso->heap()->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
138 327 : }
139 :
140 173 : void CcTest::PreciseCollectAllGarbage(i::Isolate* isolate) {
141 173 : i::Isolate* iso = isolate ? isolate : i_isolate();
142 : iso->heap()->PreciseCollectAllGarbage(i::Heap::kNoGCFlags,
143 173 : i::GarbageCollectionReason::kTesting);
144 173 : }
145 :
146 45 : v8::base::RandomNumberGenerator* CcTest::random_number_generator() {
147 45 : return InitIsolateOnce()->random_number_generator();
148 : }
149 :
150 6483 : v8::Local<v8::Object> CcTest::global() {
151 12966 : return isolate()->GetCurrentContext()->Global();
152 : }
153 :
154 17081 : void CcTest::InitializeVM() {
155 17081 : CHECK(!v8::base::Relaxed_Load(&isolate_used_));
156 17081 : CHECK(!initialize_called_);
157 17081 : initialize_called_ = true;
158 34162 : v8::HandleScope handle_scope(CcTest::isolate());
159 34162 : v8::Context::New(CcTest::isolate())->Enter();
160 17081 : }
161 :
162 0 : void CcTest::TearDown() {
163 26624 : if (isolate_ != nullptr) isolate_->Dispose();
164 0 : }
165 :
166 94 : v8::Local<v8::Context> CcTest::NewContext(CcTestExtensionFlags extension_flags,
167 : v8::Isolate* isolate) {
168 : const char* extension_names[kMaxExtensions];
169 : int extension_count = 0;
170 846 : for (int i = 0; i < kMaxExtensions; ++i) {
171 752 : if (!extension_flags.contains(static_cast<CcTestExtensionId>(i))) continue;
172 99 : extension_names[extension_count] = kExtensionName[i];
173 99 : ++extension_count;
174 : }
175 : v8::ExtensionConfiguration config(extension_count, extension_names);
176 94 : v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
177 94 : CHECK(!context.IsEmpty());
178 94 : return context;
179 : }
180 :
181 5 : void CcTest::DisableAutomaticDispose() {
182 5 : CHECK_EQ(kUninitialized, initialization_state_);
183 5 : disable_automatic_dispose_ = true;
184 5 : }
185 :
186 23806 : LocalContext::~LocalContext() {
187 23806 : v8::HandleScope scope(isolate_);
188 23806 : v8::Local<v8::Context>::New(isolate_, context_)->Exit();
189 : context_.Reset();
190 11903 : }
191 :
192 11902 : void LocalContext::Initialize(v8::Isolate* isolate,
193 : v8::ExtensionConfiguration* extensions,
194 : v8::Local<v8::ObjectTemplate> global_template,
195 : v8::Local<v8::Value> global_object) {
196 23805 : v8::HandleScope scope(isolate);
197 : v8::Local<v8::Context> context =
198 11902 : v8::Context::New(isolate, extensions, global_template, global_object);
199 : context_.Reset(isolate, context);
200 11903 : context->Enter();
201 : // We can't do this later perhaps because of a fatal error.
202 11903 : isolate_ = isolate;
203 11903 : }
204 :
205 : // This indirection is needed because HandleScopes cannot be heap-allocated, and
206 : // we don't want any unnecessary #includes in cctest.h.
207 1444810 : class InitializedHandleScopeImpl {
208 : public:
209 : explicit InitializedHandleScopeImpl(i::Isolate* isolate)
210 : : handle_scope_(isolate) {}
211 :
212 : private:
213 : i::HandleScope handle_scope_;
214 : };
215 :
216 1444810 : InitializedHandleScope::InitializedHandleScope()
217 : : main_isolate_(CcTest::InitIsolateOnce()),
218 : initialized_handle_scope_impl_(
219 2889620 : new InitializedHandleScopeImpl(main_isolate_)) {}
220 :
221 : InitializedHandleScope::~InitializedHandleScope() = default;
222 :
223 1442880 : HandleAndZoneScope::HandleAndZoneScope()
224 4328640 : : main_zone_(new i::Zone(&allocator_, ZONE_NAME)) {}
225 :
226 : HandleAndZoneScope::~HandleAndZoneScope() = default;
227 :
228 1564 : i::Handle<i::JSFunction> Optimize(i::Handle<i::JSFunction> function,
229 : i::Zone* zone, i::Isolate* isolate,
230 : uint32_t flags,
231 : i::compiler::JSHeapBroker** out_broker) {
232 : i::Handle<i::SharedFunctionInfo> shared(function->shared(), isolate);
233 1564 : i::IsCompiledScope is_compiled_scope(shared->is_compiled_scope());
234 1564 : CHECK(is_compiled_scope.is_compiled() ||
235 : i::Compiler::Compile(function, i::Compiler::CLEAR_EXCEPTION,
236 : &is_compiled_scope));
237 :
238 1564 : CHECK_NOT_NULL(zone);
239 :
240 3128 : i::OptimizedCompilationInfo info(zone, isolate, shared, function);
241 :
242 1564 : if (flags & i::OptimizedCompilationInfo::kInliningEnabled) {
243 : info.MarkAsInliningEnabled();
244 : }
245 :
246 1564 : CHECK(info.shared_info()->HasBytecodeArray());
247 1564 : i::JSFunction::EnsureFeedbackVector(function);
248 :
249 : i::Handle<i::Code> code =
250 3128 : i::compiler::Pipeline::GenerateCodeForTesting(&info, isolate, out_broker)
251 : .ToHandleChecked();
252 1564 : info.native_context()->AddOptimizedCode(*code);
253 1564 : function->set_code(*code);
254 :
255 3128 : return function;
256 : }
257 :
258 24104 : static void PrintTestList(CcTest* current) {
259 24104 : if (current == nullptr) return;
260 24100 : PrintTestList(current->prev());
261 : printf("%s/%s\n", current->file(), current->name());
262 : }
263 :
264 :
265 : static void SuggestTestHarness(int tests) {
266 26630 : if (tests == 0) return;
267 : printf("Running multiple tests in sequence is deprecated and may cause "
268 : "bogus failure. Consider using tools/run-tests.py instead.\n");
269 : }
270 :
271 :
272 26639 : int main(int argc, char* argv[]) {
273 : #if V8_OS_WIN
274 : UINT new_flags =
275 : SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
276 : UINT existing_flags = SetErrorMode(new_flags);
277 : SetErrorMode(existing_flags | new_flags);
278 : #if V8_CC_MSVC
279 : _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
280 : _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
281 : _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
282 : _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
283 : _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
284 : _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
285 : _set_error_mode(_OUT_TO_STDERR);
286 : #endif // V8_CC_MSVC
287 : #endif // V8_OS_WIN
288 :
289 : // hack to print cctest specific flags
290 263543 : for (int i = 1; i < argc; i++) {
291 118452 : char* arg = argv[i];
292 118452 : if ((strcmp(arg, "--help") == 0) || (strcmp(arg, "-h") == 0)) {
293 0 : printf("Usage: %s [--list] [[V8_FLAGS] CCTEST]\n", argv[0]);
294 : printf("\n");
295 : printf("Options:\n");
296 : printf(" --list: list all cctests\n");
297 : printf(" CCTEST: cctest identfier returned by --list\n");
298 : printf(" D8_FLAGS: see d8 output below\n");
299 : printf("\n\n");
300 : }
301 : }
302 :
303 26639 : v8::V8::InitializeICUDefaultLocation(argv[0]);
304 53278 : std::unique_ptr<v8::Platform> platform(v8::platform::NewDefaultPlatform());
305 : v8::V8::InitializePlatform(platform.get());
306 26639 : v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
307 26639 : v8::V8::Initialize();
308 26639 : v8::V8::InitializeExternalStartupData(argv[0]);
309 :
310 26639 : if (V8_TRAP_HANDLER_SUPPORTED && i::FLAG_wasm_trap_handler) {
311 : constexpr bool use_default_signal_handler = true;
312 26639 : CHECK(v8::V8::EnableWebAssemblyTrapHandler(use_default_signal_handler));
313 : }
314 :
315 26639 : CcTest::set_array_buffer_allocator(
316 : v8::ArrayBuffer::Allocator::NewDefaultAllocator());
317 :
318 106556 : v8::RegisterExtension(v8::base::make_unique<i::PrintExtension>());
319 106556 : v8::RegisterExtension(v8::base::make_unique<i::ProfilerExtension>());
320 106556 : v8::RegisterExtension(v8::base::make_unique<i::TraceExtension>());
321 :
322 : int tests_run = 0;
323 : bool print_run_count = true;
324 103741 : for (int i = 1; i < argc; i++) {
325 38566 : char* arg = argv[i];
326 38566 : if (strcmp(arg, "--list") == 0) {
327 4 : PrintTestList(CcTest::last());
328 : print_run_count = false;
329 :
330 : } else {
331 38562 : char* arg_copy = v8::internal::StrDup(arg);
332 : char* testname = strchr(arg_copy, '/');
333 38562 : if (testname) {
334 : // Split the string in two by nulling the slash and then run
335 : // exact matches.
336 26635 : *testname = 0;
337 : char* file = arg_copy;
338 26635 : char* name = testname + 1;
339 : CcTest* test = CcTest::last();
340 320935515 : while (test != nullptr) {
341 160454455 : if (test->enabled()
342 160427835 : && strcmp(test->file(), file) == 0
343 168089603 : && strcmp(test->name(), name) == 0) {
344 26630 : SuggestTestHarness(tests_run++);
345 26630 : test->Run();
346 : }
347 : test = test->prev();
348 : }
349 :
350 : } else {
351 : // Run all tests with the specified file or test name.
352 : char* file_or_name = arg_copy;
353 : CcTest* test = CcTest::last();
354 143732277 : while (test != nullptr) {
355 71860175 : if (test->enabled()
356 71860175 : && (strcmp(test->file(), file_or_name) == 0
357 71848248 : || strcmp(test->name(), file_or_name) == 0)) {
358 0 : SuggestTestHarness(tests_run++);
359 0 : test->Run();
360 : }
361 : test = test->prev();
362 : }
363 : }
364 : v8::internal::DeleteArray<char>(arg_copy);
365 : }
366 : }
367 26624 : if (print_run_count && tests_run != 1)
368 : printf("Ran %i tests.\n", tests_run);
369 : CcTest::TearDown();
370 26624 : if (!disable_automatic_dispose_) v8::V8::Dispose();
371 26624 : v8::V8::ShutdownPlatform();
372 : return 0;
373 : }
374 :
375 : RegisterThreadedTest* RegisterThreadedTest::first_ = nullptr;
376 79917 : int RegisterThreadedTest::count_ = 0;
|