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/enums.h" 23 #include "base/macros.h" 24 #include "base/malloc_arena_pool.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 // Run the tests only on host. 37 #ifndef ART_TARGET_ANDROID 38 39 class JNICFITest : public CFITest { 40 public: 41 // Enable this flag to generate the expected outputs. 42 static constexpr bool kGenerateExpected = false; 43 TestImpl(InstructionSet isa,const char * isa_str,const std::vector<uint8_t> & expected_asm,const std::vector<uint8_t> & expected_cfi)44 void TestImpl(InstructionSet isa, 45 const char* isa_str, 46 const std::vector<uint8_t>& expected_asm, 47 const std::vector<uint8_t>& expected_cfi) { 48 if (Is64BitInstructionSet(isa)) { 49 TestImplSized<PointerSize::k64>(isa, isa_str, expected_asm, expected_cfi); 50 } else { 51 TestImplSized<PointerSize::k32>(isa, isa_str, expected_asm, expected_cfi); 52 } 53 } 54 55 private: 56 template <PointerSize kPointerSize> TestImplSized(InstructionSet isa,const char * isa_str,const std::vector<uint8_t> & expected_asm,const std::vector<uint8_t> & expected_cfi)57 void TestImplSized(InstructionSet isa, 58 const char* isa_str, 59 const std::vector<uint8_t>& expected_asm, 60 const std::vector<uint8_t>& expected_cfi) { 61 // Description of simple method. 62 const bool is_static = true; 63 const bool is_synchronized = false; 64 const char* shorty = "IIFII"; 65 66 MallocArenaPool pool; 67 ArenaAllocator allocator(&pool); 68 69 std::unique_ptr<JniCallingConvention> jni_conv( 70 JniCallingConvention::Create(&allocator, 71 is_static, 72 is_synchronized, 73 /*is_fast_native=*/ false, 74 /*is_critical_native=*/ false, 75 shorty, 76 isa)); 77 std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv( 78 ManagedRuntimeCallingConvention::Create( 79 &allocator, is_static, is_synchronized, shorty, isa)); 80 const int frame_size(jni_conv->FrameSize()); 81 ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters(); 82 83 // Assemble the method. 84 std::unique_ptr<JNIMacroAssembler<kPointerSize>> jni_asm( 85 JNIMacroAssembler<kPointerSize>::Create(&allocator, isa)); 86 jni_asm->cfi().SetEnabled(true); 87 jni_asm->BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs); 88 // Spill arguments. 89 mr_conv->ResetIterator(FrameOffset(frame_size)); 90 for (; mr_conv->HasNext(); mr_conv->Next()) { 91 if (mr_conv->IsCurrentParamInRegister()) { 92 size_t size = mr_conv->IsCurrentParamALongOrDouble() ? 8u : 4u; 93 jni_asm->Store(mr_conv->CurrentParamStackOffset(), mr_conv->CurrentParamRegister(), size); 94 } 95 } 96 jni_asm->IncreaseFrameSize(32); 97 jni_asm->DecreaseFrameSize(32); 98 jni_asm->RemoveFrame(frame_size, callee_save_regs, /* may_suspend= */ true); 99 jni_asm->FinalizeCode(); 100 std::vector<uint8_t> actual_asm(jni_asm->CodeSize()); 101 MemoryRegion code(&actual_asm[0], actual_asm.size()); 102 jni_asm->FinalizeInstructions(code); 103 ASSERT_EQ(jni_asm->cfi().GetCurrentCFAOffset(), frame_size); 104 const std::vector<uint8_t>& actual_cfi = *(jni_asm->cfi().data()); 105 106 if (kGenerateExpected) { 107 GenerateExpected(stdout, 108 isa, 109 isa_str, 110 ArrayRef<const uint8_t>(actual_asm), 111 ArrayRef<const uint8_t>(actual_cfi)); 112 } else { 113 EXPECT_EQ(expected_asm, actual_asm); 114 EXPECT_EQ(expected_cfi, actual_cfi); 115 } 116 } 117 }; 118 119 #define TEST_ISA(isa) \ 120 TEST_F(JNICFITest, isa) { \ 121 std::vector<uint8_t> expected_asm(expected_asm_##isa, \ 122 expected_asm_##isa + arraysize(expected_asm_##isa)); \ 123 std::vector<uint8_t> expected_cfi(expected_cfi_##isa, \ 124 expected_cfi_##isa + arraysize(expected_cfi_##isa)); \ 125 TestImpl(InstructionSet::isa, #isa, expected_asm, expected_cfi); \ 126 } 127 128 // We can't use compile-time macros for read-barrier as the introduction 129 // of userfaultfd-GC has made it a runtime choice. 130 #define TEST_ISA_ONLY_CC(isa) \ 131 TEST_F(JNICFITest, isa) { \ 132 if (kUseBakerReadBarrier && gUseReadBarrier) { \ 133 std::vector<uint8_t> expected_asm(expected_asm_##isa, \ 134 expected_asm_##isa + arraysize(expected_asm_##isa)); \ 135 std::vector<uint8_t> expected_cfi(expected_cfi_##isa, \ 136 expected_cfi_##isa + arraysize(expected_cfi_##isa)); \ 137 TestImpl(InstructionSet::isa, #isa, expected_asm, expected_cfi); \ 138 } \ 139 } 140 141 #ifdef ART_ENABLE_CODEGEN_arm 142 // Run the tests for ARM only with Baker read barriers, as the 143 // expected generated code contains a Marking Register refresh 144 // instruction. 145 TEST_ISA_ONLY_CC(kThumb2) 146 #endif 147 148 #ifdef ART_ENABLE_CODEGEN_arm64 149 // Run the tests for ARM64 only with Baker read barriers, as the 150 // expected generated code contains a Marking Register refresh 151 // instruction. 152 TEST_ISA_ONLY_CC(kArm64) 153 #endif 154 155 #ifdef ART_ENABLE_CODEGEN_x86 156 TEST_ISA(kX86) 157 #endif 158 159 #ifdef ART_ENABLE_CODEGEN_x86_64 160 TEST_ISA(kX86_64) 161 #endif 162 163 #endif // ART_TARGET_ANDROID 164 165 } // namespace art 166