diff options
author | 2015-12-16 15:21:25 +0000 | |
---|---|---|
committer | 2015-12-16 15:21:25 +0000 | |
commit | 4741516396e9dbfb3afc2c1d8241a7e4e26a6302 (patch) | |
tree | 5b828a40c6a4342e4a3fbe995560df014db8fa81 | |
parent | 7f3b38cc23b638ab84ac01a94e90f0456da3b688 (diff) | |
parent | 751beff19b36f777d9e3a966d754fd9cfad5d534 (diff) |
Merge "Revert "Revert "Introduce support for hardware simulators, starting with ARM64"""
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | cmdline/cmdline_parser_test.cc | 5 | ||||
-rw-r--r-- | cmdline/cmdline_types.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/codegen_test.cc | 333 | ||||
-rw-r--r-- | runtime/Android.mk | 1 | ||||
-rw-r--r-- | runtime/base/logging.h | 1 | ||||
-rw-r--r-- | runtime/code_simulator_container.cc | 55 | ||||
-rw-r--r-- | runtime/code_simulator_container.h | 54 | ||||
-rw-r--r-- | runtime/parsed_options.cc | 1 | ||||
-rw-r--r-- | runtime/parsed_options_test.cc | 2 | ||||
-rw-r--r-- | runtime/simulator/Android.mk | 105 | ||||
-rw-r--r-- | runtime/simulator/code_simulator.cc | 35 | ||||
-rw-r--r-- | runtime/simulator/code_simulator.h | 46 | ||||
-rw-r--r-- | runtime/simulator/code_simulator_arm64.cc | 69 | ||||
-rw-r--r-- | runtime/simulator/code_simulator_arm64.h | 57 |
15 files changed, 651 insertions, 116 deletions
diff --git a/Android.mk b/Android.mk index 3438beba3f..97a82e2077 100644 --- a/Android.mk +++ b/Android.mk @@ -77,6 +77,7 @@ include $(art_path)/build/Android.cpplint.mk # product rules include $(art_path)/runtime/Android.mk +include $(art_path)/runtime/simulator/Android.mk include $(art_path)/compiler/Android.mk include $(art_path)/dexdump/Android.mk include $(art_path)/dexlist/Android.mk diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc index 529143d93d..fe83ba9e14 100644 --- a/cmdline/cmdline_parser_test.cc +++ b/cmdline/cmdline_parser_test.cc @@ -243,8 +243,8 @@ TEST_F(CmdlineParserTest, TestSimpleFailures) { TEST_F(CmdlineParserTest, TestLogVerbosity) { { const char* log_args = "-verbose:" - "class,compiler,gc,heap,jdwp,jni,monitor,profiler,signals,startup,third-party-jni," - "threads,verifier"; + "class,compiler,gc,heap,jdwp,jni,monitor,profiler,signals,simulator,startup," + "third-party-jni,threads,verifier"; LogVerbosity log_verbosity = LogVerbosity(); log_verbosity.class_linker = true; @@ -256,6 +256,7 @@ TEST_F(CmdlineParserTest, TestLogVerbosity) { log_verbosity.monitor = true; log_verbosity.profiler = true; log_verbosity.signals = true; + log_verbosity.simulator = true; log_verbosity.startup = true; log_verbosity.third_party_jni = true; log_verbosity.threads = true; diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h index 47519894eb..6c0a0e1f4f 100644 --- a/cmdline/cmdline_types.h +++ b/cmdline/cmdline_types.h @@ -606,6 +606,8 @@ struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> { log_verbosity.profiler = true; } else if (verbose_options[j] == "signals") { log_verbosity.signals = true; + } else if (verbose_options[j] == "simulator") { + log_verbosity.simulator = true; } else if (verbose_options[j] == "startup") { log_verbosity.startup = true; } else if (verbose_options[j] == "third-party-jni") { diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index 57de41f557..d970704368 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -35,6 +35,7 @@ #include "code_generator_mips64.h" #include "code_generator_x86.h" #include "code_generator_x86_64.h" +#include "code_simulator_container.h" #include "common_compiler_test.h" #include "dex_file.h" #include "dex_instruction.h" @@ -124,26 +125,85 @@ class InternalCodeAllocator : public CodeAllocator { DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); }; +static bool CanExecuteOnHardware(InstructionSet target_isa) { + return (target_isa == kRuntimeISA) + // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2). + || (kRuntimeISA == kArm && target_isa == kThumb2); +} + +static bool CanExecute(InstructionSet target_isa) { + CodeSimulatorContainer simulator(target_isa); + return CanExecuteOnHardware(target_isa) || simulator.CanSimulate(); +} + +template <typename Expected> +static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)()); + +template <> +bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) { + simulator->RunFrom(reinterpret_cast<intptr_t>(f)); + return simulator->GetCReturnBool(); +} + +template <> +int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) { + simulator->RunFrom(reinterpret_cast<intptr_t>(f)); + return simulator->GetCReturnInt32(); +} + +template <> +int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) { + simulator->RunFrom(reinterpret_cast<intptr_t>(f)); + return simulator->GetCReturnInt64(); +} + +template <typename Expected> +static void VerifyGeneratedCode(InstructionSet target_isa, + Expected (*f)(), + bool has_result, + Expected expected) { + ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable."; + + // Verify on simulator. + CodeSimulatorContainer simulator(target_isa); + if (simulator.CanSimulate()) { + Expected result = SimulatorExecute<Expected>(simulator.Get(), f); + if (has_result) { + ASSERT_EQ(expected, result); + } + } + + // Verify on hardware. + if (CanExecuteOnHardware(target_isa)) { + Expected result = f(); + if (has_result) { + ASSERT_EQ(expected, result); + } + } +} + template <typename Expected> static void Run(const InternalCodeAllocator& allocator, const CodeGenerator& codegen, bool has_result, Expected expected) { + InstructionSet target_isa = codegen.GetInstructionSet(); + typedef Expected (*fptr)(); CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize()); fptr f = reinterpret_cast<fptr>(allocator.GetMemory()); - if (codegen.GetInstructionSet() == kThumb2) { + if (target_isa == kThumb2) { // For thumb we need the bottom bit set. f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1); } - Expected result = f(); - if (has_result) { - ASSERT_EQ(expected, result); - } + VerifyGeneratedCode(target_isa, f, has_result, expected); } template <typename Expected> -static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { +static void RunCodeBaseline(InstructionSet target_isa, + HGraph* graph, + bool has_result, + Expected expected) { InternalCodeAllocator allocator; CompilerOptions compiler_options; @@ -153,7 +213,7 @@ static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { // We avoid doing a stack overflow check that requires the runtime being setup, // by making sure the compiler knows the methods we are running are leaf methods. codegenX86.CompileBaseline(&allocator, true); - if (kRuntimeISA == kX86) { + if (target_isa == kX86) { Run(allocator, codegenX86, has_result, expected); } @@ -161,7 +221,7 @@ static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { ArmInstructionSetFeatures::FromCppDefines()); TestCodeGeneratorARM codegenARM(graph, *features_arm.get(), compiler_options); codegenARM.CompileBaseline(&allocator, true); - if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) { + if (target_isa == kArm || target_isa == kThumb2) { Run(allocator, codegenARM, has_result, expected); } @@ -169,7 +229,7 @@ static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { X86_64InstructionSetFeatures::FromCppDefines()); x86_64::CodeGeneratorX86_64 codegenX86_64(graph, *features_x86_64.get(), compiler_options); codegenX86_64.CompileBaseline(&allocator, true); - if (kRuntimeISA == kX86_64) { + if (target_isa == kX86_64) { Run(allocator, codegenX86_64, has_result, expected); } @@ -177,7 +237,7 @@ static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { Arm64InstructionSetFeatures::FromCppDefines()); arm64::CodeGeneratorARM64 codegenARM64(graph, *features_arm64.get(), compiler_options); codegenARM64.CompileBaseline(&allocator, true); - if (kRuntimeISA == kArm64) { + if (target_isa == kArm64) { Run(allocator, codegenARM64, has_result, expected); } @@ -193,7 +253,7 @@ static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { Mips64InstructionSetFeatures::FromCppDefines()); mips64::CodeGeneratorMIPS64 codegenMIPS64(graph, *features_mips64.get(), compiler_options); codegenMIPS64.CompileBaseline(&allocator, true); - if (kRuntimeISA == kMips64) { + if (target_isa == kMips64) { Run(allocator, codegenMIPS64, has_result, expected); } } @@ -221,37 +281,38 @@ static void RunCodeOptimized(CodeGenerator* codegen, } template <typename Expected> -static void RunCodeOptimized(HGraph* graph, +static void RunCodeOptimized(InstructionSet target_isa, + HGraph* graph, std::function<void(HGraph*)> hook_before_codegen, bool has_result, Expected expected) { CompilerOptions compiler_options; - if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) { - TestCodeGeneratorARM codegenARM(graph, - *ArmInstructionSetFeatures::FromCppDefines(), - compiler_options); + if (target_isa == kArm || target_isa == kThumb2) { + std::unique_ptr<const ArmInstructionSetFeatures> features_arm( + ArmInstructionSetFeatures::FromCppDefines()); + TestCodeGeneratorARM codegenARM(graph, *features_arm.get(), compiler_options); RunCodeOptimized(&codegenARM, graph, hook_before_codegen, has_result, expected); - } else if (kRuntimeISA == kArm64) { - arm64::CodeGeneratorARM64 codegenARM64(graph, - *Arm64InstructionSetFeatures::FromCppDefines(), - compiler_options); + } else if (target_isa == kArm64) { + std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64( + Arm64InstructionSetFeatures::FromCppDefines()); + arm64::CodeGeneratorARM64 codegenARM64(graph, *features_arm64.get(), compiler_options); RunCodeOptimized(&codegenARM64, graph, hook_before_codegen, has_result, expected); - } else if (kRuntimeISA == kX86) { + } else if (target_isa == kX86) { std::unique_ptr<const X86InstructionSetFeatures> features_x86( X86InstructionSetFeatures::FromCppDefines()); x86::CodeGeneratorX86 codegenX86(graph, *features_x86.get(), compiler_options); RunCodeOptimized(&codegenX86, graph, hook_before_codegen, has_result, expected); - } else if (kRuntimeISA == kX86_64) { + } else if (target_isa == kX86_64) { std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64( X86_64InstructionSetFeatures::FromCppDefines()); x86_64::CodeGeneratorX86_64 codegenX86_64(graph, *features_x86_64.get(), compiler_options); RunCodeOptimized(&codegenX86_64, graph, hook_before_codegen, has_result, expected); - } else if (kRuntimeISA == kMips) { + } else if (target_isa == kMips) { std::unique_ptr<const MipsInstructionSetFeatures> features_mips( MipsInstructionSetFeatures::FromCppDefines()); mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), compiler_options); RunCodeOptimized(&codegenMIPS, graph, hook_before_codegen, has_result, expected); - } else if (kRuntimeISA == kMips64) { + } else if (target_isa == kMips64) { std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64( Mips64InstructionSetFeatures::FromCppDefines()); mips64::CodeGeneratorMIPS64 codegenMIPS64(graph, *features_mips64.get(), compiler_options); @@ -259,7 +320,10 @@ static void RunCodeOptimized(HGraph* graph, } } -static void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0) { +static void TestCode(InstructionSet target_isa, + const uint16_t* data, + bool has_result = false, + int32_t expected = 0) { ArenaPool pool; ArenaAllocator arena(&pool); HGraph* graph = CreateGraph(&arena); @@ -269,10 +333,13 @@ static void TestCode(const uint16_t* data, bool has_result = false, int32_t expe ASSERT_TRUE(graph_built); // Remove suspend checks, they cannot be executed in this context. RemoveSuspendChecks(graph); - RunCodeBaseline(graph, has_result, expected); + RunCodeBaseline(target_isa, graph, has_result, expected); } -static void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected) { +static void TestCodeLong(InstructionSet target_isa, + const uint16_t* data, + bool has_result, + int64_t expected) { ArenaPool pool; ArenaAllocator arena(&pool); HGraph* graph = CreateGraph(&arena); @@ -282,108 +349,110 @@ static void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected ASSERT_TRUE(graph_built); // Remove suspend checks, they cannot be executed in this context. RemoveSuspendChecks(graph); - RunCodeBaseline(graph, has_result, expected); + RunCodeBaseline(target_isa, graph, has_result, expected); } -TEST(CodegenTest, ReturnVoid) { +class CodegenTest: public ::testing::TestWithParam<InstructionSet> {}; + +TEST_P(CodegenTest, ReturnVoid) { const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID); - TestCode(data); + TestCode(GetParam(), data); } -TEST(CodegenTest, CFG1) { +TEST_P(CodegenTest, CFG1) { const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( Instruction::GOTO | 0x100, Instruction::RETURN_VOID); - TestCode(data); + TestCode(GetParam(), data); } -TEST(CodegenTest, CFG2) { +TEST_P(CodegenTest, CFG2) { const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( Instruction::GOTO | 0x100, Instruction::GOTO | 0x100, Instruction::RETURN_VOID); - TestCode(data); + TestCode(GetParam(), data); } -TEST(CodegenTest, CFG3) { +TEST_P(CodegenTest, CFG3) { const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM( Instruction::GOTO | 0x200, Instruction::RETURN_VOID, Instruction::GOTO | 0xFF00); - TestCode(data1); + TestCode(GetParam(), data1); const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM( Instruction::GOTO_16, 3, Instruction::RETURN_VOID, Instruction::GOTO_16, 0xFFFF); - TestCode(data2); + TestCode(GetParam(), data2); const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM( Instruction::GOTO_32, 4, 0, Instruction::RETURN_VOID, Instruction::GOTO_32, 0xFFFF, 0xFFFF); - TestCode(data3); + TestCode(GetParam(), data3); } -TEST(CodegenTest, CFG4) { +TEST_P(CodegenTest, CFG4) { const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( Instruction::RETURN_VOID, Instruction::GOTO | 0x100, Instruction::GOTO | 0xFE00); - TestCode(data); + TestCode(GetParam(), data); } -TEST(CodegenTest, CFG5) { +TEST_P(CodegenTest, CFG5) { const uint16_t data[] = ONE_REGISTER_CODE_ITEM( Instruction::CONST_4 | 0 | 0, Instruction::IF_EQ, 3, Instruction::GOTO | 0x100, Instruction::RETURN_VOID); - TestCode(data); + TestCode(GetParam(), data); } -TEST(CodegenTest, IntConstant) { +TEST_P(CodegenTest, IntConstant) { const uint16_t data[] = ONE_REGISTER_CODE_ITEM( Instruction::CONST_4 | 0 | 0, Instruction::RETURN_VOID); - TestCode(data); + TestCode(GetParam(), data); } -TEST(CodegenTest, Return1) { +TEST_P(CodegenTest, Return1) { const uint16_t data[] = ONE_REGISTER_CODE_ITEM( Instruction::CONST_4 | 0 | 0, Instruction::RETURN | 0); - TestCode(data, true, 0); + TestCode(GetParam(), data, true, 0); } -TEST(CodegenTest, Return2) { +TEST_P(CodegenTest, Return2) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 0 | 0, Instruction::CONST_4 | 0 | 1 << 8, Instruction::RETURN | 1 << 8); - TestCode(data, true, 0); + TestCode(GetParam(), data, true, 0); } -TEST(CodegenTest, Return3) { +TEST_P(CodegenTest, Return3) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 0 | 0, Instruction::CONST_4 | 1 << 8 | 1 << 12, Instruction::RETURN | 1 << 8); - TestCode(data, true, 1); + TestCode(GetParam(), data, true, 1); } -TEST(CodegenTest, ReturnIf1) { +TEST_P(CodegenTest, ReturnIf1) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 0 | 0, Instruction::CONST_4 | 1 << 8 | 1 << 12, @@ -391,10 +460,10 @@ TEST(CodegenTest, ReturnIf1) { Instruction::RETURN | 0 << 8, Instruction::RETURN | 1 << 8); - TestCode(data, true, 1); + TestCode(GetParam(), data, true, 1); } -TEST(CodegenTest, ReturnIf2) { +TEST_P(CodegenTest, ReturnIf2) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 0 | 0, Instruction::CONST_4 | 1 << 8 | 1 << 12, @@ -402,12 +471,12 @@ TEST(CodegenTest, ReturnIf2) { Instruction::RETURN | 0 << 8, Instruction::RETURN | 1 << 8); - TestCode(data, true, 0); + TestCode(GetParam(), data, true, 0); } // Exercise bit-wise (one's complement) not-int instruction. #define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \ -TEST(CodegenTest, TEST_NAME) { \ +TEST_P(CodegenTest, TEST_NAME) { \ const int32_t input = INPUT; \ const uint16_t input_lo = Low16Bits(input); \ const uint16_t input_hi = High16Bits(input); \ @@ -416,7 +485,7 @@ TEST(CodegenTest, TEST_NAME) { \ Instruction::NOT_INT | 1 << 8 | 0 << 12 , \ Instruction::RETURN | 1 << 8); \ \ - TestCode(data, true, EXPECTED_OUTPUT); \ + TestCode(GetParam(), data, true, EXPECTED_OUTPUT); \ } NOT_INT_TEST(ReturnNotIntMinus2, -2, 1) @@ -432,7 +501,7 @@ NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31) // Exercise bit-wise (one's complement) not-long instruction. #define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \ -TEST(CodegenTest, TEST_NAME) { \ +TEST_P(CodegenTest, TEST_NAME) { \ const int64_t input = INPUT; \ const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \ const uint16_t word1 = High16Bits(Low32Bits(input)); \ @@ -443,7 +512,7 @@ TEST(CodegenTest, TEST_NAME) { \ Instruction::NOT_LONG | 2 << 8 | 0 << 12, \ Instruction::RETURN_WIDE | 2 << 8); \ \ - TestCodeLong(data, true, EXPECTED_OUTPUT); \ + TestCodeLong(GetParam(), data, true, EXPECTED_OUTPUT); \ } NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1)) @@ -482,7 +551,7 @@ NOT_LONG_TEST(ReturnNotLongINT64_MAX, #undef NOT_LONG_TEST -TEST(CodegenTest, IntToLongOfLongToInt) { +TEST_P(CodegenTest, IntToLongOfLongToInt) { const int64_t input = INT64_C(4294967296); // 2^32 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW. const uint16_t word1 = High16Bits(Low32Bits(input)); @@ -496,48 +565,48 @@ TEST(CodegenTest, IntToLongOfLongToInt) { Instruction::INT_TO_LONG | 2 << 8 | 4 << 12, Instruction::RETURN_WIDE | 2 << 8); - TestCodeLong(data, true, 1); + TestCodeLong(GetParam(), data, true, 1); } -TEST(CodegenTest, ReturnAdd1) { +TEST_P(CodegenTest, ReturnAdd1) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 3 << 12 | 0, Instruction::CONST_4 | 4 << 12 | 1 << 8, Instruction::ADD_INT, 1 << 8 | 0, Instruction::RETURN); - TestCode(data, true, 7); + TestCode(GetParam(), data, true, 7); } -TEST(CodegenTest, ReturnAdd2) { +TEST_P(CodegenTest, ReturnAdd2) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 3 << 12 | 0, Instruction::CONST_4 | 4 << 12 | 1 << 8, Instruction::ADD_INT_2ADDR | 1 << 12, Instruction::RETURN); - TestCode(data, true, 7); + TestCode(GetParam(), data, true, 7); } -TEST(CodegenTest, ReturnAdd3) { +TEST_P(CodegenTest, ReturnAdd3) { const uint16_t data[] = ONE_REGISTER_CODE_ITEM( Instruction::CONST_4 | 4 << 12 | 0 << 8, Instruction::ADD_INT_LIT8, 3 << 8 | 0, Instruction::RETURN); - TestCode(data, true, 7); + TestCode(GetParam(), data, true, 7); } -TEST(CodegenTest, ReturnAdd4) { +TEST_P(CodegenTest, ReturnAdd4) { const uint16_t data[] = ONE_REGISTER_CODE_ITEM( Instruction::CONST_4 | 4 << 12 | 0 << 8, Instruction::ADD_INT_LIT16, 3, Instruction::RETURN); - TestCode(data, true, 7); + TestCode(GetParam(), data, true, 7); } -TEST(CodegenTest, NonMaterializedCondition) { +TEST_P(CodegenTest, NonMaterializedCondition) { ArenaPool pool; ArenaAllocator allocator(&pool); @@ -583,30 +652,30 @@ TEST(CodegenTest, NonMaterializedCondition) { block->InsertInstructionBefore(move, block->GetLastInstruction()); }; - RunCodeOptimized(graph, hook_before_codegen, true, 0); + RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, 0); } -TEST(CodegenTest, ReturnMulInt) { +TEST_P(CodegenTest, ReturnMulInt) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 3 << 12 | 0, Instruction::CONST_4 | 4 << 12 | 1 << 8, Instruction::MUL_INT, 1 << 8 | 0, Instruction::RETURN); - TestCode(data, true, 12); + TestCode(GetParam(), data, true, 12); } -TEST(CodegenTest, ReturnMulInt2addr) { +TEST_P(CodegenTest, ReturnMulInt2addr) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 3 << 12 | 0, Instruction::CONST_4 | 4 << 12 | 1 << 8, Instruction::MUL_INT_2ADDR | 1 << 12, Instruction::RETURN); - TestCode(data, true, 12); + TestCode(GetParam(), data, true, 12); } -TEST(CodegenTest, ReturnMulLong) { +TEST_P(CodegenTest, ReturnMulLong) { const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 3 << 12 | 0, Instruction::CONST_4 | 0 << 12 | 1 << 8, @@ -615,10 +684,10 @@ TEST(CodegenTest, ReturnMulLong) { Instruction::MUL_LONG, 2 << 8 | 0, Instruction::RETURN_WIDE); - TestCodeLong(data, true, 12); + TestCodeLong(GetParam(), data, true, 12); } -TEST(CodegenTest, ReturnMulLong2addr) { +TEST_P(CodegenTest, ReturnMulLong2addr) { const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 3 << 12 | 0 << 8, Instruction::CONST_4 | 0 << 12 | 1 << 8, @@ -627,28 +696,28 @@ TEST(CodegenTest, ReturnMulLong2addr) { Instruction::MUL_LONG_2ADDR | 2 << 12, Instruction::RETURN_WIDE); - TestCodeLong(data, true, 12); + TestCodeLong(GetParam(), data, true, 12); } -TEST(CodegenTest, ReturnMulIntLit8) { +TEST_P(CodegenTest, ReturnMulIntLit8) { const uint16_t data[] = ONE_REGISTER_CODE_ITEM( Instruction::CONST_4 | 4 << 12 | 0 << 8, Instruction::MUL_INT_LIT8, 3 << 8 | 0, Instruction::RETURN); - TestCode(data, true, 12); + TestCode(GetParam(), data, true, 12); } -TEST(CodegenTest, ReturnMulIntLit16) { +TEST_P(CodegenTest, ReturnMulIntLit16) { const uint16_t data[] = ONE_REGISTER_CODE_ITEM( Instruction::CONST_4 | 4 << 12 | 0 << 8, Instruction::MUL_INT_LIT16, 3, Instruction::RETURN); - TestCode(data, true, 12); + TestCode(GetParam(), data, true, 12); } -TEST(CodegenTest, MaterializedCondition1) { +TEST_P(CodegenTest, MaterializedCondition1) { // Check that condition are materialized correctly. A materialized condition // should yield `1` if it evaluated to true, and `0` otherwise. // We force the materialization of comparisons for different combinations of @@ -689,11 +758,11 @@ TEST(CodegenTest, MaterializedCondition1) { block->InsertInstructionBefore(move, block->GetLastInstruction()); }; - RunCodeOptimized(graph, hook_before_codegen, true, lhs[i] < rhs[i]); + RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, lhs[i] < rhs[i]); } } -TEST(CodegenTest, MaterializedCondition2) { +TEST_P(CodegenTest, MaterializedCondition2) { // Check that HIf correctly interprets a materialized condition. // We force the materialization of comparisons for different combinations of // inputs. An HIf takes the materialized combination as input and returns a @@ -755,31 +824,35 @@ TEST(CodegenTest, MaterializedCondition2) { block->InsertInstructionBefore(move, block->GetLastInstruction()); }; - RunCodeOptimized(graph, hook_before_codegen, true, lhs[i] < rhs[i]); + RunCodeOptimized(GetParam(), graph, hook_before_codegen, true, lhs[i] < rhs[i]); } } -TEST(CodegenTest, ReturnDivIntLit8) { +TEST_P(CodegenTest, ReturnDivIntLit8) { const uint16_t data[] = ONE_REGISTER_CODE_ITEM( Instruction::CONST_4 | 4 << 12 | 0 << 8, Instruction::DIV_INT_LIT8, 3 << 8 | 0, Instruction::RETURN); - TestCode(data, true, 1); + TestCode(GetParam(), data, true, 1); } -TEST(CodegenTest, ReturnDivInt2Addr) { +TEST_P(CodegenTest, ReturnDivInt2Addr) { const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 4 << 12 | 0, Instruction::CONST_4 | 2 << 12 | 1 << 8, Instruction::DIV_INT_2ADDR | 1 << 12, Instruction::RETURN); - TestCode(data, true, 2); + TestCode(GetParam(), data, true, 2); } // Helper method. -static void TestComparison(IfCondition condition, int64_t i, int64_t j, Primitive::Type type) { +static void TestComparison(IfCondition condition, + int64_t i, + int64_t j, + Primitive::Type type, + const InstructionSet target_isa) { ArenaPool pool; ArenaAllocator allocator(&pool); HGraph* graph = CreateGraph(&allocator); @@ -862,46 +935,78 @@ static void TestComparison(IfCondition condition, int64_t i, int64_t j, Primitiv auto hook_before_codegen = [](HGraph*) { }; - RunCodeOptimized(graph, hook_before_codegen, true, expected_result); + RunCodeOptimized(target_isa, graph, hook_before_codegen, true, expected_result); } -TEST(CodegenTest, ComparisonsInt) { +TEST_P(CodegenTest, ComparisonsInt) { + const InstructionSet target_isa = GetParam(); for (int64_t i = -1; i <= 1; i++) { for (int64_t j = -1; j <= 1; j++) { - TestComparison(kCondEQ, i, j, Primitive::kPrimInt); - TestComparison(kCondNE, i, j, Primitive::kPrimInt); - TestComparison(kCondLT, i, j, Primitive::kPrimInt); - TestComparison(kCondLE, i, j, Primitive::kPrimInt); - TestComparison(kCondGT, i, j, Primitive::kPrimInt); - TestComparison(kCondGE, i, j, Primitive::kPrimInt); - TestComparison(kCondB, i, j, Primitive::kPrimInt); - TestComparison(kCondBE, i, j, Primitive::kPrimInt); - TestComparison(kCondA, i, j, Primitive::kPrimInt); - TestComparison(kCondAE, i, j, Primitive::kPrimInt); + TestComparison(kCondEQ, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondNE, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondLT, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondLE, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondGT, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondGE, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondB, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondBE, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondA, i, j, Primitive::kPrimInt, target_isa); + TestComparison(kCondAE, i, j, Primitive::kPrimInt, target_isa); } } } -TEST(CodegenTest, ComparisonsLong) { +TEST_P(CodegenTest, ComparisonsLong) { // TODO: make MIPS work for long if (kRuntimeISA == kMips || kRuntimeISA == kMips64) { return; } + const InstructionSet target_isa = GetParam(); + if (target_isa == kMips || target_isa == kMips64) { + return; + } + for (int64_t i = -1; i <= 1; i++) { for (int64_t j = -1; j <= 1; j++) { - TestComparison(kCondEQ, i, j, Primitive::kPrimLong); - TestComparison(kCondNE, i, j, Primitive::kPrimLong); - TestComparison(kCondLT, i, j, Primitive::kPrimLong); - TestComparison(kCondLE, i, j, Primitive::kPrimLong); - TestComparison(kCondGT, i, j, Primitive::kPrimLong); - TestComparison(kCondGE, i, j, Primitive::kPrimLong); - TestComparison(kCondB, i, j, Primitive::kPrimLong); - TestComparison(kCondBE, i, j, Primitive::kPrimLong); - TestComparison(kCondA, i, j, Primitive::kPrimLong); - TestComparison(kCondAE, i, j, Primitive::kPrimLong); + TestComparison(kCondEQ, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondNE, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondLT, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondLE, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondGT, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondGE, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondB, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondBE, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondA, i, j, Primitive::kPrimLong, target_isa); + TestComparison(kCondAE, i, j, Primitive::kPrimLong, target_isa); } } } +static ::std::vector<InstructionSet> GetTargetISAs() { + ::std::vector<InstructionSet> v; + // Add all ISAs that are executable on hardware or on simulator. + const ::std::vector<InstructionSet> executable_isa_candidates = { + kArm, + kArm64, + kThumb2, + kX86, + kX86_64, + kMips, + kMips64 + }; + + for (auto target_isa : executable_isa_candidates) { + if (CanExecute(target_isa)) { + v.push_back(target_isa); + } + } + + return v; +} + +INSTANTIATE_TEST_CASE_P(MultipleTargets, + CodegenTest, + ::testing::ValuesIn(GetTargetISAs())); + } // namespace art diff --git a/runtime/Android.mk b/runtime/Android.mk index 993f37f3f7..40961179d3 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -42,6 +42,7 @@ LIBART_COMMON_SRC_FILES := \ check_jni.cc \ class_linker.cc \ class_table.cc \ + code_simulator_container.cc \ common_throws.cc \ debugger.cc \ dex_file.cc \ diff --git a/runtime/base/logging.h b/runtime/base/logging.h index 2cd1a4de9f..115c26073d 100644 --- a/runtime/base/logging.h +++ b/runtime/base/logging.h @@ -48,6 +48,7 @@ struct LogVerbosity { bool oat; bool profiler; bool signals; + bool simulator; bool startup; bool third_party_jni; // Enabled with "-verbose:third-party-jni". bool threads; diff --git a/runtime/code_simulator_container.cc b/runtime/code_simulator_container.cc new file mode 100644 index 0000000000..d884c58782 --- /dev/null +++ b/runtime/code_simulator_container.cc @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dlfcn.h> + +#include "code_simulator_container.h" +#include "globals.h" + +namespace art { + +CodeSimulatorContainer::CodeSimulatorContainer(InstructionSet target_isa) + : libart_simulator_handle_(nullptr), + simulator_(nullptr) { + const char* libart_simulator_so_name = + kIsDebugBuild ? "libartd-simulator.so" : "libart-simulator.so"; + libart_simulator_handle_ = dlopen(libart_simulator_so_name, RTLD_NOW); + // It is not a real error when libart-simulator does not exist, e.g., on target. + if (libart_simulator_handle_ == nullptr) { + VLOG(simulator) << "Could not load " << libart_simulator_so_name << ": " << dlerror(); + } else { + typedef CodeSimulator* (*create_code_simulator_ptr_)(InstructionSet target_isa); + create_code_simulator_ptr_ create_code_simulator_ = + reinterpret_cast<create_code_simulator_ptr_>( + dlsym(libart_simulator_handle_, "CreateCodeSimulator")); + DCHECK(create_code_simulator_ != nullptr) << "Fail to find symbol of CreateCodeSimulator: " + << dlerror(); + simulator_ = create_code_simulator_(target_isa); + } +} + +CodeSimulatorContainer::~CodeSimulatorContainer() { + // Free simulator object before closing libart-simulator because destructor of + // CodeSimulator lives in it. + if (simulator_ != nullptr) { + delete simulator_; + } + if (libart_simulator_handle_ != nullptr) { + dlclose(libart_simulator_handle_); + } +} + +} // namespace art diff --git a/runtime/code_simulator_container.h b/runtime/code_simulator_container.h new file mode 100644 index 0000000000..655a2472f4 --- /dev/null +++ b/runtime/code_simulator_container.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_CODE_SIMULATOR_CONTAINER_H_ +#define ART_RUNTIME_CODE_SIMULATOR_CONTAINER_H_ + +#include "arch/instruction_set.h" +#include "simulator/code_simulator.h" + +namespace art { + +// This container dynamically opens and closes libart-simulator. +class CodeSimulatorContainer { + public: + explicit CodeSimulatorContainer(InstructionSet target_isa); + ~CodeSimulatorContainer(); + + bool CanSimulate() const { + return simulator_ != nullptr; + } + + CodeSimulator* Get() { + DCHECK(CanSimulate()); + return simulator_; + } + + const CodeSimulator* Get() const { + DCHECK(CanSimulate()); + return simulator_; + } + + private: + void* libart_simulator_handle_; + CodeSimulator* simulator_; + + DISALLOW_COPY_AND_ASSIGN(CodeSimulatorContainer); +}; + +} // namespace art + +#endif // ART_RUNTIME_CODE_SIMULATOR_CONTAINER_H_ diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index 5b1061087d..2b92303fe2 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -399,6 +399,7 @@ static void MaybeOverrideVerbosity() { // gLogVerbosity.oat = true; // TODO: don't check this in! // gLogVerbosity.profiler = true; // TODO: don't check this in! // gLogVerbosity.signals = true; // TODO: don't check this in! + // gLogVerbosity.simulator = true; // TODO: don't check this in! // gLogVerbosity.startup = true; // TODO: don't check this in! // gLogVerbosity.third_party_jni = true; // TODO: don't check this in! // gLogVerbosity.threads = true; // TODO: don't check this in! diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc index fad00c73d8..06b40fd925 100644 --- a/runtime/parsed_options_test.cc +++ b/runtime/parsed_options_test.cc @@ -87,6 +87,8 @@ TEST_F(ParsedOptionsTest, ParsedOptions) { EXPECT_FALSE(VLOG_IS_ON(jdwp)); EXPECT_TRUE(VLOG_IS_ON(jni)); EXPECT_FALSE(VLOG_IS_ON(monitor)); + EXPECT_FALSE(VLOG_IS_ON(signals)); + EXPECT_FALSE(VLOG_IS_ON(simulator)); EXPECT_FALSE(VLOG_IS_ON(startup)); EXPECT_FALSE(VLOG_IS_ON(third_party_jni)); EXPECT_FALSE(VLOG_IS_ON(threads)); diff --git a/runtime/simulator/Android.mk b/runtime/simulator/Android.mk new file mode 100644 index 0000000000..c154eb6346 --- /dev/null +++ b/runtime/simulator/Android.mk @@ -0,0 +1,105 @@ +# +# Copyright (C) 2015 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +include art/build/Android.common_build.mk + +LIBART_SIMULATOR_SRC_FILES := \ + code_simulator.cc \ + code_simulator_arm64.cc + +# $(1): target or host +# $(2): ndebug or debug +define build-libart-simulator + ifneq ($(1),target) + ifneq ($(1),host) + $$(error expected target or host for argument 1, received $(1)) + endif + endif + ifneq ($(2),ndebug) + ifneq ($(2),debug) + $$(error expected ndebug or debug for argument 2, received $(2)) + endif + endif + + art_target_or_host := $(1) + art_ndebug_or_debug := $(2) + + include $(CLEAR_VARS) + ifeq ($$(art_target_or_host),host) + LOCAL_IS_HOST_MODULE := true + endif + LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION) + ifeq ($$(art_ndebug_or_debug),ndebug) + LOCAL_MODULE := libart-simulator + else # debug + LOCAL_MODULE := libartd-simulator + endif + + LOCAL_MODULE_TAGS := optional + LOCAL_MODULE_CLASS := SHARED_LIBRARIES + + LOCAL_SRC_FILES := $$(LIBART_SIMULATOR_SRC_FILES) + + ifeq ($$(art_target_or_host),target) + $(call set-target-local-clang-vars) + $(call set-target-local-cflags-vars,$(2)) + else # host + LOCAL_CLANG := $(ART_HOST_CLANG) + LOCAL_LDLIBS := $(ART_HOST_LDLIBS) + LOCAL_CFLAGS += $(ART_HOST_CFLAGS) + LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS) + ifeq ($$(art_ndebug_or_debug),debug) + LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS) + else + LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS) + endif + endif + + LOCAL_SHARED_LIBRARIES += liblog + ifeq ($$(art_ndebug_or_debug),debug) + LOCAL_SHARED_LIBRARIES += libartd + else + LOCAL_SHARED_LIBRARIES += libart + endif + + LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime + LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + LOCAL_MULTILIB := both + + LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk + LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk + LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE) + # For simulator_arm64. + ifeq ($$(art_ndebug_or_debug),debug) + LOCAL_SHARED_LIBRARIES += libvixld + else + LOCAL_SHARED_LIBRARIES += libvixl + endif + ifeq ($$(art_target_or_host),target) + include $(BUILD_SHARED_LIBRARY) + else # host + include $(BUILD_HOST_SHARED_LIBRARY) + endif +endef + +ifeq ($(ART_BUILD_HOST_NDEBUG),true) + $(eval $(call build-libart-simulator,host,ndebug)) +endif +ifeq ($(ART_BUILD_HOST_DEBUG),true) + $(eval $(call build-libart-simulator,host,debug)) +endif diff --git a/runtime/simulator/code_simulator.cc b/runtime/simulator/code_simulator.cc new file mode 100644 index 0000000000..1a1116050e --- /dev/null +++ b/runtime/simulator/code_simulator.cc @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "simulator/code_simulator.h" +#include "simulator/code_simulator_arm64.h" + +namespace art { + +CodeSimulator* CodeSimulator::CreateCodeSimulator(InstructionSet target_isa) { + switch (target_isa) { + case kArm64: + return arm64::CodeSimulatorArm64::CreateCodeSimulatorArm64(); + default: + return nullptr; + } +} + +CodeSimulator* CreateCodeSimulator(InstructionSet target_isa) { + return CodeSimulator::CreateCodeSimulator(target_isa); +} + +} // namespace art diff --git a/runtime/simulator/code_simulator.h b/runtime/simulator/code_simulator.h new file mode 100644 index 0000000000..bd48909e41 --- /dev/null +++ b/runtime/simulator/code_simulator.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_SIMULATOR_CODE_SIMULATOR_H_ +#define ART_RUNTIME_SIMULATOR_CODE_SIMULATOR_H_ + +#include "arch/instruction_set.h" + +namespace art { + +class CodeSimulator { + public: + CodeSimulator() {} + virtual ~CodeSimulator() {} + // Returns a null pointer if a simulator cannot be found for target_isa. + static CodeSimulator* CreateCodeSimulator(InstructionSet target_isa); + + virtual void RunFrom(intptr_t code_buffer) = 0; + + // Get return value according to C ABI. + virtual bool GetCReturnBool() const = 0; + virtual int32_t GetCReturnInt32() const = 0; + virtual int64_t GetCReturnInt64() const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(CodeSimulator); +}; + +extern "C" CodeSimulator* CreateCodeSimulator(InstructionSet target_isa); + +} // namespace art + +#endif // ART_RUNTIME_SIMULATOR_CODE_SIMULATOR_H_ diff --git a/runtime/simulator/code_simulator_arm64.cc b/runtime/simulator/code_simulator_arm64.cc new file mode 100644 index 0000000000..39dfa6dafb --- /dev/null +++ b/runtime/simulator/code_simulator_arm64.cc @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "simulator/code_simulator_arm64.h" + +namespace art { +namespace arm64 { + +// VIXL has not been tested on 32bit architectures, so vixl::Simulator is not always +// available. To avoid linker error on these architectures, we check if we can simulate +// in the beginning of following methods, with compile time constant `kCanSimulate`. +// TODO: when vixl::Simulator is always available, remove the these checks. + +CodeSimulatorArm64* CodeSimulatorArm64::CreateCodeSimulatorArm64() { + if (kCanSimulate) { + return new CodeSimulatorArm64(); + } else { + return nullptr; + } +} + +CodeSimulatorArm64::CodeSimulatorArm64() + : CodeSimulator(), decoder_(nullptr), simulator_(nullptr) { + DCHECK(kCanSimulate); + decoder_ = new vixl::Decoder(); + simulator_ = new vixl::Simulator(decoder_); +} + +CodeSimulatorArm64::~CodeSimulatorArm64() { + DCHECK(kCanSimulate); + delete simulator_; + delete decoder_; +} + +void CodeSimulatorArm64::RunFrom(intptr_t code_buffer) { + DCHECK(kCanSimulate); + simulator_->RunFrom(reinterpret_cast<const vixl::Instruction*>(code_buffer)); +} + +bool CodeSimulatorArm64::GetCReturnBool() const { + DCHECK(kCanSimulate); + return simulator_->wreg(0); +} + +int32_t CodeSimulatorArm64::GetCReturnInt32() const { + DCHECK(kCanSimulate); + return simulator_->wreg(0); +} + +int64_t CodeSimulatorArm64::GetCReturnInt64() const { + DCHECK(kCanSimulate); + return simulator_->xreg(0); +} + +} // namespace arm64 +} // namespace art diff --git a/runtime/simulator/code_simulator_arm64.h b/runtime/simulator/code_simulator_arm64.h new file mode 100644 index 0000000000..10fceb98f7 --- /dev/null +++ b/runtime/simulator/code_simulator_arm64.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_SIMULATOR_CODE_SIMULATOR_ARM64_H_ +#define ART_RUNTIME_SIMULATOR_CODE_SIMULATOR_ARM64_H_ + +#include "memory" +#include "simulator/code_simulator.h" +// TODO: make vixl clean wrt -Wshadow. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#include "vixl/a64/simulator-a64.h" +#pragma GCC diagnostic pop + +namespace art { +namespace arm64 { + +class CodeSimulatorArm64 : public CodeSimulator { + public: + static CodeSimulatorArm64* CreateCodeSimulatorArm64(); + virtual ~CodeSimulatorArm64(); + + void RunFrom(intptr_t code_buffer) OVERRIDE; + + bool GetCReturnBool() const OVERRIDE; + int32_t GetCReturnInt32() const OVERRIDE; + int64_t GetCReturnInt64() const OVERRIDE; + + private: + CodeSimulatorArm64(); + + vixl::Decoder* decoder_; + vixl::Simulator* simulator_; + + // TODO: Enable CodeSimulatorArm64 for more host ISAs once vixl::Simulator supports them. + static constexpr bool kCanSimulate = (kRuntimeISA == kX86_64); + + DISALLOW_COPY_AND_ASSIGN(CodeSimulatorArm64); +}; + +} // namespace arm64 +} // namespace art + +#endif // ART_RUNTIME_SIMULATOR_CODE_SIMULATOR_ARM64_H_ |