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 : #ifndef CCTEST_H_
29 : #define CCTEST_H_
30 :
31 : #include <memory>
32 :
33 : #include "include/libplatform/libplatform.h"
34 : #include "include/v8-platform.h"
35 : #include "src/base/enum-set.h"
36 : #include "src/debug/debug-interface.h"
37 : #include "src/flags.h"
38 : #include "src/heap/factory.h"
39 : #include "src/isolate.h"
40 : #include "src/objects.h"
41 : #include "src/register-configuration.h"
42 : #include "src/v8.h"
43 : #include "src/zone/accounting-allocator.h"
44 :
45 : namespace v8 {
46 : namespace base {
47 :
48 : class RandomNumberGenerator;
49 :
50 : } // namespace base
51 :
52 : namespace internal {
53 :
54 : const auto GetRegConfig = RegisterConfiguration::Default;
55 :
56 : class HandleScope;
57 : class Zone;
58 :
59 : namespace compiler {
60 :
61 : class JSHeapBroker;
62 :
63 : } // namespace compiler
64 :
65 : } // namespace internal
66 :
67 : } // namespace v8
68 :
69 : #ifndef TEST
70 : #define TEST(Name) \
71 : static void Test##Name(); \
72 : CcTest register_test_##Name(Test##Name, __FILE__, #Name, true, true); \
73 : static void Test##Name()
74 : #endif
75 :
76 : #ifndef UNINITIALIZED_TEST
77 : #define UNINITIALIZED_TEST(Name) \
78 : static void Test##Name(); \
79 : CcTest register_test_##Name(Test##Name, __FILE__, #Name, true, false); \
80 : static void Test##Name()
81 : #endif
82 :
83 : #ifndef DISABLED_TEST
84 : #define DISABLED_TEST(Name) \
85 : static void Test##Name(); \
86 : CcTest register_test_##Name(Test##Name, __FILE__, #Name, false, true); \
87 : static void Test##Name()
88 : #endif
89 :
90 : #define EXTENSION_LIST(V) \
91 : V(GC_EXTENSION, "v8/gc") \
92 : V(PRINT_EXTENSION, "v8/print") \
93 : V(PROFILER_EXTENSION, "v8/profiler") \
94 : V(TRACE_EXTENSION, "v8/trace")
95 :
96 : #define DEFINE_EXTENSION_ID(Name, Ident) Name##_ID,
97 : enum CcTestExtensionId { EXTENSION_LIST(DEFINE_EXTENSION_ID) kMaxExtensions };
98 : #undef DEFINE_EXTENSION_ID
99 :
100 : using CcTestExtensionFlags = v8::base::EnumSet<CcTestExtensionId>;
101 :
102 : #define DEFINE_EXTENSION_NAME(Name, Ident) Ident,
103 : static constexpr const char* kExtensionName[kMaxExtensions] = {
104 : EXTENSION_LIST(DEFINE_EXTENSION_NAME)};
105 : #undef DEFINE_EXTENSION_NAME
106 :
107 : class CcTest {
108 : public:
109 : typedef void (TestFunction)();
110 : CcTest(TestFunction* callback, const char* file, const char* name,
111 : bool enabled, bool initialize);
112 302168250 : ~CcTest() { i::DeleteArray(file_); }
113 : void Run();
114 37416 : static CcTest* last() { return last_; }
115 : CcTest* prev() { return prev_; }
116 : const char* file() { return file_; }
117 : const char* name() { return name_; }
118 : bool enabled() { return enabled_; }
119 :
120 15849877 : static v8::Isolate* isolate() {
121 15849877 : CHECK_NOT_NULL(isolate_);
122 : v8::base::Relaxed_Store(&isolate_used_, 1);
123 15849877 : return isolate_;
124 : }
125 :
126 12557558 : static i::Isolate* InitIsolateOnce() {
127 12557558 : if (!initialize_called_) InitializeVM();
128 12557558 : return i_isolate();
129 : }
130 :
131 : static i::Isolate* i_isolate() {
132 15655675 : return reinterpret_cast<i::Isolate*>(isolate());
133 : }
134 :
135 : static i::Heap* heap();
136 :
137 : static void CollectGarbage(i::AllocationSpace space);
138 : static void CollectAllGarbage(i::Isolate* isolate = nullptr);
139 : static void CollectAllAvailableGarbage(i::Isolate* isolate = nullptr);
140 : static void PreciseCollectAllGarbage(i::Isolate* isolate = nullptr);
141 :
142 : static v8::base::RandomNumberGenerator* random_number_generator();
143 :
144 : static v8::Local<v8::Object> global();
145 :
146 : static v8::ArrayBuffer::Allocator* array_buffer_allocator() {
147 1530 : return allocator_;
148 : }
149 :
150 : static void set_array_buffer_allocator(
151 : v8::ArrayBuffer::Allocator* allocator) {
152 25875 : allocator_ = allocator;
153 : }
154 :
155 : // TODO(dcarney): Remove.
156 : // This must be called first in a test.
157 : static void InitializeVM();
158 :
159 : // Only for UNINITIALIZED_TESTs
160 : static void DisableAutomaticDispose();
161 :
162 : // Helper function to configure a context.
163 : // Must be in a HandleScope.
164 : static v8::Local<v8::Context> NewContext(
165 : v8::Isolate* isolate = CcTest::isolate()) {
166 : return NewContext({}, isolate);
167 : }
168 : static v8::Local<v8::Context> NewContext(
169 : CcTestExtensionFlags extension_flags,
170 : v8::Isolate* isolate = CcTest::isolate());
171 :
172 : static void TearDown();
173 :
174 : private:
175 : friend int main(int argc, char** argv);
176 : TestFunction* callback_;
177 : const char* file_;
178 : const char* name_;
179 : bool enabled_;
180 : bool initialize_;
181 : CcTest* prev_;
182 : static CcTest* last_;
183 : static v8::ArrayBuffer::Allocator* allocator_;
184 : static v8::Isolate* isolate_;
185 : static bool initialize_called_;
186 : static v8::base::Atomic32 isolate_used_;
187 : };
188 :
189 : // Switches between all the Api tests using the threading support.
190 : // In order to get a surprising but repeatable pattern of thread
191 : // switching it has extra semaphores to control the order in which
192 : // the tests alternate, not relying solely on the big V8 lock.
193 : //
194 : // A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
195 : // callbacks. This will have no effect when we are not running the
196 : // thread fuzzing test. In the thread fuzzing test it will
197 : // pseudorandomly select a successor thread and switch execution
198 : // to that thread, suspending the current test.
199 : class ApiTestFuzzer: public v8::base::Thread {
200 : public:
201 : void CallTest();
202 :
203 : // The ApiTestFuzzer is also a Thread, so it has a Run method.
204 : void Run() override;
205 :
206 : enum PartOfTest {
207 : FIRST_PART,
208 : SECOND_PART,
209 : THIRD_PART,
210 : FOURTH_PART,
211 : FIFTH_PART,
212 : SIXTH_PART,
213 : SEVENTH_PART,
214 : EIGHTH_PART,
215 : LAST_PART = EIGHTH_PART
216 : };
217 :
218 : static void SetUp(PartOfTest part);
219 : static void RunAllTests();
220 : static void TearDown();
221 : // This method switches threads if we are running the Threading test.
222 : // Otherwise it does nothing.
223 : static void Fuzz();
224 :
225 : private:
226 468 : explicit ApiTestFuzzer(int num)
227 : : Thread(Options("ApiTestFuzzer")),
228 : test_number_(num),
229 : gate_(0),
230 468 : active_(true) {}
231 0 : ~ApiTestFuzzer() override = default;
232 :
233 : static bool fuzzing_;
234 : static int tests_being_run_;
235 : static int current_;
236 : static int active_tests_;
237 : static bool NextThread();
238 : int test_number_;
239 : v8::base::Semaphore gate_;
240 : bool active_;
241 : void ContextSwitch();
242 : static int GetNextTestNumber();
243 : static v8::base::Semaphore all_tests_done_;
244 : };
245 :
246 :
247 : #define THREADED_TEST(Name) \
248 : static void Test##Name(); \
249 : RegisterThreadedTest register_##Name(Test##Name, #Name); \
250 : /* */ TEST(Name)
251 :
252 : class RegisterThreadedTest {
253 : public:
254 : explicit RegisterThreadedTest(CcTest::TestFunction* callback,
255 : const char* name)
256 12109500 : : fuzzer_(nullptr), callback_(callback), name_(name) {
257 12109500 : prev_ = first_;
258 12109500 : first_ = this;
259 12109500 : count_++;
260 : }
261 3317866 : static int count() { return count_; }
262 3314106 : static RegisterThreadedTest* nth(int i) {
263 3314106 : CHECK(i < count());
264 3314106 : RegisterThreadedTest* current = first_;
265 102535447 : while (i > 0) {
266 95907235 : i--;
267 95907235 : current = current->prev_;
268 : }
269 3314106 : return current;
270 : }
271 : CcTest::TestFunction* callback() { return callback_; }
272 : ApiTestFuzzer* fuzzer_;
273 : const char* name() { return name_; }
274 :
275 : private:
276 : static RegisterThreadedTest* first_;
277 : static int count_;
278 : CcTest::TestFunction* callback_;
279 : RegisterThreadedTest* prev_;
280 : const char* name_;
281 : };
282 :
283 : // A LocalContext holds a reference to a v8::Context.
284 : class LocalContext {
285 : public:
286 : LocalContext(v8::Isolate* isolate,
287 : v8::ExtensionConfiguration* extensions = nullptr,
288 : v8::Local<v8::ObjectTemplate> global_template =
289 : v8::Local<v8::ObjectTemplate>(),
290 2462 : v8::Local<v8::Value> global_object = v8::Local<v8::Value>()) {
291 2462 : Initialize(isolate, extensions, global_template, global_object);
292 : }
293 :
294 9307 : LocalContext(v8::ExtensionConfiguration* extensions = nullptr,
295 : v8::Local<v8::ObjectTemplate> global_template =
296 : v8::Local<v8::ObjectTemplate>(),
297 9307 : v8::Local<v8::Value> global_object = v8::Local<v8::Value>()) {
298 9307 : Initialize(CcTest::isolate(), extensions, global_template, global_object);
299 9307 : }
300 :
301 : virtual ~LocalContext();
302 :
303 : v8::Context* operator->() {
304 112494 : return *reinterpret_cast<v8::Context**>(&context_);
305 : }
306 : v8::Context* operator*() { return operator->(); }
307 : bool IsReady() { return !context_.IsEmpty(); }
308 :
309 187850 : v8::Local<v8::Context> local() {
310 375700 : return v8::Local<v8::Context>::New(isolate_, context_);
311 : }
312 :
313 : private:
314 : void Initialize(v8::Isolate* isolate, v8::ExtensionConfiguration* extensions,
315 : v8::Local<v8::ObjectTemplate> global_template,
316 : v8::Local<v8::Value> global_object);
317 :
318 : v8::Persistent<v8::Context> context_;
319 : v8::Isolate* isolate_;
320 : };
321 :
322 :
323 25997 : static inline uint16_t* AsciiToTwoByteString(const char* source) {
324 25997 : int array_length = i::StrLength(source) + 1;
325 25997 : uint16_t* converted = i::NewArray<uint16_t>(array_length);
326 25997 : for (int i = 0; i < array_length; i++) converted[i] = source[i];
327 25997 : return converted;
328 : }
329 :
330 : template <typename T>
331 70 : static inline i::Handle<T> GetGlobal(const char* name) {
332 : i::Isolate* isolate = CcTest::i_isolate();
333 : i::Handle<i::String> str_name =
334 70 : isolate->factory()->InternalizeUtf8String(name);
335 :
336 : i::Handle<i::Object> value =
337 140 : i::Object::GetProperty(isolate, isolate->global_object(), str_name)
338 140 : .ToHandleChecked();
339 70 : return i::Handle<T>::cast(value);
340 : }
341 :
342 77362 : static inline v8::Local<v8::Value> v8_num(double x) {
343 77362 : return v8::Number::New(v8::Isolate::GetCurrent(), x);
344 : }
345 :
346 : static inline v8::Local<v8::Integer> v8_int(int32_t x) {
347 40 : return v8::Integer::New(v8::Isolate::GetCurrent(), x);
348 : }
349 :
350 502679 : static inline v8::Local<v8::String> v8_str(const char* x) {
351 : return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x,
352 502679 : v8::NewStringType::kNormal)
353 1005358 : .ToLocalChecked();
354 : }
355 :
356 :
357 913 : static inline v8::Local<v8::String> v8_str(v8::Isolate* isolate,
358 : const char* x) {
359 : return v8::String::NewFromUtf8(isolate, x, v8::NewStringType::kNormal)
360 1826 : .ToLocalChecked();
361 : }
362 :
363 :
364 5 : static inline v8::Local<v8::Symbol> v8_symbol(const char* name) {
365 5 : return v8::Symbol::New(v8::Isolate::GetCurrent(), v8_str(name));
366 : }
367 :
368 :
369 116428 : static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
370 : v8::Local<v8::Script> result;
371 232855 : if (v8::Script::Compile(v8::Isolate::GetCurrent()->GetCurrentContext(), x)
372 116428 : .ToLocal(&result)) {
373 116417 : return result;
374 : }
375 10 : return v8::Local<v8::Script>();
376 : }
377 :
378 :
379 : static inline v8::Local<v8::Script> v8_compile(const char* x) {
380 2224 : return v8_compile(v8_str(x));
381 : }
382 :
383 :
384 2054 : static inline int32_t v8_run_int32value(v8::Local<v8::Script> script) {
385 2054 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
386 6162 : return script->Run(context).ToLocalChecked()->Int32Value(context).FromJust();
387 : }
388 :
389 :
390 60 : static inline v8::Local<v8::Script> CompileWithOrigin(
391 : v8::Local<v8::String> source, v8::Local<v8::String> origin_url) {
392 : v8::ScriptOrigin origin(origin_url);
393 : v8::ScriptCompiler::Source script_source(source, origin);
394 : return v8::ScriptCompiler::Compile(
395 60 : v8::Isolate::GetCurrent()->GetCurrentContext(), &script_source)
396 120 : .ToLocalChecked();
397 : }
398 :
399 :
400 : static inline v8::Local<v8::Script> CompileWithOrigin(
401 : v8::Local<v8::String> source, const char* origin_url) {
402 17 : return CompileWithOrigin(source, v8_str(origin_url));
403 : }
404 :
405 :
406 27 : static inline v8::Local<v8::Script> CompileWithOrigin(const char* source,
407 : const char* origin_url) {
408 27 : return CompileWithOrigin(v8_str(source), v8_str(origin_url));
409 : }
410 :
411 :
412 : // Helper functions that compile and run the source.
413 273 : static inline v8::MaybeLocal<v8::Value> CompileRun(
414 : v8::Local<v8::Context> context, const char* source) {
415 273 : return v8::Script::Compile(context, v8_str(source))
416 273 : .ToLocalChecked()
417 273 : ->Run(context);
418 : }
419 :
420 :
421 538 : static inline v8::Local<v8::Value> CompileRunChecked(v8::Isolate* isolate,
422 : const char* source) {
423 : v8::Local<v8::String> source_string =
424 : v8::String::NewFromUtf8(isolate, source, v8::NewStringType::kNormal)
425 1076 : .ToLocalChecked();
426 538 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
427 : v8::Local<v8::Script> script =
428 538 : v8::Script::Compile(context, source_string).ToLocalChecked();
429 1076 : return script->Run(context).ToLocalChecked();
430 : }
431 :
432 :
433 114077 : static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
434 : v8::Local<v8::Value> result;
435 114077 : if (v8_compile(source)
436 228154 : ->Run(v8::Isolate::GetCurrent()->GetCurrentContext())
437 114076 : .ToLocal(&result)) {
438 111516 : return result;
439 : }
440 2561 : return v8::Local<v8::Value>();
441 : }
442 :
443 :
444 : // Helper functions that compile and run the source.
445 : static inline v8::Local<v8::Value> CompileRun(const char* source) {
446 112234 : return CompileRun(v8_str(source));
447 : }
448 :
449 :
450 80 : static inline v8::Local<v8::Value> CompileRun(
451 : v8::Local<v8::Context> context, v8::ScriptCompiler::Source* script_source,
452 : v8::ScriptCompiler::CompileOptions options) {
453 : v8::Local<v8::Value> result;
454 80 : if (v8::ScriptCompiler::Compile(context, script_source, options)
455 80 : .ToLocalChecked()
456 : ->Run(context)
457 80 : .ToLocal(&result)) {
458 60 : return result;
459 : }
460 20 : return v8::Local<v8::Value>();
461 : }
462 :
463 :
464 : // Helper functions that compile and run the source with given origin.
465 60 : static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
466 : const char* origin_url,
467 : int line_number,
468 : int column_number) {
469 60 : v8::Isolate* isolate = v8::Isolate::GetCurrent();
470 60 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
471 : v8::ScriptOrigin origin(v8_str(origin_url),
472 : v8::Integer::New(isolate, line_number),
473 60 : v8::Integer::New(isolate, column_number));
474 60 : v8::ScriptCompiler::Source script_source(v8_str(source), origin);
475 : return CompileRun(context, &script_source,
476 120 : v8::ScriptCompiler::CompileOptions());
477 : }
478 :
479 :
480 20 : static inline v8::Local<v8::Value> CompileRunWithOrigin(
481 : v8::Local<v8::String> source, const char* origin_url) {
482 20 : v8::Isolate* isolate = v8::Isolate::GetCurrent();
483 20 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
484 : v8::ScriptCompiler::Source script_source(
485 20 : source, v8::ScriptOrigin(v8_str(origin_url)));
486 : return CompileRun(context, &script_source,
487 40 : v8::ScriptCompiler::CompileOptions());
488 : }
489 :
490 :
491 : static inline v8::Local<v8::Value> CompileRunWithOrigin(
492 : const char* source, const char* origin_url) {
493 20 : return CompileRunWithOrigin(v8_str(source), origin_url);
494 : }
495 :
496 : // Takes a JSFunction and runs it through the test version of the optimizing
497 : // pipeline, allocating the temporary compilation artifacts in a given Zone.
498 : // For possible {flags} values, look at OptimizedCompilationInfo::Flag.
499 : // If passed a non-null pointer for {broker}, outputs the JSHeapBroker to it.
500 : i::Handle<i::JSFunction> Optimize(
501 : i::Handle<i::JSFunction> function, i::Zone* zone, i::Isolate* isolate,
502 : uint32_t flags, i::compiler::JSHeapBroker** out_broker = nullptr);
503 :
504 872 : static inline void ExpectString(const char* code, const char* expected) {
505 : v8::Local<v8::Value> result = CompileRun(code);
506 872 : CHECK(result->IsString());
507 872 : v8::String::Utf8Value utf8(v8::Isolate::GetCurrent(), result);
508 872 : CHECK_EQ(0, strcmp(expected, *utf8));
509 872 : }
510 :
511 :
512 1238 : static inline void ExpectInt32(const char* code, int expected) {
513 : v8::Local<v8::Value> result = CompileRun(code);
514 1238 : CHECK(result->IsInt32());
515 2476 : CHECK_EQ(expected,
516 : result->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext())
517 : .FromJust());
518 1238 : }
519 :
520 :
521 882 : static inline void ExpectBoolean(const char* code, bool expected) {
522 : v8::Local<v8::Value> result = CompileRun(code);
523 882 : CHECK(result->IsBoolean());
524 882 : CHECK_EQ(expected, result->BooleanValue(v8::Isolate::GetCurrent()));
525 882 : }
526 :
527 :
528 : static inline void ExpectTrue(const char* code) {
529 254 : ExpectBoolean(code, true);
530 : }
531 :
532 :
533 : static inline void ExpectFalse(const char* code) {
534 89 : ExpectBoolean(code, false);
535 : }
536 :
537 :
538 92 : static inline void ExpectObject(const char* code,
539 : v8::Local<v8::Value> expected) {
540 : v8::Local<v8::Value> result = CompileRun(code);
541 92 : CHECK(result->SameValue(expected));
542 92 : }
543 :
544 :
545 42 : static inline void ExpectUndefined(const char* code) {
546 : v8::Local<v8::Value> result = CompileRun(code);
547 42 : CHECK(result->IsUndefined());
548 42 : }
549 :
550 :
551 : static inline void ExpectNull(const char* code) {
552 : v8::Local<v8::Value> result = CompileRun(code);
553 : CHECK(result->IsNull());
554 : }
555 :
556 :
557 5 : static inline void CheckDoubleEquals(double expected, double actual) {
558 : const double kEpsilon = 1e-10;
559 10 : CHECK_LE(expected, actual + kEpsilon);
560 10 : CHECK_GE(expected, actual - kEpsilon);
561 5 : }
562 :
563 4709250 : static v8::debug::DebugDelegate dummy_delegate;
564 :
565 : static inline void EnableDebugger(v8::Isolate* isolate) {
566 30 : v8::debug::SetDebugDelegate(isolate, &dummy_delegate);
567 : }
568 :
569 :
570 : static inline void DisableDebugger(v8::Isolate* isolate) {
571 25 : v8::debug::SetDebugDelegate(isolate, nullptr);
572 : }
573 :
574 :
575 25506 : static inline void EmptyMessageQueues(v8::Isolate* isolate) {
576 68378 : while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(),
577 42872 : isolate)) {
578 : }
579 25506 : }
580 :
581 : class InitializedHandleScopeImpl;
582 :
583 3844 : class InitializedHandleScope {
584 : public:
585 : InitializedHandleScope();
586 : ~InitializedHandleScope();
587 :
588 : // Prefixing the below with main_ reduces a lot of naming clashes.
589 : i::Isolate* main_isolate() { return main_isolate_; }
590 :
591 : private:
592 : i::Isolate* main_isolate_;
593 : std::unique_ptr<InitializedHandleScopeImpl> initialized_handle_scope_impl_;
594 : };
595 :
596 4326639 : class HandleAndZoneScope : public InitializedHandleScope {
597 : public:
598 : HandleAndZoneScope();
599 : ~HandleAndZoneScope();
600 :
601 : // Prefixing the below with main_ reduces a lot of naming clashes.
602 : i::Zone* main_zone() { return main_zone_.get(); }
603 :
604 : private:
605 : v8::internal::AccountingAllocator allocator_;
606 : std::unique_ptr<i::Zone> main_zone_;
607 : };
608 :
609 : class StaticOneByteResource : public v8::String::ExternalOneByteStringResource {
610 : public:
611 5 : explicit StaticOneByteResource(const char* data) : data_(data) {}
612 :
613 10 : ~StaticOneByteResource() override = default;
614 :
615 10 : const char* data() const override { return data_; }
616 :
617 20 : size_t length() const override { return strlen(data_); }
618 :
619 : private:
620 : const char* data_;
621 : };
622 :
623 : class ManualGCScope {
624 : public:
625 : ManualGCScope()
626 : : flag_concurrent_marking_(i::FLAG_concurrent_marking),
627 : flag_concurrent_sweeping_(i::FLAG_concurrent_sweeping),
628 : flag_stress_incremental_marking_(i::FLAG_stress_incremental_marking),
629 : flag_parallel_marking_(i::FLAG_parallel_marking),
630 : flag_detect_ineffective_gcs_near_heap_limit_(
631 502 : i::FLAG_detect_ineffective_gcs_near_heap_limit) {
632 502 : i::FLAG_concurrent_marking = false;
633 502 : i::FLAG_concurrent_sweeping = false;
634 502 : i::FLAG_stress_incremental_marking = false;
635 : // Parallel marking has a dependency on concurrent marking.
636 502 : i::FLAG_parallel_marking = false;
637 502 : i::FLAG_detect_ineffective_gcs_near_heap_limit = false;
638 : }
639 : ~ManualGCScope() {
640 502 : i::FLAG_concurrent_marking = flag_concurrent_marking_;
641 502 : i::FLAG_concurrent_sweeping = flag_concurrent_sweeping_;
642 502 : i::FLAG_stress_incremental_marking = flag_stress_incremental_marking_;
643 502 : i::FLAG_parallel_marking = flag_parallel_marking_;
644 : i::FLAG_detect_ineffective_gcs_near_heap_limit =
645 502 : flag_detect_ineffective_gcs_near_heap_limit_;
646 : }
647 :
648 : private:
649 : bool flag_concurrent_marking_;
650 : bool flag_concurrent_sweeping_;
651 : bool flag_stress_incremental_marking_;
652 : bool flag_parallel_marking_;
653 : bool flag_detect_ineffective_gcs_near_heap_limit_;
654 : };
655 :
656 : // This is an abstract base class that can be overridden to implement a test
657 : // platform. It delegates all operations to a given platform at the time
658 : // of construction.
659 : class TestPlatform : public v8::Platform {
660 : public:
661 : // v8::Platform implementation.
662 0 : v8::PageAllocator* GetPageAllocator() override {
663 0 : return old_platform_->GetPageAllocator();
664 : }
665 :
666 0 : void OnCriticalMemoryPressure() override {
667 0 : old_platform_->OnCriticalMemoryPressure();
668 0 : }
669 :
670 0 : bool OnCriticalMemoryPressure(size_t length) override {
671 0 : return old_platform_->OnCriticalMemoryPressure(length);
672 : }
673 :
674 181 : int NumberOfWorkerThreads() override {
675 181 : return old_platform_->NumberOfWorkerThreads();
676 : }
677 :
678 6 : std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
679 : v8::Isolate* isolate) override {
680 6 : return old_platform_->GetForegroundTaskRunner(isolate);
681 : }
682 :
683 7 : void CallOnWorkerThread(std::unique_ptr<v8::Task> task) override {
684 21 : old_platform_->CallOnWorkerThread(std::move(task));
685 7 : }
686 :
687 0 : void CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task,
688 : double delay_in_seconds) override {
689 0 : old_platform_->CallDelayedOnWorkerThread(std::move(task), delay_in_seconds);
690 0 : }
691 :
692 0 : void CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) override {
693 : // This is a deprecated function and should not be called anymore.
694 0 : UNREACHABLE();
695 : }
696 :
697 0 : void CallDelayedOnForegroundThread(v8::Isolate* isolate, v8::Task* task,
698 : double delay_in_seconds) override {
699 : // This is a deprecated function and should not be called anymore.
700 0 : UNREACHABLE();
701 : }
702 :
703 17693 : double MonotonicallyIncreasingTime() override {
704 17693 : return old_platform_->MonotonicallyIncreasingTime();
705 : }
706 :
707 0 : double CurrentClockTimeMillis() override {
708 0 : return old_platform_->CurrentClockTimeMillis();
709 : }
710 :
711 0 : void CallIdleOnForegroundThread(v8::Isolate* isolate,
712 : v8::IdleTask* task) override {
713 : // This is a deprecated function and should not be called anymore.
714 0 : UNREACHABLE();
715 : }
716 :
717 0 : bool IdleTasksEnabled(v8::Isolate* isolate) override {
718 0 : return old_platform_->IdleTasksEnabled(isolate);
719 : }
720 :
721 3569 : v8::TracingController* GetTracingController() override {
722 3569 : return old_platform_->GetTracingController();
723 : }
724 :
725 : protected:
726 240 : TestPlatform() : old_platform_(i::V8::GetCurrentPlatform()) {}
727 225 : ~TestPlatform() override { i::V8::SetPlatformForTesting(old_platform_); }
728 :
729 : v8::Platform* old_platform() const { return old_platform_; }
730 :
731 : private:
732 : v8::Platform* old_platform_;
733 :
734 : DISALLOW_COPY_AND_ASSIGN(TestPlatform);
735 : };
736 :
737 : #endif // ifndef CCTEST_H_
|