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 kIntrinsicFloat2Int, 41 kIntrinsicDouble2Long, 42 kIntrinsicFloatIsInfinite, 43 kIntrinsicDoubleIsInfinite, 44 kIntrinsicFloatIsNaN, 45 kIntrinsicDoubleIsNaN, 46 kIntrinsicReverseBits, 47 kIntrinsicReverseBytes, 48 kIntrinsicBitCount, 49 kIntrinsicCompare, 50 kIntrinsicHighestOneBit, 51 kIntrinsicLowestOneBit, 52 kIntrinsicNumberOfLeadingZeros, 53 kIntrinsicNumberOfTrailingZeros, 54 kIntrinsicRotateRight, 55 kIntrinsicRotateLeft, 56 kIntrinsicSignum, 57 kIntrinsicAbsInt, 58 kIntrinsicAbsLong, 59 kIntrinsicAbsFloat, 60 kIntrinsicAbsDouble, 61 kIntrinsicMinMaxInt, 62 kIntrinsicMinMaxLong, 63 kIntrinsicMinMaxFloat, 64 kIntrinsicMinMaxDouble, 65 kIntrinsicCos, 66 kIntrinsicSin, 67 kIntrinsicAcos, 68 kIntrinsicAsin, 69 kIntrinsicAtan, 70 kIntrinsicAtan2, 71 kIntrinsicCbrt, 72 kIntrinsicCosh, 73 kIntrinsicExp, 74 kIntrinsicExpm1, 75 kIntrinsicHypot, 76 kIntrinsicLog, 77 kIntrinsicLog10, 78 kIntrinsicNextAfter, 79 kIntrinsicSinh, 80 kIntrinsicTan, 81 kIntrinsicTanh, 82 kIntrinsicSqrt, 83 kIntrinsicCeil, 84 kIntrinsicFloor, 85 kIntrinsicRint, 86 kIntrinsicRoundFloat, 87 kIntrinsicRoundDouble, 88 kIntrinsicReferenceGetReferent, 89 kIntrinsicCharAt, 90 kIntrinsicCompareTo, 91 kIntrinsicEquals, 92 kIntrinsicGetCharsNoCheck, 93 kIntrinsicIsEmptyOrLength, 94 kIntrinsicIndexOf, 95 kIntrinsicNewStringFromBytes, 96 kIntrinsicNewStringFromChars, 97 kIntrinsicNewStringFromString, 98 kIntrinsicCurrentThread, 99 kIntrinsicPeek, 100 kIntrinsicPoke, 101 kIntrinsicCas, 102 kIntrinsicUnsafeGet, 103 kIntrinsicUnsafePut, 104 105 // 1.8. 106 kIntrinsicUnsafeGetAndAddInt, 107 kIntrinsicUnsafeGetAndAddLong, 108 kIntrinsicUnsafeGetAndSetInt, 109 kIntrinsicUnsafeGetAndSetLong, 110 kIntrinsicUnsafeGetAndSetObject, 111 kIntrinsicUnsafeLoadFence, 112 kIntrinsicUnsafeStoreFence, 113 kIntrinsicUnsafeFullFence, 114 115 kIntrinsicSystemArrayCopyCharArray, 116 kIntrinsicSystemArrayCopy, 117 118 kInlineOpNop, 119 kInlineOpReturnArg, 120 kInlineOpNonWideConst, 121 kInlineOpIGet, 122 kInlineOpIPut, 123 kInlineOpConstructor, 124 kInlineStringInit, 125 }; 126 std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs); 127 128 enum InlineMethodFlags : uint16_t { 129 kNoInlineMethodFlags = 0x0000, 130 kInlineIntrinsic = 0x0001, 131 kInlineSpecial = 0x0002, 132 }; 133 134 // IntrinsicFlags are stored in InlineMethod::d::raw_data 135 enum IntrinsicFlags { 136 kIntrinsicFlagNone = 0, 137 138 // kIntrinsicMinMaxInt 139 kIntrinsicFlagMax = kIntrinsicFlagNone, 140 kIntrinsicFlagMin = 1, 141 142 // kIntrinsicIsEmptyOrLength 143 kIntrinsicFlagLength = kIntrinsicFlagNone, 144 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin, 145 146 // kIntrinsicIndexOf 147 kIntrinsicFlagBase0 = kIntrinsicFlagMin, 148 149 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas 150 kIntrinsicFlagIsLong = kIntrinsicFlagMin, 151 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut 152 kIntrinsicFlagIsVolatile = 2, 153 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas 154 kIntrinsicFlagIsObject = 4, 155 // kIntrinsicUnsafePut 156 kIntrinsicFlagIsOrdered = 8, 157 158 // kIntrinsicDoubleCvt, kIntrinsicFloatCvt. 159 kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin, 160 }; 161 162 struct InlineIGetIPutData { 163 // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration. 164 uint16_t op_variant : 3; 165 uint16_t method_is_static : 1; 166 uint16_t object_arg : 4; 167 uint16_t src_arg : 4; // iput only 168 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void. 169 uint16_t field_idx; 170 uint32_t is_volatile : 1; 171 uint32_t field_offset : 31; 172 }; 173 static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData"); 174 175 struct InlineReturnArgData { 176 uint16_t arg; 177 uint16_t is_wide : 1; 178 uint16_t is_object : 1; 179 uint16_t reserved : 14; 180 uint32_t reserved2; 181 }; 182 static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t), 183 "Invalid size of InlineReturnArgData"); 184 185 struct InlineConstructorData { 186 // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16. 187 uint16_t iput0_field_index; 188 uint16_t iput1_field_index; 189 uint16_t iput2_field_index; 190 uint16_t iput0_arg : 4; 191 uint16_t iput1_arg : 4; 192 uint16_t iput2_arg : 4; 193 uint16_t reserved : 4; 194 }; 195 static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t), 196 "Invalid size of InlineConstructorData"); 197 198 struct InlineMethod { 199 InlineMethodOpcode opcode; 200 InlineMethodFlags flags; 201 union { 202 uint64_t data; 203 InlineIGetIPutData ifield_data; 204 InlineReturnArgData return_data; 205 InlineConstructorData constructor_data; 206 } d; 207 }; 208 209 class InlineMethodAnalyser { 210 public: 211 /** 212 * Analyse method code to determine if the method is a candidate for inlining. 213 * If it is, record the inlining data. 214 * 215 * @param verifier the method verifier holding data about the method to analyse. 216 * @param method placeholder for the inline method data. 217 * @return true if the method is a candidate for inlining, false otherwise. 218 */ 219 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* result) 220 SHARED_REQUIRES(Locks::mutator_lock_); 221 static bool AnalyseMethodCode(ArtMethod* method, InlineMethod* result) 222 SHARED_REQUIRES(Locks::mutator_lock_); 223 IsInstructionIGet(Instruction::Code opcode)224 static constexpr bool IsInstructionIGet(Instruction::Code opcode) { 225 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT; 226 } 227 IsInstructionIPut(Instruction::Code opcode)228 static constexpr bool IsInstructionIPut(Instruction::Code opcode) { 229 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT; 230 } 231 IGetVariant(Instruction::Code opcode)232 static constexpr uint16_t IGetVariant(Instruction::Code opcode) { 233 return opcode - Instruction::IGET; 234 } 235 IPutVariant(Instruction::Code opcode)236 static constexpr uint16_t IPutVariant(Instruction::Code opcode) { 237 return opcode - Instruction::IPUT; 238 } 239 240 // Determines whether the method is a synthetic accessor (method name starts with "access$"). 241 static bool IsSyntheticAccessor(MethodReference ref); 242 243 private: 244 static bool AnalyseMethodCode(const DexFile::CodeItem* code_item, 245 const MethodReference& method_ref, 246 bool is_static, 247 ArtMethod* method, 248 InlineMethod* result) 249 SHARED_REQUIRES(Locks::mutator_lock_); 250 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result); 251 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result); 252 static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item, 253 const MethodReference& method_ref, 254 bool is_static, 255 ArtMethod* method, 256 InlineMethod* result) 257 SHARED_REQUIRES(Locks::mutator_lock_); 258 static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item, 259 const MethodReference& method_ref, 260 bool is_static, 261 ArtMethod* method, 262 InlineMethod* result) 263 SHARED_REQUIRES(Locks::mutator_lock_); 264 265 // Can we fast path instance field access in a verified accessor? 266 // If yes, computes field's offset and volatility and whether the method is static or not. 267 static bool ComputeSpecialAccessorInfo(ArtMethod* method, 268 uint32_t field_idx, 269 bool is_put, 270 InlineIGetIPutData* result) 271 SHARED_REQUIRES(Locks::mutator_lock_); 272 }; 273 274 } // namespace art 275 276 #endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_ 277