2011-10-05 05:20:07 +00:00
|
|
|
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
#ifndef VM_UNIT_TEST_H_
|
|
|
|
#define VM_UNIT_TEST_H_
|
|
|
|
|
2014-09-09 21:47:44 +00:00
|
|
|
#include "include/dart_native_api.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
|
2014-04-02 17:39:32 +00:00
|
|
|
#include "platform/globals.h"
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/ast.h"
|
|
|
|
#include "vm/dart.h"
|
|
|
|
#include "vm/globals.h"
|
|
|
|
#include "vm/heap.h"
|
|
|
|
#include "vm/isolate.h"
|
2011-11-04 22:08:13 +00:00
|
|
|
#include "vm/longjump.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/object.h"
|
|
|
|
#include "vm/object_store.h"
|
2013-02-07 00:55:47 +00:00
|
|
|
#include "vm/simulator.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/zone.h"
|
|
|
|
|
|
|
|
// The UNIT_TEST_CASE macro is used for tests that do not need any
|
|
|
|
// default isolate or zone functionality.
|
|
|
|
#define UNIT_TEST_CASE(name) \
|
|
|
|
void Dart_Test##name(); \
|
|
|
|
static const dart::TestCase kRegister##name(Dart_Test##name, #name); \
|
|
|
|
void Dart_Test##name()
|
|
|
|
|
|
|
|
// The TEST_CASE macro is used for tests that need an isolate and zone
|
|
|
|
// in order to test its functionality.
|
|
|
|
#define TEST_CASE(name) \
|
2015-09-02 00:18:55 +00:00
|
|
|
static void Dart_TestHelper##name(Thread* thread); \
|
2011-10-05 05:20:07 +00:00
|
|
|
UNIT_TEST_CASE(name) \
|
|
|
|
{ \
|
|
|
|
TestIsolateScope __test_isolate__; \
|
2015-08-13 20:11:30 +00:00
|
|
|
Thread* __thread__ = Thread::Current(); \
|
|
|
|
ASSERT(__thread__->isolate() == __test_isolate__.isolate()); \
|
|
|
|
StackZone __zone__(__thread__); \
|
|
|
|
HandleScope __hs__(__thread__); \
|
2015-09-02 00:18:55 +00:00
|
|
|
Dart_TestHelper##name(__thread__); \
|
2011-10-05 05:20:07 +00:00
|
|
|
} \
|
2015-09-02 00:18:55 +00:00
|
|
|
static void Dart_TestHelper##name(Thread* thread)
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
// The ASSEMBLER_TEST_GENERATE macro is used to generate a unit test
|
|
|
|
// for the assembler.
|
|
|
|
#define ASSEMBLER_TEST_GENERATE(name, assembler) \
|
2012-06-22 23:48:51 +00:00
|
|
|
void AssemblerTestGenerate##name(Assembler* assembler)
|
|
|
|
|
|
|
|
// The ASSEMBLER_TEST_EXTERN macro is used to declare a unit test
|
|
|
|
// for the assembler.
|
|
|
|
#define ASSEMBLER_TEST_EXTERN(name) \
|
|
|
|
extern void AssemblerTestGenerate##name(Assembler* assembler);
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
// The ASSEMBLER_TEST_RUN macro is used to execute the assembler unit
|
|
|
|
// test generated using the ASSEMBLER_TEST_GENERATE macro.
|
|
|
|
// C++ callee-saved registers are not preserved. Arguments may be passed in.
|
2013-02-15 23:55:31 +00:00
|
|
|
#define ASSEMBLER_TEST_RUN(name, test) \
|
|
|
|
static void AssemblerTestRun##name(AssemblerTest* test); \
|
2011-10-05 05:20:07 +00:00
|
|
|
TEST_CASE(name) { \
|
|
|
|
Assembler __assembler__; \
|
2013-02-15 23:55:31 +00:00
|
|
|
AssemblerTest test(""#name, &__assembler__); \
|
|
|
|
AssemblerTestGenerate##name(test.assembler()); \
|
|
|
|
test.Assemble(); \
|
|
|
|
AssemblerTestRun##name(&test); \
|
2011-10-05 05:20:07 +00:00
|
|
|
} \
|
2013-02-15 23:55:31 +00:00
|
|
|
static void AssemblerTestRun##name(AssemblerTest* test)
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
// Populate node list with AST nodes.
|
|
|
|
#define CODEGEN_TEST_GENERATE(name, test) \
|
|
|
|
static void CodeGenTestGenerate##name(CodeGenTest* test)
|
|
|
|
|
|
|
|
// Populate node list with AST nodes, possibly using the provided function
|
|
|
|
// object built by a previous CODEGEN_TEST_GENERATE.
|
|
|
|
#define CODEGEN_TEST2_GENERATE(name, function, test) \
|
|
|
|
static void CodeGenTestGenerate##name(const Function& function, \
|
|
|
|
CodeGenTest* test)
|
|
|
|
|
|
|
|
|
|
|
|
// Pass the name of test and the expected results as RawObject.
|
|
|
|
#define CODEGEN_TEST_RUN(name, expected) \
|
|
|
|
static void CodeGenTestRun##name(const Function& function); \
|
|
|
|
TEST_CASE(name) { \
|
|
|
|
CodeGenTest __test__(""#name); \
|
|
|
|
CodeGenTestGenerate##name(&__test__); \
|
|
|
|
__test__.Compile(); \
|
|
|
|
CodeGenTestRun##name(__test__.function()); \
|
|
|
|
} \
|
|
|
|
static void CodeGenTestRun##name(const Function& function) { \
|
2012-02-02 19:05:06 +00:00
|
|
|
Object& result = Object::Handle(); \
|
2013-02-25 19:30:29 +00:00
|
|
|
result = DartEntry::InvokeFunction(function, Object::empty_array()); \
|
2012-02-02 19:05:06 +00:00
|
|
|
EXPECT(!result.IsError()); \
|
|
|
|
Instance& actual = Instance::Handle(); \
|
|
|
|
actual ^= result.raw(); \
|
2014-05-12 20:53:23 +00:00
|
|
|
EXPECT(actual.CanonicalizeEquals(Instance::Handle(expected))); \
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Pass the name of test, and use the generated function to call it
|
|
|
|
// and evaluate its result.
|
|
|
|
#define CODEGEN_TEST_RAW_RUN(name, function) \
|
|
|
|
static void CodeGenTestRun##name(const Function& function); \
|
|
|
|
TEST_CASE(name) { \
|
|
|
|
CodeGenTest __test__(""#name); \
|
|
|
|
CodeGenTestGenerate##name(&__test__); \
|
|
|
|
__test__.Compile(); \
|
|
|
|
CodeGenTestRun##name(__test__.function()); \
|
|
|
|
} \
|
|
|
|
static void CodeGenTestRun##name(const Function& function)
|
|
|
|
|
|
|
|
|
|
|
|
// Generate code for two sequences of AST nodes and execute the first one.
|
|
|
|
// The first one may reference the Function object generated by the second one.
|
|
|
|
#define CODEGEN_TEST2_RUN(name1, name2, expected) \
|
|
|
|
static void CodeGenTestRun##name1(const Function& function); \
|
|
|
|
TEST_CASE(name1) { \
|
|
|
|
/* Generate code for name2 */ \
|
|
|
|
CodeGenTest __test2__(""#name2); \
|
|
|
|
CodeGenTestGenerate##name2(&__test2__); \
|
|
|
|
__test2__.Compile(); \
|
|
|
|
/* Generate code for name1, providing function2 */ \
|
|
|
|
CodeGenTest __test1__(""#name1); \
|
|
|
|
CodeGenTestGenerate##name1(__test2__.function(), &__test1__); \
|
|
|
|
__test1__.Compile(); \
|
|
|
|
CodeGenTestRun##name1(__test1__.function()); \
|
|
|
|
} \
|
|
|
|
static void CodeGenTestRun##name1(const Function& function) { \
|
2012-02-02 19:05:06 +00:00
|
|
|
Object& result = Object::Handle(); \
|
2013-02-25 19:30:29 +00:00
|
|
|
result = DartEntry::InvokeFunction(function, Object::empty_array()); \
|
2012-02-02 19:05:06 +00:00
|
|
|
EXPECT(!result.IsError()); \
|
|
|
|
Instance& actual = Instance::Handle(); \
|
|
|
|
actual ^= result.raw(); \
|
2014-05-12 20:53:23 +00:00
|
|
|
EXPECT(actual.CanonicalizeEquals(Instance::Handle(expected))); \
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-02 17:39:32 +00:00
|
|
|
#if defined(TARGET_ARCH_ARM) || \
|
|
|
|
defined(TARGET_ARCH_MIPS) || \
|
|
|
|
defined(TARGET_ARCH_ARM64)
|
|
|
|
#if defined(HOST_ARCH_ARM) || \
|
|
|
|
defined(HOST_ARCH_MIPS) || \
|
|
|
|
defined(HOST_ARCH_ARM64)
|
2013-02-07 00:55:47 +00:00
|
|
|
// Running on actual ARM or MIPS hardware, execute code natively.
|
|
|
|
#define EXECUTE_TEST_CODE_INT32(name, entry) reinterpret_cast<name>(entry)()
|
2014-05-27 18:05:20 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INT64(name, entry) reinterpret_cast<name>(entry)()
|
2013-02-07 00:55:47 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1) \
|
|
|
|
reinterpret_cast<name>(entry)(long_arg0, long_arg1)
|
|
|
|
#define EXECUTE_TEST_CODE_FLOAT(name, entry) reinterpret_cast<name>(entry)()
|
|
|
|
#define EXECUTE_TEST_CODE_DOUBLE(name, entry) reinterpret_cast<name>(entry)()
|
|
|
|
#define EXECUTE_TEST_CODE_INT32_F(name, entry, float_arg) \
|
|
|
|
reinterpret_cast<name>(entry)(float_arg)
|
|
|
|
#define EXECUTE_TEST_CODE_INT32_D(name, entry, double_arg) \
|
|
|
|
reinterpret_cast<name>(entry)(double_arg)
|
2014-12-15 18:48:15 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INTPTR_INTPTR(name, entry, pointer_arg) \
|
|
|
|
reinterpret_cast<name>(entry)(pointer_arg)
|
2013-02-07 00:55:47 +00:00
|
|
|
#else
|
|
|
|
// Not running on ARM or MIPS hardware, call simulator to execute code.
|
2014-04-02 17:39:32 +00:00
|
|
|
#if defined(ARCH_IS_64_BIT)
|
|
|
|
// TODO(zra): Supply more macros for 64-bit as tests are added for ARM64.
|
2014-04-03 18:26:11 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INT64(name, entry) \
|
|
|
|
static_cast<int64_t>(Simulator::Current()->Call( \
|
2014-04-02 17:39:32 +00:00
|
|
|
bit_cast<int64_t, uword>(entry), 0, 0, 0, 0))
|
2014-05-01 21:50:17 +00:00
|
|
|
#define EXECUTE_TEST_CODE_DOUBLE(name, entry) \
|
|
|
|
bit_cast<double, int64_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int64_t, uword>(entry), 0, 0, 0, 0, true))
|
2014-12-15 18:48:15 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INTPTR_INTPTR(name, entry, pointer_arg) \
|
|
|
|
static_cast<intptr_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int64_t, uword>(entry), \
|
|
|
|
bit_cast<int64_t, intptr_t>(pointer_arg), \
|
|
|
|
0, 0, 0))
|
2014-04-02 17:39:32 +00:00
|
|
|
#else
|
2013-02-07 00:55:47 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INT32(name, entry) \
|
2013-04-08 16:44:39 +00:00
|
|
|
static_cast<int32_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int32_t, uword>(entry), 0, 0, 0, 0))
|
2014-05-01 21:50:17 +00:00
|
|
|
#define EXECUTE_TEST_CODE_DOUBLE(name, entry) \
|
|
|
|
bit_cast<double, int64_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int32_t, uword>(entry), 0, 0, 0, 0, true))
|
2014-12-15 18:48:15 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INTPTR_INTPTR(name, entry, pointer_arg) \
|
|
|
|
static_cast<intptr_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int32_t, uword>(entry), \
|
|
|
|
bit_cast<int32_t, intptr_t>(pointer_arg), \
|
|
|
|
0, 0, 0))
|
2014-04-02 17:39:32 +00:00
|
|
|
#endif
|
2013-02-07 00:55:47 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1) \
|
2013-04-08 16:44:39 +00:00
|
|
|
static_cast<int64_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int32_t, uword>(entry), \
|
2013-02-07 00:55:47 +00:00
|
|
|
Utils::Low32Bits(long_arg0), \
|
|
|
|
Utils::High32Bits(long_arg0), \
|
|
|
|
Utils::Low32Bits(long_arg1), \
|
2013-03-07 11:04:27 +00:00
|
|
|
Utils::High32Bits(long_arg1)))
|
2013-06-18 16:47:43 +00:00
|
|
|
#define EXECUTE_TEST_CODE_FLOAT(name, entry) \
|
|
|
|
bit_cast<float, int32_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int32_t, uword>(entry), 0, 0, 0, 0, true))
|
2013-02-07 00:55:47 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INT32_F(name, entry, float_arg) \
|
2013-04-08 16:44:39 +00:00
|
|
|
static_cast<int32_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int32_t, uword>(entry), \
|
2013-02-07 00:55:47 +00:00
|
|
|
bit_cast<int32_t, float>(float_arg), \
|
2013-06-24 20:16:16 +00:00
|
|
|
0, 0, 0, false, true))
|
2013-02-07 00:55:47 +00:00
|
|
|
#define EXECUTE_TEST_CODE_INT32_D(name, entry, double_arg) \
|
2013-04-08 16:44:39 +00:00
|
|
|
static_cast<int32_t>(Simulator::Current()->Call( \
|
|
|
|
bit_cast<int32_t, uword>(entry), \
|
2013-02-07 00:55:47 +00:00
|
|
|
Utils::Low32Bits(bit_cast<int64_t, double>(double_arg)), \
|
|
|
|
Utils::High32Bits(bit_cast<int64_t, double>(double_arg)), \
|
2013-06-24 20:16:16 +00:00
|
|
|
0, 0, false, true))
|
2013-02-07 00:55:47 +00:00
|
|
|
#endif // defined(HOST_ARCH_ARM) || defined(HOST_ARCH_MIPS)
|
|
|
|
#endif // defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
|
|
|
|
|
|
|
|
|
2012-10-31 17:56:46 +00:00
|
|
|
inline Dart_Handle NewString(const char* str) {
|
|
|
|
return Dart_NewStringFromCString(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
namespace dart {
|
|
|
|
|
|
|
|
// Forward declarations.
|
|
|
|
class Assembler;
|
|
|
|
class CodeGenerator;
|
|
|
|
class VirtualMemory;
|
|
|
|
|
|
|
|
|
2013-05-22 17:25:25 +00:00
|
|
|
namespace bin {
|
2015-03-31 18:46:19 +00:00
|
|
|
// vm_isolate_snapshot_buffer points to a snapshot for the vm isolate if we
|
|
|
|
// link in a snapshot otherwise it is initialized to NULL.
|
|
|
|
extern const uint8_t* vm_isolate_snapshot_buffer;
|
|
|
|
|
|
|
|
// isolate_snapshot_buffer points to a snapshot for an isolate if we link in a
|
|
|
|
// snapshot otherwise it is initialized to NULL.
|
|
|
|
extern const uint8_t* isolate_snapshot_buffer;
|
2013-05-22 17:25:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
class TestCaseBase {
|
|
|
|
public:
|
|
|
|
explicit TestCaseBase(const char* name);
|
|
|
|
virtual ~TestCaseBase() { }
|
|
|
|
|
|
|
|
const char* name() const { return name_; }
|
|
|
|
|
|
|
|
virtual void Run() = 0;
|
|
|
|
void RunTest();
|
|
|
|
|
|
|
|
static void RunAll();
|
|
|
|
|
|
|
|
private:
|
|
|
|
static TestCaseBase* first_;
|
|
|
|
static TestCaseBase* tail_;
|
|
|
|
|
|
|
|
TestCaseBase* next_;
|
|
|
|
const char* name_;
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(TestCaseBase);
|
|
|
|
};
|
|
|
|
|
2014-05-09 18:25:41 +00:00
|
|
|
#define USER_TEST_URI "test-lib"
|
|
|
|
#define CORELIB_TEST_URI "dart:test-lib"
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
class TestCase : TestCaseBase {
|
|
|
|
public:
|
|
|
|
typedef void (RunEntry)();
|
|
|
|
|
|
|
|
TestCase(RunEntry* run, const char* name) : TestCaseBase(name), run_(run) { }
|
|
|
|
|
|
|
|
static Dart_Handle LoadTestScript(const char* script,
|
2014-05-09 18:25:41 +00:00
|
|
|
Dart_NativeEntryResolver resolver,
|
2014-07-22 20:08:15 +00:00
|
|
|
const char* lib_uri = USER_TEST_URI,
|
|
|
|
bool finalize = true);
|
2014-05-09 18:25:41 +00:00
|
|
|
|
|
|
|
static Dart_Handle LoadCoreTestScript(const char* script,
|
|
|
|
Dart_NativeEntryResolver resolver);
|
2011-10-05 05:20:07 +00:00
|
|
|
static Dart_Handle lib();
|
2014-05-09 18:25:41 +00:00
|
|
|
static const char* url() { return USER_TEST_URI; }
|
2015-01-29 18:31:27 +00:00
|
|
|
static Dart_Isolate CreateTestIsolateFromSnapshot(
|
|
|
|
uint8_t* buffer, const char* name = NULL) {
|
|
|
|
return CreateIsolate(buffer, name);
|
2011-12-01 00:30:25 +00:00
|
|
|
}
|
2015-01-29 18:31:27 +00:00
|
|
|
static Dart_Isolate CreateTestIsolate(const char* name = NULL) {
|
2015-03-31 18:46:19 +00:00
|
|
|
return CreateIsolate(bin::isolate_snapshot_buffer, name);
|
2011-12-01 00:30:25 +00:00
|
|
|
}
|
|
|
|
static Dart_Handle library_handler(Dart_LibraryTag tag,
|
|
|
|
Dart_Handle library,
|
2012-05-23 18:32:51 +00:00
|
|
|
Dart_Handle url);
|
2014-09-09 21:47:44 +00:00
|
|
|
static char* BigintToHexValue(Dart_CObject* bigint);
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
virtual void Run();
|
|
|
|
|
|
|
|
private:
|
2015-01-29 18:31:27 +00:00
|
|
|
static Dart_Isolate CreateIsolate(const uint8_t* buffer,
|
|
|
|
const char* name) {
|
2011-12-01 00:30:25 +00:00
|
|
|
char* err;
|
2015-06-07 15:57:34 +00:00
|
|
|
Dart_Isolate isolate = Dart_CreateIsolate(
|
|
|
|
name, NULL, buffer, NULL, NULL, &err);
|
2015-05-19 18:41:42 +00:00
|
|
|
if (isolate == NULL) {
|
2011-12-01 00:30:25 +00:00
|
|
|
OS::Print("Creation of isolate failed '%s'\n", err);
|
|
|
|
free(err);
|
|
|
|
}
|
2015-05-19 18:41:42 +00:00
|
|
|
EXPECT(isolate != NULL);
|
2011-12-01 00:30:25 +00:00
|
|
|
return isolate;
|
|
|
|
}
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
RunEntry* const run_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class TestIsolateScope {
|
|
|
|
public:
|
|
|
|
TestIsolateScope() {
|
2015-05-19 18:41:42 +00:00
|
|
|
isolate_ = reinterpret_cast<Isolate*>(TestCase::CreateTestIsolate());
|
2011-10-05 05:20:07 +00:00
|
|
|
Dart_EnterScope(); // Create a Dart API scope for unit tests.
|
|
|
|
}
|
|
|
|
~TestIsolateScope() {
|
|
|
|
Dart_ExitScope(); // Exit the Dart API scope created for unit tests.
|
2015-05-19 18:41:42 +00:00
|
|
|
ASSERT(isolate_ == Isolate::Current());
|
2011-11-04 22:08:13 +00:00
|
|
|
Dart_ShutdownIsolate();
|
2015-05-19 18:41:42 +00:00
|
|
|
isolate_ = NULL;
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2015-05-19 18:41:42 +00:00
|
|
|
Isolate* isolate() const { return isolate_; }
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
private:
|
2015-05-19 18:41:42 +00:00
|
|
|
Isolate* isolate_;
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(TestIsolateScope);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-08-18 09:36:05 +00:00
|
|
|
template<typename T> struct is_void {
|
|
|
|
static const bool value = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<> struct is_void<void> {
|
|
|
|
static const bool value = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T> struct is_double {
|
|
|
|
static const bool value = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<> struct is_double<double> {
|
|
|
|
static const bool value = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
class AssemblerTest {
|
|
|
|
public:
|
|
|
|
AssemblerTest(const char* name, Assembler* assembler)
|
|
|
|
: name_(name),
|
2013-02-15 23:55:31 +00:00
|
|
|
assembler_(assembler),
|
|
|
|
code_(Code::ZoneHandle()) {
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(name != NULL);
|
|
|
|
ASSERT(assembler != NULL);
|
|
|
|
}
|
|
|
|
~AssemblerTest() { }
|
|
|
|
|
|
|
|
Assembler* assembler() const { return assembler_; }
|
|
|
|
|
2013-02-15 23:55:31 +00:00
|
|
|
const Code& code() const { return code_; }
|
|
|
|
|
2015-08-18 09:36:05 +00:00
|
|
|
uword entry() const { return code_.EntryPoint(); }
|
|
|
|
|
2015-12-04 17:46:21 +00:00
|
|
|
// Invoke/InvokeWithCodeAndThread is used to call assembler test functions
|
|
|
|
// using the ABI calling convention.
|
2015-08-18 09:36:05 +00:00
|
|
|
// ResultType is the return type of the assembler test function.
|
|
|
|
// ArgNType is the type of the Nth argument.
|
|
|
|
#if defined(USING_SIMULATOR)
|
|
|
|
|
|
|
|
#if defined(ARCH_IS_64_BIT)
|
2015-12-04 17:46:21 +00:00
|
|
|
// TODO(fschneider): Make InvokeWithCodeAndThread<> more general and work on
|
|
|
|
// 32-bit.
|
2015-08-18 09:36:05 +00:00
|
|
|
// Since Simulator::Call always return a int64_t, bit_cast does not work
|
|
|
|
// on 32-bit platforms when returning an int32_t. Since template functions
|
|
|
|
// don't support partial specialization, we'd need to introduce a helper
|
|
|
|
// class to support 32-bit return types.
|
2015-12-04 17:46:21 +00:00
|
|
|
template<typename ResultType> ResultType InvokeWithCodeAndThread() {
|
2015-08-18 09:36:05 +00:00
|
|
|
const bool fp_return = is_double<ResultType>::value;
|
|
|
|
const bool fp_args = false;
|
2015-12-04 17:46:21 +00:00
|
|
|
Thread* thread = Thread::Current();
|
|
|
|
ASSERT(thread != NULL);
|
2015-08-18 09:36:05 +00:00
|
|
|
return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
|
2015-09-19 11:21:09 +00:00
|
|
|
bit_cast<intptr_t, uword>(entry()),
|
2015-12-04 17:46:21 +00:00
|
|
|
reinterpret_cast<intptr_t>(&code_),
|
|
|
|
reinterpret_cast<intptr_t>(thread),
|
|
|
|
0, 0, fp_return, fp_args));
|
2015-08-18 09:36:05 +00:00
|
|
|
}
|
|
|
|
template<typename ResultType, typename Arg1Type>
|
2015-12-04 17:46:21 +00:00
|
|
|
ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
|
2015-08-18 09:36:05 +00:00
|
|
|
const bool fp_return = is_double<ResultType>::value;
|
|
|
|
const bool fp_args = is_double<Arg1Type>::value;
|
|
|
|
// TODO(fschneider): Support double arguments for simulator calls.
|
|
|
|
COMPILE_ASSERT(!fp_args);
|
2015-12-04 17:46:21 +00:00
|
|
|
Thread* thread = Thread::Current();
|
|
|
|
ASSERT(thread != NULL);
|
2015-08-18 09:36:05 +00:00
|
|
|
return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
|
|
|
|
bit_cast<intptr_t, uword>(entry()),
|
2015-09-19 11:21:09 +00:00
|
|
|
reinterpret_cast<intptr_t>(&code_),
|
2015-12-04 17:46:21 +00:00
|
|
|
reinterpret_cast<intptr_t>(thread),
|
2015-08-18 09:36:05 +00:00
|
|
|
reinterpret_cast<intptr_t>(arg1),
|
2015-12-04 17:46:21 +00:00
|
|
|
0, fp_return, fp_args));
|
2015-08-18 09:36:05 +00:00
|
|
|
}
|
|
|
|
#endif // ARCH_IS_64_BIT
|
|
|
|
|
|
|
|
template<typename ResultType,
|
|
|
|
typename Arg1Type,
|
|
|
|
typename Arg2Type,
|
|
|
|
typename Arg3Type>
|
|
|
|
ResultType Invoke(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3) {
|
|
|
|
// TODO(fschneider): Support double arguments for simulator calls.
|
|
|
|
COMPILE_ASSERT(is_void<ResultType>::value);
|
|
|
|
COMPILE_ASSERT(!is_double<Arg1Type>::value);
|
|
|
|
COMPILE_ASSERT(!is_double<Arg2Type>::value);
|
|
|
|
COMPILE_ASSERT(!is_double<Arg3Type>::value);
|
|
|
|
const bool fp_args = false;
|
|
|
|
const bool fp_return = false;
|
|
|
|
Simulator::Current()->Call(
|
|
|
|
bit_cast<intptr_t, uword>(entry()),
|
|
|
|
reinterpret_cast<intptr_t>(arg1),
|
|
|
|
reinterpret_cast<intptr_t>(arg2),
|
|
|
|
reinterpret_cast<intptr_t>(arg3),
|
|
|
|
0, fp_return, fp_args);
|
|
|
|
}
|
|
|
|
#else
|
2015-12-04 17:46:21 +00:00
|
|
|
template<typename ResultType> ResultType InvokeWithCodeAndThread() {
|
|
|
|
Thread* thread = Thread::Current();
|
|
|
|
ASSERT(thread != NULL);
|
|
|
|
typedef ResultType (*FunctionType) (const Code&, Thread*);
|
|
|
|
return reinterpret_cast<FunctionType>(entry())(code_, thread);
|
2015-08-18 09:36:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ResultType, typename Arg1Type>
|
2015-12-04 17:46:21 +00:00
|
|
|
ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
|
|
|
|
Thread* thread = Thread::Current();
|
|
|
|
ASSERT(thread != NULL);
|
|
|
|
typedef ResultType (*FunctionType) (const Code&, Thread*, Arg1Type);
|
|
|
|
return reinterpret_cast<FunctionType>(entry())(code_, thread, arg1);
|
2015-08-18 09:36:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ResultType,
|
|
|
|
typename Arg1Type,
|
|
|
|
typename Arg2Type,
|
|
|
|
typename Arg3Type>
|
|
|
|
ResultType Invoke(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3) {
|
|
|
|
typedef ResultType (*FunctionType) (Arg1Type, Arg2Type, Arg3Type);
|
|
|
|
return reinterpret_cast<FunctionType>(entry())(arg1, arg2, arg3);
|
|
|
|
}
|
|
|
|
#endif // USING_SIMULATOR
|
2013-02-15 23:55:31 +00:00
|
|
|
|
2015-08-18 09:36:05 +00:00
|
|
|
// Assemble test and set code_.
|
2013-02-15 23:55:31 +00:00
|
|
|
void Assemble();
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
const char* name_;
|
|
|
|
Assembler* assembler_;
|
2013-02-15 23:55:31 +00:00
|
|
|
Code& code_;
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class CodeGenTest {
|
|
|
|
public:
|
|
|
|
explicit CodeGenTest(const char* name);
|
|
|
|
~CodeGenTest() { }
|
|
|
|
|
|
|
|
// Accessors.
|
|
|
|
const Function& function() const { return function_; }
|
|
|
|
|
|
|
|
SequenceNode* node_sequence() const { return node_sequence_; }
|
|
|
|
|
2015-08-25 00:22:44 +00:00
|
|
|
void set_default_parameter_values(ZoneGrowableArray<const Instance*>* value) {
|
|
|
|
default_parameter_values_ = value;
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compile test and set code in function.
|
|
|
|
void Compile();
|
|
|
|
|
|
|
|
private:
|
|
|
|
Function& function_;
|
|
|
|
SequenceNode* node_sequence_;
|
2015-08-25 00:22:44 +00:00
|
|
|
ZoneGrowableArray<const Instance*>* default_parameter_values_;
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CodeGenTest);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class CompilerTest : public AllStatic {
|
|
|
|
public:
|
|
|
|
// Test the Compiler::CompileScript functionality by checking the return
|
|
|
|
// value to see if no parse errors were reported.
|
|
|
|
static bool TestCompileScript(const Library& library, const Script& script);
|
|
|
|
|
|
|
|
// Test the Compiler::CompileFunction functionality by checking the return
|
|
|
|
// value to see if no parse errors were reported.
|
|
|
|
static bool TestCompileFunction(const Function& function);
|
|
|
|
};
|
|
|
|
|
2012-04-18 18:11:55 +00:00
|
|
|
#define EXPECT_VALID(handle) \
|
|
|
|
do { \
|
|
|
|
Dart_Handle tmp_handle = (handle); \
|
|
|
|
if (Dart_IsError(tmp_handle)) { \
|
|
|
|
dart::Expect(__FILE__, __LINE__).Fail( \
|
|
|
|
"expected '%s' to be a valid handle but found an error handle:\n" \
|
|
|
|
" '%s'\n", \
|
|
|
|
#handle, Dart_GetError(tmp_handle)); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define EXPECT_ERROR(handle, substring) \
|
|
|
|
do { \
|
|
|
|
Dart_Handle tmp_handle = (handle); \
|
|
|
|
if (Dart_IsError(tmp_handle)) { \
|
|
|
|
dart::Expect(__FILE__, __LINE__).IsSubstring((substring), \
|
|
|
|
Dart_GetError(tmp_handle)); \
|
|
|
|
} else { \
|
|
|
|
dart::Expect(__FILE__, __LINE__).Fail( \
|
|
|
|
"expected '%s' to be an error handle but found a valid handle.\n", \
|
|
|
|
#handle); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
2011-10-31 20:18:07 +00:00
|
|
|
|
2013-03-25 16:21:58 +00:00
|
|
|
#define EXPECT_TRUE(handle) \
|
|
|
|
do { \
|
|
|
|
Dart_Handle tmp_handle = (handle); \
|
|
|
|
if (Dart_IsBoolean(tmp_handle)) { \
|
|
|
|
bool value; \
|
|
|
|
Dart_BooleanValue(tmp_handle, &value); \
|
|
|
|
if (!value) { \
|
|
|
|
dart::Expect(__FILE__, __LINE__).Fail("expected True, but was '%s'\n", \
|
|
|
|
#handle); \
|
|
|
|
} \
|
|
|
|
} else { \
|
|
|
|
dart::Expect(__FILE__, __LINE__).Fail("expected True, but was '%s'\n", \
|
|
|
|
#handle); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2015-09-11 19:29:21 +00:00
|
|
|
|
|
|
|
// Elide a substring which starts with some prefix and ends with a ".
|
|
|
|
//
|
|
|
|
// This is used to remove non-deterministic or fragile substrings from
|
|
|
|
// JSON output.
|
|
|
|
//
|
|
|
|
// For example:
|
|
|
|
//
|
|
|
|
// prefix = "classes"
|
|
|
|
// in = "\"id\":\"classes/46\""
|
|
|
|
//
|
|
|
|
// Yields:
|
|
|
|
//
|
|
|
|
// out = "\"id\":\"\""
|
|
|
|
//
|
|
|
|
void ElideJSONSubstring(const char* prefix, const char* in, char* out);
|
|
|
|
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
} // namespace dart
|
|
|
|
|
|
|
|
#endif // VM_UNIT_TEST_H_
|