1 /* 2 * Copyright (C) 2014 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 #ifndef ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_ 18 #define ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_ 19 20 #include "base/macros.h" 21 #include "base/mutex.h" 22 #include "dex_file.h" 23 #include "dex_instruction.h" 24 #include "method_reference.h" 25 26 /* 27 * NOTE: This code is part of the quick compiler. It lives in the runtime 28 * only to allow the debugger to check whether a method has been inlined. 29 */ 30 31 namespace art { 32 33 namespace verifier { 34 class MethodVerifier; 35 } // namespace verifier 36 37 enum InlineMethodOpcode : uint16_t { 38 kIntrinsicDoubleCvt, 39 kIntrinsicFloatCvt, 40 kIntrinsicReverseBits, 41 kIntrinsicReverseBytes, 42 kIntrinsicAbsInt, 43 kIntrinsicAbsLong, 44 kIntrinsicAbsFloat, 45 kIntrinsicAbsDouble, 46 kIntrinsicMinMaxInt, 47 kIntrinsicMinMaxLong, 48 kIntrinsicMinMaxFloat, 49 kIntrinsicMinMaxDouble, 50 kIntrinsicSqrt, 51 kIntrinsicCeil, 52 kIntrinsicFloor, 53 kIntrinsicRint, 54 kIntrinsicRoundFloat, 55 kIntrinsicRoundDouble, 56 kIntrinsicReferenceGetReferent, 57 kIntrinsicCharAt, 58 kIntrinsicCompareTo, 59 kIntrinsicIsEmptyOrLength, 60 kIntrinsicIndexOf, 61 kIntrinsicCurrentThread, 62 kIntrinsicPeek, 63 kIntrinsicPoke, 64 kIntrinsicCas, 65 kIntrinsicUnsafeGet, 66 kIntrinsicUnsafePut, 67 kIntrinsicSystemArrayCopyCharArray, 68 69 kInlineOpNop, 70 kInlineOpReturnArg, 71 kInlineOpNonWideConst, 72 kInlineOpIGet, 73 kInlineOpIPut, 74 }; 75 std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs); 76 77 enum InlineMethodFlags : uint16_t { 78 kNoInlineMethodFlags = 0x0000, 79 kInlineIntrinsic = 0x0001, 80 kInlineSpecial = 0x0002, 81 }; 82 83 // IntrinsicFlags are stored in InlineMethod::d::raw_data 84 enum IntrinsicFlags { 85 kIntrinsicFlagNone = 0, 86 87 // kIntrinsicMinMaxInt 88 kIntrinsicFlagMax = kIntrinsicFlagNone, 89 kIntrinsicFlagMin = 1, 90 91 // kIntrinsicIsEmptyOrLength 92 kIntrinsicFlagLength = kIntrinsicFlagNone, 93 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin, 94 95 // kIntrinsicIndexOf 96 kIntrinsicFlagBase0 = kIntrinsicFlagMin, 97 98 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas 99 kIntrinsicFlagIsLong = kIntrinsicFlagMin, 100 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut 101 kIntrinsicFlagIsVolatile = 2, 102 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas 103 kIntrinsicFlagIsObject = 4, 104 // kIntrinsicUnsafePut 105 kIntrinsicFlagIsOrdered = 8, 106 }; 107 108 struct InlineIGetIPutData { 109 // The op_variant below is opcode-Instruction::IGET for IGETs and 110 // opcode-Instruction::IPUT for IPUTs. This is because the runtime 111 // doesn't know the OpSize enumeration. 112 uint16_t op_variant : 3; 113 uint16_t method_is_static : 1; 114 uint16_t object_arg : 4; 115 uint16_t src_arg : 4; // iput only 116 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void. 117 uint16_t field_idx; 118 uint32_t is_volatile : 1; 119 uint32_t field_offset : 31; 120 }; 121 COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint64_t), InvalidSizeOfInlineIGetIPutData); 122 123 struct InlineReturnArgData { 124 uint16_t arg; 125 uint16_t is_wide : 1; 126 uint16_t is_object : 1; 127 uint16_t reserved : 14; 128 uint32_t reserved2; 129 }; 130 COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData); 131 132 struct InlineMethod { 133 InlineMethodOpcode opcode; 134 InlineMethodFlags flags; 135 union { 136 uint64_t data; 137 InlineIGetIPutData ifield_data; 138 InlineReturnArgData return_data; 139 } d; 140 }; 141 142 class InlineMethodAnalyser { 143 public: 144 /** 145 * Analyse method code to determine if the method is a candidate for inlining. 146 * If it is, record the inlining data. 147 * 148 * @param verifier the method verifier holding data about the method to analyse. 149 * @param method placeholder for the inline method data. 150 * @return true if the method is a candidate for inlining, false otherwise. 151 */ 152 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method) 153 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 154 IsInstructionIGet(Instruction::Code opcode)155 static constexpr bool IsInstructionIGet(Instruction::Code opcode) { 156 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT; 157 } 158 IsInstructionIPut(Instruction::Code opcode)159 static constexpr bool IsInstructionIPut(Instruction::Code opcode) { 160 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT; 161 } 162 IGetVariant(Instruction::Code opcode)163 static constexpr uint16_t IGetVariant(Instruction::Code opcode) { 164 return opcode - Instruction::IGET; 165 } 166 IPutVariant(Instruction::Code opcode)167 static constexpr uint16_t IPutVariant(Instruction::Code opcode) { 168 return opcode - Instruction::IPUT; 169 } 170 171 // Determines whether the method is a synthetic accessor (method name starts with "access$"). 172 static bool IsSyntheticAccessor(MethodReference ref); 173 174 private: 175 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result); 176 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result); 177 static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result) 178 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 179 static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result) 180 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 181 182 // Can we fast path instance field access in a verified accessor? 183 // If yes, computes field's offset and volatility and whether the method is static or not. 184 static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put, 185 verifier::MethodVerifier* verifier, 186 InlineIGetIPutData* result) 187 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 188 }; 189 190 } // namespace art 191 192 #endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_ 193