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
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.
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.
33 #include "src/isolate-inl.h"
37 static void Test##Name(); \
38 CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true, true); \
39 static void Test##Name()
42 #ifndef UNINITIALIZED_TEST
43 #define UNINITIALIZED_TEST(Name) \
44 static void Test##Name(); \
45 CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true, false); \
46 static void Test##Name()
49 #ifndef DEPENDENT_TEST
50 #define DEPENDENT_TEST(Name, Dep) \
51 static void Test##Name(); \
52 CcTest register_test_##Name(Test##Name, __FILE__, #Name, #Dep, true, true); \
53 static void Test##Name()
56 #ifndef UNINITIALIZED_DEPENDENT_TEST
57 #define UNINITIALIZED_DEPENDENT_TEST(Name, Dep) \
58 static void Test##Name(); \
59 CcTest register_test_##Name(Test##Name, __FILE__, #Name, #Dep, true, false); \
60 static void Test##Name()
64 #define DISABLED_TEST(Name) \
65 static void Test##Name(); \
66 CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, false, true); \
67 static void Test##Name()
70 #define EXTENSION_LIST(V) \
71 V(GC_EXTENSION, "v8/gc") \
72 V(PRINT_EXTENSION, "v8/print") \
73 V(PROFILER_EXTENSION, "v8/profiler") \
74 V(TRACE_EXTENSION, "v8/trace")
76 #define DEFINE_EXTENSION_ID(Name, Ident) Name##_ID,
77 enum CcTestExtensionIds {
78 EXTENSION_LIST(DEFINE_EXTENSION_ID)
81 #undef DEFINE_EXTENSION_ID
83 typedef v8::internal::EnumSet<CcTestExtensionIds> CcTestExtensionFlags;
84 #define DEFINE_EXTENSION_FLAG(Name, Ident) \
85 static const CcTestExtensionFlags Name(1 << Name##_ID);
86 static const CcTestExtensionFlags NO_EXTENSIONS(0);
87 static const CcTestExtensionFlags ALL_EXTENSIONS((1 << kMaxExtensions) - 1);
88 EXTENSION_LIST(DEFINE_EXTENSION_FLAG)
89 #undef DEFINE_EXTENSION_FLAG
92 // Use this to expose protected methods in i::Heap.
93 class TestHeap : public i::Heap {
95 using i::Heap::AllocateByteArray;
96 using i::Heap::AllocateFixedArray;
97 using i::Heap::AllocateHeapNumber;
98 using i::Heap::AllocateJSObject;
99 using i::Heap::AllocateJSObjectFromMap;
100 using i::Heap::AllocateMap;
101 using i::Heap::CopyCode;
102 using i::Heap::kInitialNumberStringCacheSize;
108 typedef void (TestFunction)();
109 CcTest(TestFunction* callback, const char* file, const char* name,
110 const char* dependency, bool enabled, bool initialize);
112 static CcTest* last() { return last_; }
113 CcTest* prev() { return prev_; }
114 const char* file() { return file_; }
115 const char* name() { return name_; }
116 const char* dependency() { return dependency_; }
117 bool enabled() { return enabled_; }
119 static v8::Isolate* isolate() {
120 CHECK(isolate_ != NULL);
121 v8::base::NoBarrier_Store(&isolate_used_, 1);
125 static i::Isolate* InitIsolateOnce() {
126 if (!initialize_called_) InitializeVM();
130 static i::Isolate* i_isolate() {
131 return reinterpret_cast<i::Isolate*>(isolate());
134 static i::Heap* heap() {
135 return i_isolate()->heap();
138 static TestHeap* test_heap() {
139 return reinterpret_cast<TestHeap*>(i_isolate()->heap());
142 static v8::base::RandomNumberGenerator* random_number_generator() {
143 return InitIsolateOnce()->random_number_generator();
146 static v8::Local<v8::Object> global() {
147 return isolate()->GetCurrentContext()->Global();
150 // TODO(dcarney): Remove.
151 // This must be called first in a test.
152 static void InitializeVM() {
153 CHECK(!v8::base::NoBarrier_Load(&isolate_used_));
154 CHECK(!initialize_called_);
155 initialize_called_ = true;
156 v8::HandleScope handle_scope(CcTest::isolate());
157 v8::Context::New(CcTest::isolate())->Enter();
160 // Only for UNINITIALIZED_TESTs
161 static void DisableAutomaticDispose();
163 // Helper function to configure a context.
164 // Must be in a HandleScope.
165 static v8::Local<v8::Context> NewContext(
166 CcTestExtensionFlags extensions,
167 v8::Isolate* isolate = CcTest::isolate());
169 static void TearDown() {
170 if (isolate_ != NULL) isolate_->Dispose();
174 friend int main(int argc, char** argv);
175 TestFunction* callback_;
178 const char* dependency_;
182 static CcTest* last_;
183 static v8::Isolate* isolate_;
184 static bool initialize_called_;
185 static v8::base::Atomic32 isolate_used_;
188 // Switches between all the Api tests using the threading support.
189 // In order to get a surprising but repeatable pattern of thread
190 // switching it has extra semaphores to control the order in which
191 // the tests alternate, not relying solely on the big V8 lock.
193 // A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
194 // callbacks. This will have no effect when we are not running the
195 // thread fuzzing test. In the thread fuzzing test it will
196 // pseudorandomly select a successor thread and switch execution
197 // to that thread, suspending the current test.
198 class ApiTestFuzzer: public v8::base::Thread {
202 // The ApiTestFuzzer is also a Thread, so it has a Run method.
205 enum PartOfTest { FIRST_PART,
209 LAST_PART = FOURTH_PART };
211 static void SetUp(PartOfTest part);
212 static void RunAllTests();
213 static void TearDown();
214 // This method switches threads if we are running the Threading test.
215 // Otherwise it does nothing.
219 explicit ApiTestFuzzer(int num)
220 : Thread(Options("ApiTestFuzzer")),
226 static bool fuzzing_;
227 static int tests_being_run_;
229 static int active_tests_;
230 static bool NextThread();
232 v8::base::Semaphore gate_;
234 void ContextSwitch();
235 static int GetNextTestNumber();
236 static v8::base::Semaphore all_tests_done_;
240 #define THREADED_TEST(Name) \
241 static void Test##Name(); \
242 RegisterThreadedTest register_##Name(Test##Name, #Name); \
246 class RegisterThreadedTest {
248 explicit RegisterThreadedTest(CcTest::TestFunction* callback,
250 : fuzzer_(NULL), callback_(callback), name_(name) {
255 static int count() { return count_; }
256 static RegisterThreadedTest* nth(int i) {
258 RegisterThreadedTest* current = first_;
261 current = current->prev_;
265 CcTest::TestFunction* callback() { return callback_; }
266 ApiTestFuzzer* fuzzer_;
267 const char* name() { return name_; }
270 static RegisterThreadedTest* first_;
272 CcTest::TestFunction* callback_;
273 RegisterThreadedTest* prev_;
277 // A LocalContext holds a reference to a v8::Context.
280 LocalContext(v8::Isolate* isolate,
281 v8::ExtensionConfiguration* extensions = 0,
282 v8::Handle<v8::ObjectTemplate> global_template =
283 v8::Handle<v8::ObjectTemplate>(),
284 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>()) {
285 Initialize(isolate, extensions, global_template, global_object);
288 LocalContext(v8::ExtensionConfiguration* extensions = 0,
289 v8::Handle<v8::ObjectTemplate> global_template =
290 v8::Handle<v8::ObjectTemplate>(),
291 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>()) {
292 Initialize(CcTest::isolate(), extensions, global_template, global_object);
295 virtual ~LocalContext() {
296 v8::HandleScope scope(isolate_);
297 v8::Local<v8::Context>::New(isolate_, context_)->Exit();
301 v8::Context* operator->() {
302 return *reinterpret_cast<v8::Context**>(&context_);
304 v8::Context* operator*() { return operator->(); }
305 bool IsReady() { return !context_.IsEmpty(); }
307 v8::Local<v8::Context> local() {
308 return v8::Local<v8::Context>::New(isolate_, context_);
312 void Initialize(v8::Isolate* isolate,
313 v8::ExtensionConfiguration* extensions,
314 v8::Handle<v8::ObjectTemplate> global_template,
315 v8::Handle<v8::Value> global_object) {
316 v8::HandleScope scope(isolate);
317 v8::Local<v8::Context> context = v8::Context::New(isolate,
321 context_.Reset(isolate, context);
323 // We can't do this later perhaps because of a fatal error.
327 v8::Persistent<v8::Context> context_;
328 v8::Isolate* isolate_;
332 static inline uint16_t* AsciiToTwoByteString(const char* source) {
333 int array_length = i::StrLength(source) + 1;
334 uint16_t* converted = i::NewArray<uint16_t>(array_length);
335 for (int i = 0; i < array_length; i++) converted[i] = source[i];
340 static inline v8::Local<v8::Value> v8_num(double x) {
341 return v8::Number::New(v8::Isolate::GetCurrent(), x);
345 static inline v8::Local<v8::String> v8_str(const char* x) {
346 return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x);
350 static inline v8::Local<v8::Symbol> v8_symbol(const char* name) {
351 return v8::Symbol::New(v8::Isolate::GetCurrent(), v8_str(name));
355 static inline v8::Local<v8::Script> v8_compile(const char* x) {
356 return v8::Script::Compile(v8_str(x));
360 static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
361 return v8::Script::Compile(x);
365 static inline v8::Local<v8::Script> CompileWithOrigin(
366 v8::Local<v8::String> source, v8::Local<v8::String> origin_url) {
367 v8::ScriptOrigin origin(origin_url);
368 v8::ScriptCompiler::Source script_source(source, origin);
369 return v8::ScriptCompiler::Compile(
370 v8::Isolate::GetCurrent(), &script_source);
374 static inline v8::Local<v8::Script> CompileWithOrigin(
375 v8::Local<v8::String> source, const char* origin_url) {
376 return CompileWithOrigin(source, v8_str(origin_url));
380 static inline v8::Local<v8::Script> CompileWithOrigin(const char* source,
381 const char* origin_url) {
382 return CompileWithOrigin(v8_str(source), v8_str(origin_url));
386 // Helper functions that compile and run the source.
387 static inline v8::Local<v8::Value> CompileRun(const char* source) {
388 return v8::Script::Compile(v8_str(source))->Run();
392 // Compiles source as an ES6 module.
393 static inline v8::Local<v8::Value> CompileRunModule(const char* source) {
394 v8::ScriptCompiler::Source script_source(v8_str(source));
395 return v8::ScriptCompiler::CompileModule(v8::Isolate::GetCurrent(),
396 &script_source)->Run();
400 static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
401 return v8::Script::Compile(source)->Run();
405 static inline v8::Local<v8::Value> ParserCacheCompileRun(const char* source) {
406 // Compile once just to get the preparse data, then compile the second time
408 v8::Isolate* isolate = v8::Isolate::GetCurrent();
409 v8::ScriptCompiler::Source script_source(v8_str(source));
410 v8::ScriptCompiler::Compile(isolate, &script_source,
411 v8::ScriptCompiler::kProduceParserCache);
413 // Check whether we received cached data, and if so use it.
414 v8::ScriptCompiler::CompileOptions options =
415 script_source.GetCachedData() ? v8::ScriptCompiler::kConsumeParserCache
416 : v8::ScriptCompiler::kNoCompileOptions;
418 return v8::ScriptCompiler::Compile(isolate, &script_source, options)->Run();
422 // Helper functions that compile and run the source with given origin.
423 static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
424 const char* origin_url,
427 v8::Isolate* isolate = v8::Isolate::GetCurrent();
428 v8::ScriptOrigin origin(v8_str(origin_url),
429 v8::Integer::New(isolate, line_number),
430 v8::Integer::New(isolate, column_number));
431 v8::ScriptCompiler::Source script_source(v8_str(source), origin);
432 return v8::ScriptCompiler::Compile(isolate, &script_source)->Run();
436 static inline v8::Local<v8::Value> CompileRunWithOrigin(
437 v8::Local<v8::String> source, const char* origin_url) {
438 v8::ScriptCompiler::Source script_source(
439 source, v8::ScriptOrigin(v8_str(origin_url)));
440 return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &script_source)
445 static inline v8::Local<v8::Value> CompileRunWithOrigin(
446 const char* source, const char* origin_url) {
447 return CompileRunWithOrigin(v8_str(source), origin_url);
452 static inline void ExpectString(const char* code, const char* expected) {
453 v8::Local<v8::Value> result = CompileRun(code);
454 CHECK(result->IsString());
455 v8::String::Utf8Value utf8(result);
456 CHECK_EQ(0, strcmp(expected, *utf8));
460 static inline void ExpectInt32(const char* code, int expected) {
461 v8::Local<v8::Value> result = CompileRun(code);
462 CHECK(result->IsInt32());
463 CHECK_EQ(expected, result->Int32Value());
467 static inline void ExpectBoolean(const char* code, bool expected) {
468 v8::Local<v8::Value> result = CompileRun(code);
469 CHECK(result->IsBoolean());
470 CHECK_EQ(expected, result->BooleanValue());
474 static inline void ExpectTrue(const char* code) {
475 ExpectBoolean(code, true);
479 static inline void ExpectFalse(const char* code) {
480 ExpectBoolean(code, false);
484 static inline void ExpectObject(const char* code,
485 v8::Local<v8::Value> expected) {
486 v8::Local<v8::Value> result = CompileRun(code);
487 CHECK(result->SameValue(expected));
491 static inline void ExpectUndefined(const char* code) {
492 v8::Local<v8::Value> result = CompileRun(code);
493 CHECK(result->IsUndefined());
497 // Helper function that simulates a full new-space in the heap.
498 static inline bool FillUpOnePage(v8::internal::NewSpace* space) {
499 v8::internal::AllocationResult allocation =
500 space->AllocateRaw(v8::internal::Page::kMaxRegularHeapObjectSize);
501 if (allocation.IsRetry()) return false;
502 v8::internal::HeapObject* free_space = NULL;
503 CHECK(allocation.To(&free_space));
504 space->heap()->CreateFillerObjectAt(
505 free_space->address(), v8::internal::Page::kMaxRegularHeapObjectSize);
510 // Helper function that simulates a fill new-space in the heap.
511 static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
513 int space_remaining = static_cast<int>(*space->allocation_limit_address() -
514 *space->allocation_top_address());
515 CHECK(space_remaining >= extra_bytes);
516 int new_linear_size = space_remaining - extra_bytes;
517 if (new_linear_size == 0) return;
518 v8::internal::AllocationResult allocation =
519 space->AllocateRaw(new_linear_size);
520 v8::internal::HeapObject* free_space = NULL;
521 CHECK(allocation.To(&free_space));
522 space->heap()->CreateFillerObjectAt(free_space->address(), new_linear_size);
526 static inline void FillCurrentPage(v8::internal::NewSpace* space) {
527 AllocateAllButNBytes(space, 0);
531 static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
532 FillCurrentPage(space);
533 while (FillUpOnePage(space)) {
538 // Helper function that simulates a full old-space in the heap.
539 static inline void SimulateFullSpace(v8::internal::PagedSpace* space) {
540 space->EmptyAllocationInfo();
541 space->ResetFreeList();
546 // Helper function that simulates many incremental marking steps until
547 // marking is completed.
548 static inline void SimulateIncrementalMarking(i::Heap* heap) {
549 i::MarkCompactCollector* collector = heap->mark_compact_collector();
550 i::IncrementalMarking* marking = heap->incremental_marking();
551 if (collector->sweeping_in_progress()) {
552 collector->EnsureSweepingCompleted();
554 CHECK(marking->IsMarking() || marking->IsStopped());
555 if (marking->IsStopped()) {
558 CHECK(marking->IsMarking());
559 while (!marking->IsComplete()) {
560 marking->Step(i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD);
562 CHECK(marking->IsComplete());
566 // Helper class for new allocations tracking and checking.
567 // To use checking of JS allocations tracking in a test,
568 // just create an instance of this class.
569 class HeapObjectsTracker {
571 HeapObjectsTracker() {
572 heap_profiler_ = i::Isolate::Current()->heap_profiler();
573 CHECK_NOT_NULL(heap_profiler_);
574 heap_profiler_->StartHeapObjectsTracking(true);
577 ~HeapObjectsTracker() {
578 i::Isolate::Current()->heap()->CollectAllAvailableGarbage();
579 CHECK_EQ(0, heap_profiler_->heap_object_map()->FindUntrackedObjects());
580 heap_profiler_->StopHeapObjectsTracking();
584 i::HeapProfiler* heap_profiler_;
588 class InitializedHandleScope {
590 InitializedHandleScope()
591 : main_isolate_(CcTest::InitIsolateOnce()),
592 handle_scope_(main_isolate_) {}
594 // Prefixing the below with main_ reduces a lot of naming clashes.
595 i::Isolate* main_isolate() { return main_isolate_; }
598 i::Isolate* main_isolate_;
599 i::HandleScope handle_scope_;
603 class HandleAndZoneScope : public InitializedHandleScope {
605 HandleAndZoneScope() {}
607 // Prefixing the below with main_ reduces a lot of naming clashes.
608 i::Zone* main_zone() { return &main_zone_; }
614 #endif // ifndef CCTEST_H_