1// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_UNIT_TEST_H_
6#define RUNTIME_VM_UNIT_TEST_H_
7
8#include "include/dart_native_api.h"
9
10#include "platform/globals.h"
11
12#include "vm/dart.h"
13#include "vm/dart_api_state.h"
14#include "vm/dart_entry.h"
15#include "vm/globals.h"
16#include "vm/heap/heap.h"
17#include "vm/isolate.h"
18#include "vm/longjump.h"
19#include "vm/object.h"
20#include "vm/object_store.h"
21#include "vm/simulator.h"
22#include "vm/zone.h"
23
24// The VM_UNIT_TEST_CASE macro is used for tests that do not need any
25// default isolate or zone functionality.
26#define VM_UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation) \
27 void Dart_Test##name(); \
28 static const dart::TestCase kRegister##name(Dart_Test##name, #name, \
29 expectation); \
30 void Dart_Test##name()
31
32#define VM_UNIT_TEST_CASE(name) VM_UNIT_TEST_CASE_WITH_EXPECTATION(name, "Pass")
33
34// The UNIT_TEST_CASE macro is used for tests that do not require any
35// functionality provided by the VM. Tests declared using this macro will be run
36// after the VM is cleaned up.
37#define UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation) \
38 void Dart_Test##name(); \
39 static const dart::RawTestCase kRegister##name(Dart_Test##name, #name, \
40 expectation); \
41 void Dart_Test##name()
42
43#define UNIT_TEST_CASE(name) UNIT_TEST_CASE_WITH_EXPECTATION(name, "Pass")
44
45// The ISOLATE_UNIT_TEST_CASE macro is used for tests that need an isolate and
46// zone in order to test its functionality. This macro is used for tests that
47// are implemented using the VM code directly and do not use the Dart API
48// for calling into the VM. The safepoint execution state of threads using
49// this macro is transitioned from kThreadInNative to kThreadInVM.
50#define ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation) \
51 static void Dart_TestHelper##name(Thread* thread); \
52 VM_UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation) { \
53 TestIsolateScope __test_isolate__; \
54 Thread* __thread__ = Thread::Current(); \
55 ASSERT(__thread__->isolate() == __test_isolate__.isolate()); \
56 TransitionNativeToVM transition(__thread__); \
57 StackZone __zone__(__thread__); \
58 HandleScope __hs__(__thread__); \
59 Dart_TestHelper##name(__thread__); \
60 } \
61 static void Dart_TestHelper##name(Thread* thread)
62
63#define ISOLATE_UNIT_TEST_CASE(name) \
64 ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(name, "Pass")
65
66// The TEST_CASE macro is used for tests that need an isolate and zone
67// in order to test its functionality. This macro is used for tests that
68// are implemented using the Dart API for calling into the VM. The safepoint
69// execution state of threads using this macro remains kThreadNative.
70#define TEST_CASE_WITH_EXPECTATION(name, expectation) \
71 static void Dart_TestHelper##name(Thread* thread); \
72 VM_UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation) { \
73 TestIsolateScope __test_isolate__; \
74 Thread* __thread__ = Thread::Current(); \
75 ASSERT(__thread__->isolate() == __test_isolate__.isolate()); \
76 TransitionNativeToVM transition1(__thread__); \
77 StackZone __zone__(__thread__); \
78 HandleScope __hs__(__thread__); \
79 TransitionVMToNative transition2(__thread__); \
80 Dart_TestHelper##name(__thread__); \
81 } \
82 static void Dart_TestHelper##name(Thread* thread)
83
84#define TEST_CASE(name) TEST_CASE_WITH_EXPECTATION(name, "Pass")
85
86// The ASSEMBLER_TEST_GENERATE macro is used to generate a unit test
87// for the assembler.
88#define ASSEMBLER_TEST_GENERATE(name, assembler) \
89 void AssemblerTestGenerate##name(compiler::Assembler* assembler)
90
91// The ASSEMBLER_TEST_EXTERN macro is used to declare a unit test
92// for the assembler.
93#define ASSEMBLER_TEST_EXTERN(name) \
94 extern void AssemblerTestGenerate##name(compiler::Assembler* assembler);
95
96// The ASSEMBLER_TEST_RUN macro is used to execute the assembler unit
97// test generated using the ASSEMBLER_TEST_GENERATE macro.
98// C++ callee-saved registers are not preserved. Arguments may be passed in.
99#define ASSEMBLER_TEST_RUN_WITH_EXPECTATION(name, test, expectation) \
100 static void AssemblerTestRun##name(AssemblerTest* test); \
101 ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation) { \
102 { \
103 bool use_far_branches = false; \
104 LongJumpScope jump; \
105 if (setjmp(*jump.Set()) == 0) { \
106 compiler::ObjectPoolBuilder object_pool_builder; \
107 compiler::Assembler assembler(&object_pool_builder, use_far_branches); \
108 AssemblerTest test("" #name, &assembler); \
109 AssemblerTestGenerate##name(test.assembler()); \
110 test.Assemble(); \
111 AssemblerTestRun##name(&test); \
112 return; \
113 } \
114 } \
115 \
116 const Error& error = Error::Handle(Thread::Current()->sticky_error()); \
117 if (error.raw() == Object::branch_offset_error().raw()) { \
118 bool use_far_branches = true; \
119 compiler::ObjectPoolBuilder object_pool_builder; \
120 compiler::Assembler assembler(&object_pool_builder, use_far_branches); \
121 AssemblerTest test("" #name, &assembler); \
122 AssemblerTestGenerate##name(test.assembler()); \
123 test.Assemble(); \
124 AssemblerTestRun##name(&test); \
125 } else { \
126 FATAL1("Unexpected error: %s\n", error.ToErrorCString()); \
127 } \
128 } \
129 static void AssemblerTestRun##name(AssemblerTest* test)
130
131#define ASSEMBLER_TEST_RUN(name, test) \
132 ASSEMBLER_TEST_RUN_WITH_EXPECTATION(name, test, "Pass")
133
134#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
135#if defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
136// Running on actual ARM hardware, execute code natively.
137#define EXECUTE_TEST_CODE_INT32(name, entry) reinterpret_cast<name>(entry)()
138#define EXECUTE_TEST_CODE_INT64(name, entry) reinterpret_cast<name>(entry)()
139#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1) \
140 reinterpret_cast<name>(entry)(long_arg0, long_arg1)
141#define EXECUTE_TEST_CODE_FLOAT(name, entry) reinterpret_cast<name>(entry)()
142#define EXECUTE_TEST_CODE_DOUBLE(name, entry) reinterpret_cast<name>(entry)()
143#define EXECUTE_TEST_CODE_INT32_F(name, entry, float_arg) \
144 reinterpret_cast<name>(entry)(float_arg)
145#define EXECUTE_TEST_CODE_INT32_D(name, entry, double_arg) \
146 reinterpret_cast<name>(entry)(double_arg)
147#define EXECUTE_TEST_CODE_INTPTR_INTPTR(name, entry, pointer_arg) \
148 reinterpret_cast<name>(entry)(pointer_arg)
149#define EXECUTE_TEST_CODE_INT32_INTPTR(name, entry, pointer_arg) \
150 reinterpret_cast<name>(entry)(pointer_arg)
151#else
152// Not running on ARM hardware, call simulator to execute code.
153#if defined(ARCH_IS_64_BIT)
154#define EXECUTE_TEST_CODE_INT64(name, entry) \
155 static_cast<int64_t>( \
156 Simulator::Current()->Call(bit_cast<int64_t, uword>(entry), 0, 0, 0, 0))
157#define EXECUTE_TEST_CODE_DOUBLE(name, entry) \
158 bit_cast<double, int64_t>(Simulator::Current()->Call( \
159 bit_cast<int64_t, uword>(entry), 0, 0, 0, 0, true))
160#define EXECUTE_TEST_CODE_INTPTR_INTPTR(name, entry, pointer_arg) \
161 static_cast<intptr_t>(Simulator::Current()->Call( \
162 bit_cast<int64_t, uword>(entry), \
163 bit_cast<int64_t, intptr_t>(pointer_arg), 0, 0, 0))
164#define EXECUTE_TEST_CODE_INT32_INTPTR(name, entry, pointer_arg) \
165 static_cast<int32_t>(Simulator::Current()->Call( \
166 bit_cast<int64_t, uword>(entry), \
167 bit_cast<int64_t, intptr_t>(pointer_arg), 0, 0, 0))
168#else
169#define EXECUTE_TEST_CODE_INT32(name, entry) \
170 static_cast<int32_t>( \
171 Simulator::Current()->Call(bit_cast<int32_t, uword>(entry), 0, 0, 0, 0))
172#define EXECUTE_TEST_CODE_DOUBLE(name, entry) \
173 bit_cast<double, int64_t>(Simulator::Current()->Call( \
174 bit_cast<int32_t, uword>(entry), 0, 0, 0, 0, true))
175#define EXECUTE_TEST_CODE_INTPTR_INTPTR(name, entry, pointer_arg) \
176 static_cast<intptr_t>(Simulator::Current()->Call( \
177 bit_cast<int32_t, uword>(entry), \
178 bit_cast<int32_t, intptr_t>(pointer_arg), 0, 0, 0))
179#define EXECUTE_TEST_CODE_INT32_INTPTR(name, entry, pointer_arg) \
180 static_cast<int32_t>(Simulator::Current()->Call( \
181 bit_cast<int32_t, uword>(entry), \
182 bit_cast<int32_t, intptr_t>(pointer_arg), 0, 0, 0))
183#endif // defined(ARCH_IS_64_BIT)
184#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1) \
185 static_cast<int64_t>(Simulator::Current()->Call( \
186 bit_cast<int32_t, uword>(entry), Utils::Low32Bits(long_arg0), \
187 Utils::High32Bits(long_arg0), Utils::Low32Bits(long_arg1), \
188 Utils::High32Bits(long_arg1)))
189#define EXECUTE_TEST_CODE_FLOAT(name, entry) \
190 bit_cast<float, int32_t>(Simulator::Current()->Call( \
191 bit_cast<int32_t, uword>(entry), 0, 0, 0, 0, true))
192#define EXECUTE_TEST_CODE_INT32_F(name, entry, float_arg) \
193 static_cast<int32_t>(Simulator::Current()->Call( \
194 bit_cast<int32_t, uword>(entry), bit_cast<int32_t, float>(float_arg), 0, \
195 0, 0, false, true))
196#define EXECUTE_TEST_CODE_INT32_D(name, entry, double_arg) \
197 static_cast<int32_t>(Simulator::Current()->Call( \
198 bit_cast<int32_t, uword>(entry), \
199 Utils::Low32Bits(bit_cast<int64_t, double>(double_arg)), \
200 Utils::High32Bits(bit_cast<int64_t, double>(double_arg)), 0, 0, false, \
201 true))
202#endif // defined(HOST_ARCH_ARM)
203#endif // defined(TARGET_ARCH_{ARM, ARM64})
204
205#define ZONE_STR(FMT, ...) \
206 OS::SCreate(Thread::Current()->zone(), FMT, __VA_ARGS__)
207
208inline Dart_Handle NewString(const char* str) {
209 return Dart_NewStringFromCString(str);
210}
211
212namespace dart {
213
214// Forward declarations.
215namespace compiler {
216class Assembler;
217}
218class CodeGenerator;
219class VirtualMemory;
220
221namespace bin {
222// Snapshot pieces if we link in a snapshot, otherwise initialized to NULL.
223extern const uint8_t* vm_snapshot_data;
224extern const uint8_t* vm_snapshot_instructions;
225extern const uint8_t* core_isolate_snapshot_data;
226extern const uint8_t* core_isolate_snapshot_instructions;
227} // namespace bin
228
229extern const uint8_t* platform_strong_dill;
230extern const intptr_t platform_strong_dill_size;
231
232class TesterState : public AllStatic {
233 public:
234 static const uint8_t* vm_snapshot_data;
235 static Dart_IsolateGroupCreateCallback create_callback;
236 static Dart_IsolateShutdownCallback shutdown_callback;
237 static Dart_IsolateGroupCleanupCallback group_cleanup_callback;
238 static const char** argv;
239 static int argc;
240};
241
242class KernelBufferList {
243 public:
244 explicit KernelBufferList(const uint8_t* kernel_buffer)
245 : kernel_buffer_(kernel_buffer), next_(NULL) {}
246
247 KernelBufferList(const uint8_t* kernel_buffer, KernelBufferList* next)
248 : kernel_buffer_(kernel_buffer), next_(next) {}
249
250 ~KernelBufferList() {
251 free(const_cast<uint8_t*>(kernel_buffer_));
252 if (next_ != NULL) {
253 delete next_;
254 }
255 }
256
257 void AddBufferToList(const uint8_t* kernel_buffer);
258
259 private:
260 const uint8_t* kernel_buffer_;
261 KernelBufferList* next_;
262};
263
264class TestCaseBase {
265 public:
266 explicit TestCaseBase(const char* name, const char* expectation);
267 virtual ~TestCaseBase() {}
268
269 const char* name() const { return name_; }
270 const char* expectation() const { return expectation_; }
271
272 virtual void Run() = 0;
273 void RunTest();
274
275 static void RunAll();
276 static void RunAllRaw();
277 static void CleanupState();
278 static void AddToKernelBuffers(const uint8_t* kernel_buffer);
279
280 protected:
281 static KernelBufferList* current_kernel_buffers_;
282 bool raw_test_;
283
284 private:
285 static TestCaseBase* first_;
286 static TestCaseBase* tail_;
287
288 TestCaseBase* next_;
289 const char* name_;
290 const char* expectation_;
291
292 DISALLOW_COPY_AND_ASSIGN(TestCaseBase);
293};
294
295#define USER_TEST_URI "test-lib"
296#define RESOLVED_USER_TEST_URI "file:///test-lib"
297#define CORELIB_TEST_URI "dart:test-lib"
298
299class TestCase : TestCaseBase {
300 public:
301 typedef void(RunEntry)();
302
303 TestCase(RunEntry* run, const char* name, const char* expectation)
304 : TestCaseBase(name, expectation), run_(run) {}
305
306 static char* CompileTestScriptWithDFE(const char* url,
307 const char* source,
308 const uint8_t** kernel_buffer,
309 intptr_t* kernel_buffer_size,
310 bool incrementally = true,
311 bool allow_compile_errors = false,
312 const char* multiroot_filepaths = NULL,
313 const char* multiroot_scheme = NULL);
314 static char* CompileTestScriptWithDFE(const char* url,
315 int sourcefiles_count,
316 Dart_SourceFile sourcefiles[],
317 const uint8_t** kernel_buffer,
318 intptr_t* kernel_buffer_size,
319 bool incrementally = true,
320 bool allow_compile_errors = false,
321 const char* multiroot_filepaths = NULL,
322 const char* multiroot_scheme = NULL);
323 static Dart_Handle LoadTestScript(
324 const char* script,
325 Dart_NativeEntryResolver resolver,
326 const char* lib_uri = RESOLVED_USER_TEST_URI,
327 bool finalize = true,
328 bool allow_compile_errors = false);
329 static Dart_Handle LoadTestScriptWithErrors(
330 const char* script,
331 Dart_NativeEntryResolver resolver = NULL,
332 const char* lib_uri = RESOLVED_USER_TEST_URI,
333 bool finalize = true);
334 static Dart_Handle LoadTestLibrary(const char* lib_uri,
335 const char* script,
336 Dart_NativeEntryResolver resolver = NULL);
337 static Dart_Handle LoadTestScriptWithDFE(
338 int sourcefiles_count,
339 Dart_SourceFile sourcefiles[],
340 Dart_NativeEntryResolver resolver = NULL,
341 bool finalize = true,
342 bool incrementally = true,
343 bool allow_compile_errors = false,
344 const char* entry_script_uri = NULL,
345 const char* multiroot_filepaths = NULL,
346 const char* multiroot_scheme = NULL);
347 static Dart_Handle LoadCoreTestScript(const char* script,
348 Dart_NativeEntryResolver resolver);
349
350 static Dart_Handle EvaluateExpression(const Library& lib,
351 const String& expr,
352 const Array& param_names,
353 const Array& param_values);
354
355 static Dart_Handle lib();
356 static const char* url();
357 static Dart_Isolate CreateTestIsolateFromSnapshot(uint8_t* buffer,
358 const char* name = NULL) {
359 return CreateIsolate(buffer, 0, NULL, name);
360 }
361 static Dart_Isolate CreateTestIsolate(const char* name = nullptr,
362 void* isolate_group_data = nullptr,
363 void* isolate_data = nullptr);
364 static Dart_Isolate CreateTestIsolateInGroup(const char* name,
365 Dart_Isolate parent,
366 void* group_data = nullptr,
367 void* isolate_data = nullptr);
368
369 static Dart_Handle library_handler(Dart_LibraryTag tag,
370 Dart_Handle library,
371 Dart_Handle url);
372
373 virtual void Run();
374
375 // Sets |script| to be the source used at next reload.
376 static Dart_Handle SetReloadTestScript(const char* script);
377
378 // Initiates the reload.
379 static Dart_Handle TriggerReload(const uint8_t* kernel_buffer,
380 intptr_t kernel_buffer_size);
381
382 // Helper function which reloads the current isolate using |script|.
383 static Dart_Handle ReloadTestScript(const char* script);
384
385 // Helper function which reloads the current isolate using |script|.
386 static Dart_Handle ReloadTestKernel(const uint8_t* kernel_buffer,
387 intptr_t kernel_buffer_size);
388
389 static void AddTestLib(const char* url, const char* source);
390 static const char* GetTestLib(const char* url);
391
392 // Return true if non-nullable experiment is enabled.
393 static bool IsNNBD();
394
395 static const char* NullableTag() { return IsNNBD() ? "?" : ""; }
396 static const char* NullAssertTag() { return IsNNBD() ? "!" : ""; }
397 static const char* LateTag() { return IsNNBD() ? "late" : ""; }
398
399 private:
400 // |data_buffer| can either be snapshot data, or kernel binary data.
401 // If |data_buffer| is snapshot data, then |len| should be zero as snapshot
402 // size is encoded within them. If |len| is non-zero, then |data_buffer|
403 // will be treated as a kernel binary (but CreateIsolate will not
404 // take ownership of the buffer) and |instr_buffer| will be ignored.
405 static Dart_Isolate CreateIsolate(const uint8_t* data_buffer,
406 intptr_t len,
407 const uint8_t* instr_buffer,
408 const char* name,
409 void* group_data = nullptr,
410 void* isolate_data = nullptr);
411
412 static char* ValidateCompilationResult(Zone* zone,
413 Dart_KernelCompilationResult result,
414 const uint8_t** kernel_buffer,
415 intptr_t* kernel_buffer_size,
416 bool allow_compile_errors);
417
418 RunEntry* const run_;
419};
420
421class RawTestCase : TestCaseBase {
422 public:
423 typedef void(RunEntry)();
424
425 RawTestCase(RunEntry* run, const char* name, const char* expectation)
426 : TestCaseBase(name, expectation), run_(run) {
427 raw_test_ = true;
428 }
429 virtual void Run();
430
431 private:
432 RunEntry* const run_;
433};
434
435class TestIsolateScope {
436 public:
437 TestIsolateScope() {
438 isolate_ = reinterpret_cast<Isolate*>(TestCase::CreateTestIsolate());
439 Dart_EnterScope(); // Create a Dart API scope for unit tests.
440 }
441 ~TestIsolateScope() {
442 Dart_ExitScope(); // Exit the Dart API scope created for unit tests.
443 ASSERT(isolate_ == Isolate::Current());
444 Dart_ShutdownIsolate();
445 isolate_ = NULL;
446 }
447 Isolate* isolate() const { return isolate_; }
448
449 private:
450 Isolate* isolate_;
451
452 DISALLOW_COPY_AND_ASSIGN(TestIsolateScope);
453};
454
455// Ensures core libraries are initialized, thereby allowing vm/cc tests to
456// e.g. run functions using microtasks.
457void SetupCoreLibrariesForUnitTest();
458
459template <typename T>
460struct is_void {
461 static const bool value = false;
462};
463
464template <>
465struct is_void<void> {
466 static const bool value = true;
467};
468
469template <typename T>
470struct is_double {
471 static const bool value = false;
472};
473
474template <>
475struct is_double<double> {
476 static const bool value = true;
477};
478
479class AssemblerTest {
480 public:
481 AssemblerTest(const char* name, compiler::Assembler* assembler)
482 : name_(name),
483 assembler_(assembler),
484 code_(Code::ZoneHandle()),
485 disassembly_(Thread::Current()->zone()->Alloc<char>(DISASSEMBLY_SIZE)) {
486 ASSERT(name != NULL);
487 ASSERT(assembler != NULL);
488 }
489 ~AssemblerTest() {}
490
491 compiler::Assembler* assembler() const { return assembler_; }
492
493 const Code& code() const { return code_; }
494
495 uword payload_start() const { return code_.PayloadStart(); }
496 uword payload_size() const { return assembler_->CodeSize(); }
497 uword entry() const { return code_.EntryPoint(); }
498
499// Invoke/InvokeWithCodeAndThread is used to call assembler test functions
500// using the ABI calling convention.
501// ResultType is the return type of the assembler test function.
502// ArgNType is the type of the Nth argument.
503#if defined(USING_SIMULATOR)
504
505#if defined(ARCH_IS_64_BIT)
506 // TODO(fschneider): Make InvokeWithCodeAndThread<> more general and work on
507 // 32-bit.
508 // Since Simulator::Call always return a int64_t, bit_cast does not work
509 // on 32-bit platforms when returning an int32_t. Since template functions
510 // don't support partial specialization, we'd need to introduce a helper
511 // class to support 32-bit return types.
512 template <typename ResultType>
513 ResultType InvokeWithCodeAndThread() {
514 const bool fp_return = is_double<ResultType>::value;
515 const bool fp_args = false;
516 Thread* thread = Thread::Current();
517 ASSERT(thread != NULL);
518 return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
519 bit_cast<intptr_t, uword>(entry()), reinterpret_cast<intptr_t>(&code_),
520 reinterpret_cast<intptr_t>(thread), 0, 0, fp_return, fp_args));
521 }
522 template <typename ResultType, typename Arg1Type>
523 ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
524 const bool fp_return = is_double<ResultType>::value;
525 const bool fp_args = is_double<Arg1Type>::value;
526 // TODO(fschneider): Support double arguments for simulator calls.
527 COMPILE_ASSERT(!fp_args);
528 Thread* thread = Thread::Current();
529 ASSERT(thread != NULL);
530 return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
531 bit_cast<intptr_t, uword>(entry()), reinterpret_cast<intptr_t>(&code_),
532 reinterpret_cast<intptr_t>(thread), reinterpret_cast<intptr_t>(arg1), 0,
533 fp_return, fp_args));
534 }
535#endif // ARCH_IS_64_BIT
536
537 template <typename ResultType,
538 typename Arg1Type,
539 typename Arg2Type,
540 typename Arg3Type>
541 ResultType Invoke(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3) {
542 // TODO(fschneider): Support double arguments for simulator calls.
543 COMPILE_ASSERT(is_void<ResultType>::value);
544 COMPILE_ASSERT(!is_double<Arg1Type>::value);
545 COMPILE_ASSERT(!is_double<Arg2Type>::value);
546 COMPILE_ASSERT(!is_double<Arg3Type>::value);
547 const bool fp_args = false;
548 const bool fp_return = false;
549 Simulator::Current()->Call(
550 bit_cast<intptr_t, uword>(entry()), static_cast<intptr_t>(arg1),
551 static_cast<intptr_t>(arg2), reinterpret_cast<intptr_t>(arg3), 0,
552 fp_return, fp_args);
553 }
554#else
555 template <typename ResultType>
556 ResultType InvokeWithCodeAndThread() {
557 Thread* thread = Thread::Current();
558 ASSERT(thread != NULL);
559 typedef ResultType (*FunctionType)(const Code&, Thread*);
560 return reinterpret_cast<FunctionType>(entry())(code_, thread);
561 }
562
563 template <typename ResultType, typename Arg1Type>
564 ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
565 Thread* thread = Thread::Current();
566 ASSERT(thread != NULL);
567 typedef ResultType (*FunctionType)(const Code&, Thread*, Arg1Type);
568 return reinterpret_cast<FunctionType>(entry())(code_, thread, arg1);
569 }
570
571 template <typename ResultType,
572 typename Arg1Type,
573 typename Arg2Type,
574 typename Arg3Type>
575 ResultType Invoke(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3) {
576 typedef ResultType (*FunctionType)(Arg1Type, Arg2Type, Arg3Type);
577 return reinterpret_cast<FunctionType>(entry())(arg1, arg2, arg3);
578 }
579#endif // defined(USING_SIMULATOR)
580
581 // Assemble test and set code_.
582 void Assemble();
583
584 // Disassembly of the code with large constants blanked out.
585 char* BlankedDisassembly() { return disassembly_; }
586
587 private:
588 const char* name_;
589 compiler::Assembler* assembler_;
590 Code& code_;
591 static const intptr_t DISASSEMBLY_SIZE = 10240;
592 char* disassembly_;
593
594 DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
595};
596
597class CompilerTest : public AllStatic {
598 public:
599 // Test the Compiler::CompileFunction functionality by checking the return
600 // value to see if no parse errors were reported.
601 static bool TestCompileFunction(const Function& function);
602};
603
604#define EXPECT_VALID(handle) \
605 do { \
606 Dart_Handle tmp_handle = (handle); \
607 if (!Api::IsValid(tmp_handle)) { \
608 dart::Expect(__FILE__, __LINE__) \
609 .Fail( \
610 "expected '%s' to be a valid handle but '%s' has already been " \
611 "freed\n", \
612 #handle, #handle); \
613 } \
614 if (Dart_IsError(tmp_handle)) { \
615 dart::Expect(__FILE__, __LINE__) \
616 .Fail( \
617 "expected '%s' to be a valid handle but found an error " \
618 "handle:\n" \
619 " '%s'\n", \
620 #handle, Dart_GetError(tmp_handle)); \
621 } \
622 } while (0)
623
624#define EXPECT_ERROR(handle, substring) \
625 do { \
626 Dart_Handle tmp_handle = (handle); \
627 if (Dart_IsError(tmp_handle)) { \
628 dart::Expect(__FILE__, __LINE__) \
629 .IsSubstring((substring), Dart_GetError(tmp_handle)); \
630 } else { \
631 dart::Expect(__FILE__, __LINE__) \
632 .Fail( \
633 "expected '%s' to be an error handle but found a valid " \
634 "handle.\n", \
635 #handle); \
636 } \
637 } while (0)
638
639#define EXPECT_TRUE(handle) \
640 do { \
641 Dart_Handle tmp_handle = (handle); \
642 if (Dart_IsBoolean(tmp_handle)) { \
643 bool value; \
644 Dart_BooleanValue(tmp_handle, &value); \
645 if (!value) { \
646 dart::Expect(__FILE__, __LINE__) \
647 .Fail("expected True, but was '%s'\n", #handle); \
648 } \
649 } else { \
650 dart::Expect(__FILE__, __LINE__) \
651 .Fail("expected True, but was '%s'\n", #handle); \
652 } \
653 } while (0)
654
655#define EXPECT_NULL(handle) \
656 do { \
657 Dart_Handle tmp_handle = (handle); \
658 if (!Dart_IsNull(tmp_handle)) { \
659 dart::Expect(__FILE__, __LINE__) \
660 .Fail("expected '%s' to be a null handle.\n", #handle); \
661 } \
662 } while (0)
663
664#define EXPECT_NON_NULL(handle) \
665 do { \
666 Dart_Handle tmp_handle = (handle); \
667 if (Dart_IsNull(tmp_handle)) { \
668 dart::Expect(__FILE__, __LINE__) \
669 .Fail("expected '%s' to be a non-null handle.\n", #handle); \
670 } \
671 } while (0)
672
673// Elide a substring which starts with some prefix and ends with a ".
674//
675// This is used to remove non-deterministic or fragile substrings from
676// JSON output.
677//
678// For example:
679//
680// prefix = "classes"
681// in = "\"id\":\"classes/46\""
682//
683// Yields:
684//
685// out = "\"id\":\"\""
686//
687void ElideJSONSubstring(const char* prefix, const char* in, char* out);
688
689template <typename T>
690class SetFlagScope : public ValueObject {
691 public:
692 SetFlagScope(T* flag, T value) : flag_(flag), original_value_(*flag) {
693 *flag_ = value;
694 }
695
696 ~SetFlagScope() { *flag_ = original_value_; }
697
698 private:
699 T* flag_;
700 T original_value_;
701};
702
703} // namespace dart
704
705#endif // RUNTIME_VM_UNIT_TEST_H_
706