1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <memory> 18 #include <vector> 19 20 #include "arch/instruction_set.h" 21 #include "base/arena_allocator.h" 22 #include "base/macros.h" 23 #include "base/malloc_arena_pool.h" 24 #include "base/pointer_size.h" 25 #include "cfi_test.h" 26 #include "gtest/gtest.h" 27 #include "jni/quick/calling_convention.h" 28 #include "read_barrier_config.h" 29 #include "utils/assembler.h" 30 #include "utils/jni_macro_assembler.h" 31 32 #include "jni/jni_cfi_test_expected.inc" 33 34 namespace art HIDDEN { 35 36 class JNICFITest : public CFITest { 37 public: 38 // Enable this flag to generate the expected outputs. 39 static constexpr bool kGenerateExpected = false; 40 TestImpl(InstructionSet isa,const char * isa_str,const std::vector<uint8_t> & expected_asm,const std::vector<uint8_t> & expected_cfi)41 void TestImpl(InstructionSet isa, 42 const char* isa_str, 43 const std::vector<uint8_t>& expected_asm, 44 const std::vector<uint8_t>& expected_cfi) { 45 if (Is64BitInstructionSet(isa)) { 46 TestImplSized<PointerSize::k64>(isa, isa_str, expected_asm, expected_cfi); 47 } else { 48 TestImplSized<PointerSize::k32>(isa, isa_str, expected_asm, expected_cfi); 49 } 50 } 51 52 private: 53 template <PointerSize kPointerSize> TestImplSized(InstructionSet isa,const char * isa_str,const std::vector<uint8_t> & expected_asm,const std::vector<uint8_t> & expected_cfi)54 void TestImplSized(InstructionSet isa, 55 const char* isa_str, 56 const std::vector<uint8_t>& expected_asm, 57 const std::vector<uint8_t>& expected_cfi) { 58 // Description of simple method. 59 const bool is_static = true; 60 const bool is_synchronized = false; 61 const char* shorty = "IIFII"; 62 63 MallocArenaPool pool; 64 ArenaAllocator allocator(&pool); 65 66 std::unique_ptr<JniCallingConvention> jni_conv( 67 JniCallingConvention::Create(&allocator, 68 is_static, 69 is_synchronized, 70 /*is_fast_native=*/ false, 71 /*is_critical_native=*/ false, 72 shorty, 73 isa)); 74 std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv( 75 ManagedRuntimeCallingConvention::Create( 76 &allocator, is_static, is_synchronized, shorty, isa)); 77 const int frame_size(jni_conv->FrameSize()); 78 ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters(); 79 80 // Assemble the method. 81 std::unique_ptr<JNIMacroAssembler<kPointerSize>> jni_asm( 82 JNIMacroAssembler<kPointerSize>::Create(&allocator, isa)); 83 jni_asm->cfi().SetEnabled(true); 84 jni_asm->BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs); 85 // Spill arguments. 86 mr_conv->ResetIterator(FrameOffset(frame_size)); 87 for (; mr_conv->HasNext(); mr_conv->Next()) { 88 if (mr_conv->IsCurrentParamInRegister()) { 89 size_t size = mr_conv->IsCurrentParamALongOrDouble() ? 8u : 4u; 90 jni_asm->Store(mr_conv->CurrentParamStackOffset(), mr_conv->CurrentParamRegister(), size); 91 } 92 } 93 jni_asm->IncreaseFrameSize(32); 94 jni_asm->DecreaseFrameSize(32); 95 jni_asm->RemoveFrame(frame_size, callee_save_regs, /* may_suspend= */ true); 96 jni_asm->FinalizeCode(); 97 std::vector<uint8_t> actual_asm(jni_asm->CodeSize()); 98 MemoryRegion code(&actual_asm[0], actual_asm.size()); 99 jni_asm->CopyInstructions(code); 100 ASSERT_EQ(jni_asm->cfi().GetCurrentCFAOffset(), frame_size); 101 const std::vector<uint8_t>& actual_cfi = *(jni_asm->cfi().data()); 102 103 if (kGenerateExpected) { 104 GenerateExpected(stdout, 105 isa, 106 isa_str, 107 ArrayRef<const uint8_t>(actual_asm), 108 ArrayRef<const uint8_t>(actual_cfi)); 109 } else { 110 EXPECT_EQ(expected_asm, actual_asm); 111 EXPECT_EQ(expected_cfi, actual_cfi); 112 } 113 } 114 }; 115 116 #define TEST_ISA(isa) \ 117 TEST_F(JNICFITest, isa) { \ 118 std::vector<uint8_t> expected_asm(expected_asm_##isa, \ 119 expected_asm_##isa + arraysize(expected_asm_##isa)); \ 120 std::vector<uint8_t> expected_cfi(expected_cfi_##isa, \ 121 expected_cfi_##isa + arraysize(expected_cfi_##isa)); \ 122 TestImpl(InstructionSet::isa, #isa, expected_asm, expected_cfi); \ 123 } 124 125 #ifdef ART_ENABLE_CODEGEN_arm 126 // Run the tests for ARM only if the Marking Register is reserved as the 127 // expected generated code contains a Marking Register refresh instruction. 128 #if defined(RESERVE_MARKING_REGISTER) 129 TEST_ISA(kThumb2) 130 #endif 131 #endif 132 133 #ifdef ART_ENABLE_CODEGEN_arm64 134 // Run the tests for ARM64 only if the Marking Register is reserved as the 135 // expected generated code contains a Marking Register refresh instruction. 136 #if defined(RESERVE_MARKING_REGISTER) 137 TEST_ISA(kArm64) 138 #endif 139 #endif 140 141 #ifdef ART_ENABLE_CODEGEN_x86 142 TEST_ISA(kX86) 143 #endif 144 145 #ifdef ART_ENABLE_CODEGEN_x86_64 146 TEST_ISA(kX86_64) 147 #endif 148 149 } // namespace art 150