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 "src/v8.h"
32
33#include "src/isolate-inl.h"
34
35#ifndef TEST
36#define TEST(Name)                                                             \
37  static void Test##Name();                                                    \
38  CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true, true);  \
39  static void Test##Name()
40#endif
41
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()
47#endif
48
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()
54#endif
55
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()
61#endif
62
63#ifndef DISABLED_TEST
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()
68#endif
69
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")
75
76#define DEFINE_EXTENSION_ID(Name, Ident) Name##_ID,
77enum CcTestExtensionIds {
78  EXTENSION_LIST(DEFINE_EXTENSION_ID)
79  kMaxExtensions
80};
81#undef DEFINE_EXTENSION_ID
82
83typedef 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
90
91
92// Use this to expose protected methods in i::Heap.
93class TestHeap : public i::Heap {
94 public:
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};
103
104
105class CcTest {
106 public:
107  typedef void (TestFunction)();
108  CcTest(TestFunction* callback, const char* file, const char* name,
109         const char* dependency, bool enabled, bool initialize);
110  void Run();
111  static CcTest* last() { return last_; }
112  CcTest* prev() { return prev_; }
113  const char* file() { return file_; }
114  const char* name() { return name_; }
115  const char* dependency() { return dependency_; }
116  bool enabled() { return enabled_; }
117
118  static v8::Isolate* isolate() {
119    CHECK(isolate_ != NULL);
120    isolate_used_ = true;
121    return isolate_;
122  }
123
124  static i::Isolate* InitIsolateOnce() {
125    if (!initialize_called_) InitializeVM();
126    return i_isolate();
127  }
128
129  static i::Isolate* i_isolate() {
130    return reinterpret_cast<i::Isolate*>(isolate());
131  }
132
133  static i::Heap* heap() {
134    return i_isolate()->heap();
135  }
136
137  static TestHeap* test_heap() {
138    return reinterpret_cast<TestHeap*>(i_isolate()->heap());
139  }
140
141  static v8::base::RandomNumberGenerator* random_number_generator() {
142    return InitIsolateOnce()->random_number_generator();
143  }
144
145  static v8::Local<v8::Object> global() {
146    return isolate()->GetCurrentContext()->Global();
147  }
148
149  // TODO(dcarney): Remove.
150  // This must be called first in a test.
151  static void InitializeVM() {
152    CHECK(!isolate_used_);
153    CHECK(!initialize_called_);
154    initialize_called_ = true;
155    v8::HandleScope handle_scope(CcTest::isolate());
156    v8::Context::New(CcTest::isolate())->Enter();
157  }
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      CcTestExtensionFlags extensions,
166      v8::Isolate* isolate = CcTest::isolate());
167
168  static void TearDown() {
169    if (isolate_ != NULL) isolate_->Dispose();
170  }
171
172 private:
173  friend int main(int argc, char** argv);
174  TestFunction* callback_;
175  const char* file_;
176  const char* name_;
177  const char* dependency_;
178  bool enabled_;
179  bool initialize_;
180  CcTest* prev_;
181  static CcTest* last_;
182  static v8::Isolate* isolate_;
183  static bool initialize_called_;
184  static bool isolate_used_;
185};
186
187// Switches between all the Api tests using the threading support.
188// In order to get a surprising but repeatable pattern of thread
189// switching it has extra semaphores to control the order in which
190// the tests alternate, not relying solely on the big V8 lock.
191//
192// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
193// callbacks.  This will have no effect when we are not running the
194// thread fuzzing test.  In the thread fuzzing test it will
195// pseudorandomly select a successor thread and switch execution
196// to that thread, suspending the current test.
197class ApiTestFuzzer: public v8::base::Thread {
198 public:
199  void CallTest();
200
201  // The ApiTestFuzzer is also a Thread, so it has a Run method.
202  virtual void Run();
203
204  enum PartOfTest { FIRST_PART,
205                    SECOND_PART,
206                    THIRD_PART,
207                    FOURTH_PART,
208                    LAST_PART = FOURTH_PART };
209
210  static void SetUp(PartOfTest part);
211  static void RunAllTests();
212  static void TearDown();
213  // This method switches threads if we are running the Threading test.
214  // Otherwise it does nothing.
215  static void Fuzz();
216
217 private:
218  explicit ApiTestFuzzer(int num)
219      : Thread(Options("ApiTestFuzzer")),
220        test_number_(num),
221        gate_(0),
222        active_(true) {}
223  ~ApiTestFuzzer() {}
224
225  static bool fuzzing_;
226  static int tests_being_run_;
227  static int current_;
228  static int active_tests_;
229  static bool NextThread();
230  int test_number_;
231  v8::base::Semaphore gate_;
232  bool active_;
233  void ContextSwitch();
234  static int GetNextTestNumber();
235  static v8::base::Semaphore all_tests_done_;
236};
237
238
239#define THREADED_TEST(Name)                                          \
240  static void Test##Name();                                          \
241  RegisterThreadedTest register_##Name(Test##Name, #Name);           \
242  /* */ TEST(Name)
243
244
245class RegisterThreadedTest {
246 public:
247  explicit RegisterThreadedTest(CcTest::TestFunction* callback,
248                                const char* name)
249      : fuzzer_(NULL), callback_(callback), name_(name) {
250    prev_ = first_;
251    first_ = this;
252    count_++;
253  }
254  static int count() { return count_; }
255  static RegisterThreadedTest* nth(int i) {
256    CHECK(i < count());
257    RegisterThreadedTest* current = first_;
258    while (i > 0) {
259      i--;
260      current = current->prev_;
261    }
262    return current;
263  }
264  CcTest::TestFunction* callback() { return callback_; }
265  ApiTestFuzzer* fuzzer_;
266  const char* name() { return name_; }
267
268 private:
269  static RegisterThreadedTest* first_;
270  static int count_;
271  CcTest::TestFunction* callback_;
272  RegisterThreadedTest* prev_;
273  const char* name_;
274};
275
276// A LocalContext holds a reference to a v8::Context.
277class LocalContext {
278 public:
279  LocalContext(v8::Isolate* isolate,
280               v8::ExtensionConfiguration* extensions = 0,
281               v8::Handle<v8::ObjectTemplate> global_template =
282                   v8::Handle<v8::ObjectTemplate>(),
283               v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>()) {
284    Initialize(isolate, extensions, global_template, global_object);
285  }
286
287  LocalContext(v8::ExtensionConfiguration* extensions = 0,
288               v8::Handle<v8::ObjectTemplate> global_template =
289                   v8::Handle<v8::ObjectTemplate>(),
290               v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>()) {
291    Initialize(CcTest::isolate(), extensions, global_template, global_object);
292  }
293
294  virtual ~LocalContext() {
295    v8::HandleScope scope(isolate_);
296    v8::Local<v8::Context>::New(isolate_, context_)->Exit();
297    context_.Reset();
298  }
299
300  v8::Context* operator->() {
301    return *reinterpret_cast<v8::Context**>(&context_);
302  }
303  v8::Context* operator*() { return operator->(); }
304  bool IsReady() { return !context_.IsEmpty(); }
305
306  v8::Local<v8::Context> local() {
307    return v8::Local<v8::Context>::New(isolate_, context_);
308  }
309
310 private:
311  void Initialize(v8::Isolate* isolate,
312                  v8::ExtensionConfiguration* extensions,
313                  v8::Handle<v8::ObjectTemplate> global_template,
314                  v8::Handle<v8::Value> global_object) {
315     v8::HandleScope scope(isolate);
316     v8::Local<v8::Context> context = v8::Context::New(isolate,
317                                                       extensions,
318                                                       global_template,
319                                                       global_object);
320     context_.Reset(isolate, context);
321     context->Enter();
322     // We can't do this later perhaps because of a fatal error.
323     isolate_ = isolate;
324  }
325
326  v8::Persistent<v8::Context> context_;
327  v8::Isolate* isolate_;
328};
329
330
331static inline uint16_t* AsciiToTwoByteString(const char* source) {
332  int array_length = i::StrLength(source) + 1;
333  uint16_t* converted = i::NewArray<uint16_t>(array_length);
334  for (int i = 0; i < array_length; i++) converted[i] = source[i];
335  return converted;
336}
337
338
339static inline v8::Local<v8::Value> v8_num(double x) {
340  return v8::Number::New(v8::Isolate::GetCurrent(), x);
341}
342
343
344static inline v8::Local<v8::String> v8_str(const char* x) {
345  return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x);
346}
347
348
349static inline v8::Local<v8::Script> v8_compile(const char* x) {
350  return v8::Script::Compile(v8_str(x));
351}
352
353
354static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
355  return v8::Script::Compile(x);
356}
357
358
359static inline v8::Local<v8::Script> CompileWithOrigin(
360    v8::Local<v8::String> source, v8::Local<v8::String> origin_url) {
361  v8::ScriptOrigin origin(origin_url);
362  v8::ScriptCompiler::Source script_source(source, origin);
363  return v8::ScriptCompiler::Compile(
364      v8::Isolate::GetCurrent(), &script_source);
365}
366
367
368static inline v8::Local<v8::Script> CompileWithOrigin(
369    v8::Local<v8::String> source, const char* origin_url) {
370  return CompileWithOrigin(source, v8_str(origin_url));
371}
372
373
374static inline v8::Local<v8::Script> CompileWithOrigin(const char* source,
375                                                      const char* origin_url) {
376  return CompileWithOrigin(v8_str(source), v8_str(origin_url));
377}
378
379
380// Helper functions that compile and run the source.
381static inline v8::Local<v8::Value> CompileRun(const char* source) {
382  return v8::Script::Compile(v8_str(source))->Run();
383}
384
385
386static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
387  return v8::Script::Compile(source)->Run();
388}
389
390
391static inline v8::Local<v8::Value> ParserCacheCompileRun(const char* source) {
392  // Compile once just to get the preparse data, then compile the second time
393  // using the data.
394  v8::Isolate* isolate = v8::Isolate::GetCurrent();
395  v8::ScriptCompiler::Source script_source(v8_str(source));
396  v8::ScriptCompiler::Compile(isolate, &script_source,
397                              v8::ScriptCompiler::kProduceParserCache);
398
399  // Check whether we received cached data, and if so use it.
400  v8::ScriptCompiler::CompileOptions options =
401      script_source.GetCachedData() ? v8::ScriptCompiler::kConsumeParserCache
402                                    : v8::ScriptCompiler::kNoCompileOptions;
403
404  return v8::ScriptCompiler::Compile(isolate, &script_source, options)->Run();
405}
406
407
408// Helper functions that compile and run the source with given origin.
409static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
410                                                        const char* origin_url,
411                                                        int line_number,
412                                                        int column_number) {
413  v8::Isolate* isolate = v8::Isolate::GetCurrent();
414  v8::ScriptOrigin origin(v8_str(origin_url),
415                          v8::Integer::New(isolate, line_number),
416                          v8::Integer::New(isolate, column_number));
417  v8::ScriptCompiler::Source script_source(v8_str(source), origin);
418  return v8::ScriptCompiler::Compile(isolate, &script_source)->Run();
419}
420
421
422static inline v8::Local<v8::Value> CompileRunWithOrigin(
423    v8::Local<v8::String> source, const char* origin_url) {
424  v8::ScriptCompiler::Source script_source(
425      source, v8::ScriptOrigin(v8_str(origin_url)));
426  return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &script_source)
427      ->Run();
428}
429
430
431static inline v8::Local<v8::Value> CompileRunWithOrigin(
432    const char* source, const char* origin_url) {
433  return CompileRunWithOrigin(v8_str(source), origin_url);
434}
435
436
437
438static inline void ExpectString(const char* code, const char* expected) {
439  v8::Local<v8::Value> result = CompileRun(code);
440  CHECK(result->IsString());
441  v8::String::Utf8Value utf8(result);
442  CHECK_EQ(expected, *utf8);
443}
444
445
446static inline void ExpectInt32(const char* code, int expected) {
447  v8::Local<v8::Value> result = CompileRun(code);
448  CHECK(result->IsInt32());
449  CHECK_EQ(expected, result->Int32Value());
450}
451
452
453static inline void ExpectBoolean(const char* code, bool expected) {
454  v8::Local<v8::Value> result = CompileRun(code);
455  CHECK(result->IsBoolean());
456  CHECK_EQ(expected, result->BooleanValue());
457}
458
459
460static inline void ExpectTrue(const char* code) {
461  ExpectBoolean(code, true);
462}
463
464
465static inline void ExpectFalse(const char* code) {
466  ExpectBoolean(code, false);
467}
468
469
470static inline void ExpectObject(const char* code,
471                                v8::Local<v8::Value> expected) {
472  v8::Local<v8::Value> result = CompileRun(code);
473  CHECK(result->SameValue(expected));
474}
475
476
477static inline void ExpectUndefined(const char* code) {
478  v8::Local<v8::Value> result = CompileRun(code);
479  CHECK(result->IsUndefined());
480}
481
482
483// Helper function that simulates a full new-space in the heap.
484static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
485  int new_linear_size = static_cast<int>(
486      *space->allocation_limit_address() - *space->allocation_top_address());
487  if (new_linear_size == 0) return;
488  v8::internal::AllocationResult allocation =
489      space->AllocateRaw(new_linear_size);
490  v8::internal::FreeListNode* node =
491      v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
492  node->set_size(space->heap(), new_linear_size);
493}
494
495
496// Helper function that simulates a full old-space in the heap.
497static inline void SimulateFullSpace(v8::internal::PagedSpace* space) {
498  space->EmptyAllocationInfo();
499  space->ResetFreeList();
500  space->ClearStats();
501}
502
503
504// Helper function that simulates many incremental marking steps until
505// marking is completed.
506static inline void SimulateIncrementalMarking(i::Heap* heap) {
507  i::MarkCompactCollector* collector = heap->mark_compact_collector();
508  i::IncrementalMarking* marking = heap->incremental_marking();
509  if (collector->sweeping_in_progress()) {
510    collector->EnsureSweepingCompleted();
511  }
512  CHECK(marking->IsMarking() || marking->IsStopped());
513  if (marking->IsStopped()) {
514    marking->Start();
515  }
516  CHECK(marking->IsMarking());
517  while (!marking->IsComplete()) {
518    marking->Step(i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD);
519  }
520  CHECK(marking->IsComplete());
521}
522
523
524// Helper class for new allocations tracking and checking.
525// To use checking of JS allocations tracking in a test,
526// just create an instance of this class.
527class HeapObjectsTracker {
528 public:
529  HeapObjectsTracker() {
530    heap_profiler_ = i::Isolate::Current()->heap_profiler();
531    CHECK_NE(NULL, heap_profiler_);
532    heap_profiler_->StartHeapObjectsTracking(true);
533  }
534
535  ~HeapObjectsTracker() {
536    i::Isolate::Current()->heap()->CollectAllAvailableGarbage();
537    CHECK_EQ(0, heap_profiler_->heap_object_map()->FindUntrackedObjects());
538    heap_profiler_->StopHeapObjectsTracking();
539  }
540
541 private:
542  i::HeapProfiler* heap_profiler_;
543};
544
545
546class InitializedHandleScope {
547 public:
548  InitializedHandleScope()
549      : main_isolate_(CcTest::InitIsolateOnce()),
550        handle_scope_(main_isolate_) {}
551
552  // Prefixing the below with main_ reduces a lot of naming clashes.
553  i::Isolate* main_isolate() { return main_isolate_; }
554
555 private:
556  i::Isolate* main_isolate_;
557  i::HandleScope handle_scope_;
558};
559
560
561class HandleAndZoneScope : public InitializedHandleScope {
562 public:
563  HandleAndZoneScope() : main_zone_(main_isolate()) {}
564
565  // Prefixing the below with main_ reduces a lot of naming clashes.
566  i::Zone* main_zone() { return &main_zone_; }
567
568 private:
569  i::Zone main_zone_;
570};
571
572#endif  // ifndef CCTEST_H_
573