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 kIntrinsicGetCharsNoCheck, 60 kIntrinsicIsEmptyOrLength, 61 kIntrinsicIndexOf, 62 kIntrinsicNewStringFromBytes, 63 kIntrinsicNewStringFromChars, 64 kIntrinsicNewStringFromString, 65 kIntrinsicCurrentThread, 66 kIntrinsicPeek, 67 kIntrinsicPoke, 68 kIntrinsicCas, 69 kIntrinsicUnsafeGet, 70 kIntrinsicUnsafePut, 71 kIntrinsicSystemArrayCopyCharArray, 72 73 kInlineOpNop, 74 kInlineOpReturnArg, 75 kInlineOpNonWideConst, 76 kInlineOpIGet, 77 kInlineOpIPut, 78 kInlineStringInit, 79 }; 80 std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs); 81 82 enum InlineMethodFlags : uint16_t { 83 kNoInlineMethodFlags = 0x0000, 84 kInlineIntrinsic = 0x0001, 85 kInlineSpecial = 0x0002, 86 }; 87 88 // IntrinsicFlags are stored in InlineMethod::d::raw_data 89 enum IntrinsicFlags { 90 kIntrinsicFlagNone = 0, 91 92 // kIntrinsicMinMaxInt 93 kIntrinsicFlagMax = kIntrinsicFlagNone, 94 kIntrinsicFlagMin = 1, 95 96 // kIntrinsicIsEmptyOrLength 97 kIntrinsicFlagLength = kIntrinsicFlagNone, 98 kIntrinsicFlagIsEmpty = kIntrinsicFlagMin, 99 100 // kIntrinsicIndexOf 101 kIntrinsicFlagBase0 = kIntrinsicFlagMin, 102 103 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas 104 kIntrinsicFlagIsLong = kIntrinsicFlagMin, 105 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut 106 kIntrinsicFlagIsVolatile = 2, 107 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas 108 kIntrinsicFlagIsObject = 4, 109 // kIntrinsicUnsafePut 110 kIntrinsicFlagIsOrdered = 8, 111 112 // kIntrinsicDoubleCvt, kIntrinsicFloatCvt. 113 kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin, 114 }; 115 116 struct InlineIGetIPutData { 117 // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration. 118 uint16_t op_variant : 3; 119 uint16_t method_is_static : 1; 120 uint16_t object_arg : 4; 121 uint16_t src_arg : 4; // iput only 122 uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void. 123 uint16_t field_idx; 124 uint32_t is_volatile : 1; 125 uint32_t field_offset : 31; 126 }; 127 static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData"); 128 129 struct InlineReturnArgData { 130 uint16_t arg; 131 uint16_t is_wide : 1; 132 uint16_t is_object : 1; 133 uint16_t reserved : 14; 134 uint32_t reserved2; 135 }; 136 static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t), 137 "Invalid size of InlineReturnArgData"); 138 139 struct InlineMethod { 140 InlineMethodOpcode opcode; 141 InlineMethodFlags flags; 142 union { 143 uint64_t data; 144 InlineIGetIPutData ifield_data; 145 InlineReturnArgData return_data; 146 } d; 147 }; 148 149 class InlineMethodAnalyser { 150 public: 151 /** 152 * Analyse method code to determine if the method is a candidate for inlining. 153 * If it is, record the inlining data. 154 * 155 * @param verifier the method verifier holding data about the method to analyse. 156 * @param method placeholder for the inline method data. 157 * @return true if the method is a candidate for inlining, false otherwise. 158 */ 159 static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method) 160 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 161 IsInstructionIGet(Instruction::Code opcode)162 static constexpr bool IsInstructionIGet(Instruction::Code opcode) { 163 return Instruction::IGET <= opcode && opcode <= Instruction::IGET_SHORT; 164 } 165 IsInstructionIPut(Instruction::Code opcode)166 static constexpr bool IsInstructionIPut(Instruction::Code opcode) { 167 return Instruction::IPUT <= opcode && opcode <= Instruction::IPUT_SHORT; 168 } 169 IGetVariant(Instruction::Code opcode)170 static constexpr uint16_t IGetVariant(Instruction::Code opcode) { 171 return opcode - Instruction::IGET; 172 } 173 IPutVariant(Instruction::Code opcode)174 static constexpr uint16_t IPutVariant(Instruction::Code opcode) { 175 return opcode - Instruction::IPUT; 176 } 177 178 // Determines whether the method is a synthetic accessor (method name starts with "access$"). 179 static bool IsSyntheticAccessor(MethodReference ref); 180 181 private: 182 static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result); 183 static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result); 184 static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result) 185 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 186 static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result) 187 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 188 189 // Can we fast path instance field access in a verified accessor? 190 // If yes, computes field's offset and volatility and whether the method is static or not. 191 static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put, 192 verifier::MethodVerifier* verifier, 193 InlineIGetIPutData* result) 194 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 195 }; 196 197 } // namespace art 198 199 #endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_ 200