1 /* 2 * Copyright (C) 2013 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_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ 18 #define ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ 19 20 #include <stdint.h> 21 #include "base/mutex.h" 22 #include "base/macros.h" 23 #include "safe_map.h" 24 #include "dex/compiler_enums.h" 25 #include "dex_file.h" 26 #include "quick/inline_method_analyser.h" 27 28 namespace art { 29 30 namespace verifier { 31 class MethodVerifier; 32 } // namespace verifier 33 34 struct BasicBlock; 35 struct CallInfo; 36 struct MIR; 37 class MIRGraph; 38 class Mir2Lir; 39 40 /** 41 * Handles inlining of methods from a particular DexFile. 42 * 43 * Intrinsics are a special case of inline methods. The DexFile indices for 44 * all the supported intrinsic methods are looked up once by the FindIntrinsics 45 * function and cached by this class for quick lookup by the method index. 46 * 47 * TODO: Detect short methods (at least getters, setters and empty functions) 48 * from the verifier and mark them for inlining. Inline these methods early 49 * during compilation to allow further optimizations. Similarly, provide 50 * additional information about intrinsics to the early phases of compilation. 51 */ 52 class DexFileMethodInliner { 53 public: 54 DexFileMethodInliner(); 55 ~DexFileMethodInliner(); 56 57 /** 58 * Analyse method code to determine if the method is a candidate for inlining. 59 * If it is, record its data for later. 60 * 61 * @param verifier the method verifier holding data about the method to analyse. 62 * @return true if the method is a candidate for inlining, false otherwise. 63 */ 64 bool AnalyseMethodCode(verifier::MethodVerifier* verifier) 65 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_); 66 67 /** 68 * Check whether a particular method index corresponds to an intrinsic function. 69 */ 70 bool IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) LOCKS_EXCLUDED(lock_); 71 72 /** 73 * Generate code for an intrinsic function invocation. 74 */ 75 bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) LOCKS_EXCLUDED(lock_); 76 77 /** 78 * Check whether a particular method index corresponds to a special function. 79 */ 80 bool IsSpecial(uint32_t method_index) LOCKS_EXCLUDED(lock_); 81 82 /** 83 * Generate code for a special function. 84 */ 85 bool GenSpecial(Mir2Lir* backend, uint32_t method_idx) LOCKS_EXCLUDED(lock_); 86 87 /** 88 * Try to inline an invoke. 89 */ 90 bool GenInline(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, uint32_t method_idx) 91 LOCKS_EXCLUDED(lock_); 92 93 /** 94 * To avoid multiple lookups of a class by its descriptor, we cache its 95 * type index in the IndexCache. These are the indexes into the IndexCache 96 * class_indexes array. 97 */ 98 enum ClassCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 99 kClassCacheFirst = 0, 100 kClassCacheBoolean = kClassCacheFirst, 101 kClassCacheByte, 102 kClassCacheChar, 103 kClassCacheShort, 104 kClassCacheInt, 105 kClassCacheLong, 106 kClassCacheFloat, 107 kClassCacheDouble, 108 kClassCacheVoid, 109 kClassCacheJavaLangObject, 110 kClassCacheJavaLangRefReference, 111 kClassCacheJavaLangString, 112 kClassCacheJavaLangDouble, 113 kClassCacheJavaLangFloat, 114 kClassCacheJavaLangInteger, 115 kClassCacheJavaLangLong, 116 kClassCacheJavaLangShort, 117 kClassCacheJavaLangMath, 118 kClassCacheJavaLangStrictMath, 119 kClassCacheJavaLangThread, 120 kClassCacheLibcoreIoMemory, 121 kClassCacheSunMiscUnsafe, 122 kClassCacheJavaLangSystem, 123 kClassCacheJavaLangCharArray, 124 kClassCacheLast 125 }; 126 127 /** 128 * To avoid multiple lookups of a method name string, we cache its string 129 * index in the IndexCache. These are the indexes into the IndexCache 130 * name_indexes array. 131 */ 132 enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 133 kNameCacheFirst = 0, 134 kNameCacheReverse = kNameCacheFirst, 135 kNameCacheReverseBytes, 136 kNameCacheDoubleToRawLongBits, 137 kNameCacheLongBitsToDouble, 138 kNameCacheFloatToRawIntBits, 139 kNameCacheIntBitsToFloat, 140 kNameCacheAbs, 141 kNameCacheMax, 142 kNameCacheMin, 143 kNameCacheSqrt, 144 kNameCacheCeil, 145 kNameCacheFloor, 146 kNameCacheRint, 147 kNameCacheRound, 148 kNameCacheReferenceGetReferent, 149 kNameCacheCharAt, 150 kNameCacheCompareTo, 151 kNameCacheIsEmpty, 152 kNameCacheIndexOf, 153 kNameCacheLength, 154 kNameCacheCurrentThread, 155 kNameCachePeekByte, 156 kNameCachePeekIntNative, 157 kNameCachePeekLongNative, 158 kNameCachePeekShortNative, 159 kNameCachePokeByte, 160 kNameCachePokeIntNative, 161 kNameCachePokeLongNative, 162 kNameCachePokeShortNative, 163 kNameCacheCompareAndSwapInt, 164 kNameCacheCompareAndSwapLong, 165 kNameCacheCompareAndSwapObject, 166 kNameCacheGetInt, 167 kNameCacheGetIntVolatile, 168 kNameCachePutInt, 169 kNameCachePutIntVolatile, 170 kNameCachePutOrderedInt, 171 kNameCacheGetLong, 172 kNameCacheGetLongVolatile, 173 kNameCachePutLong, 174 kNameCachePutLongVolatile, 175 kNameCachePutOrderedLong, 176 kNameCacheGetObject, 177 kNameCacheGetObjectVolatile, 178 kNameCachePutObject, 179 kNameCachePutObjectVolatile, 180 kNameCachePutOrderedObject, 181 kNameCacheArrayCopy, 182 kNameCacheLast 183 }; 184 185 /** 186 * To avoid multiple lookups of a method signature, we cache its proto 187 * index in the IndexCache. These are the indexes into the IndexCache 188 * proto_indexes array. 189 */ 190 enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 191 kProtoCacheFirst = 0, 192 kProtoCacheI_I = kProtoCacheFirst, 193 kProtoCacheJ_J, 194 kProtoCacheS_S, 195 kProtoCacheD_D, 196 kProtoCacheDD_D, 197 kProtoCacheF_F, 198 kProtoCacheFF_F, 199 kProtoCacheD_J, 200 kProtoCacheJ_D, 201 kProtoCacheF_I, 202 kProtoCacheI_F, 203 kProtoCacheII_I, 204 kProtoCacheI_C, 205 kProtoCacheString_I, 206 kProtoCache_Z, 207 kProtoCache_I, 208 kProtoCache_Object, 209 kProtoCache_Thread, 210 kProtoCacheJ_B, 211 kProtoCacheJ_I, 212 kProtoCacheJ_S, 213 kProtoCacheJB_V, 214 kProtoCacheJI_V, 215 kProtoCacheJJ_J, 216 kProtoCacheJJ_V, 217 kProtoCacheJS_V, 218 kProtoCacheObjectJII_Z, 219 kProtoCacheObjectJJJ_Z, 220 kProtoCacheObjectJObjectObject_Z, 221 kProtoCacheObjectJ_I, 222 kProtoCacheObjectJI_V, 223 kProtoCacheObjectJ_J, 224 kProtoCacheObjectJJ_V, 225 kProtoCacheObjectJ_Object, 226 kProtoCacheObjectJObject_V, 227 kProtoCacheCharArrayICharArrayII_V, 228 kProtoCacheLast 229 }; 230 231 private: 232 /** 233 * The maximum number of method parameters we support in the ProtoDef. 234 */ 235 static constexpr uint32_t kProtoMaxParams = 6; 236 237 /** 238 * The method signature (proto) definition using cached class indexes. 239 * The return_type and params are used with the IndexCache to look up 240 * appropriate class indexes to be passed to DexFile::FindProtoId(). 241 */ 242 struct ProtoDef { 243 ClassCacheIndex return_type; 244 uint8_t param_count; 245 ClassCacheIndex params[kProtoMaxParams]; 246 }; 247 248 /** 249 * The method definition using cached class, name and proto indexes. 250 * The class index, method name index and proto index are used with 251 * IndexCache to look up appropriate parameters for DexFile::FindMethodId(). 252 */ 253 struct MethodDef { 254 ClassCacheIndex declaring_class; 255 NameCacheIndex name; 256 ProtoCacheIndex proto; 257 }; 258 259 /** 260 * The definition of an intrinsic function binds the method definition 261 * to an Intrinsic. 262 */ 263 struct IntrinsicDef { 264 MethodDef method_def; 265 InlineMethod intrinsic; 266 }; 267 268 /** 269 * Cache for class, method name and method signature indexes used during 270 * intrinsic function lookup to avoid multiple lookups of the same items. 271 * 272 * Many classes have multiple intrinsics and/or they are used in multiple 273 * method signatures and we want to avoid repeated lookups since they are 274 * not exactly cheap. The method names and method signatures are sometimes 275 * reused and therefore cached as well. 276 */ 277 struct IndexCache { 278 IndexCache(); 279 280 uint32_t class_indexes[kClassCacheLast - kClassCacheFirst]; 281 uint32_t name_indexes[kNameCacheLast - kNameCacheFirst]; 282 uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst]; 283 }; 284 285 static const char* const kClassCacheNames[]; 286 static const char* const kNameCacheNames[]; 287 static const ProtoDef kProtoCacheDefs[]; 288 static const IntrinsicDef kIntrinsicMethods[]; 289 290 static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1); 291 static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2); 292 293 static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache, 294 ClassCacheIndex index); 295 static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache, 296 NameCacheIndex index); 297 static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache, 298 ProtoCacheIndex index); 299 static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache, 300 const MethodDef& method_def); 301 302 /** 303 * Find all known intrinsic methods in the dex_file and cache their indices. 304 * 305 * Only DexFileToMethodInlinerMap may call this function to initialize the inliner. 306 */ 307 void FindIntrinsics(const DexFile* dex_file) EXCLUSIVE_LOCKS_REQUIRED(lock_); 308 309 friend class DexFileToMethodInlinerMap; 310 311 bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_); 312 313 static bool GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 314 MIR* move_result, const InlineMethod& method); 315 static bool GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 316 MIR* move_result, const InlineMethod& method); 317 static bool GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 318 MIR* move_result, const InlineMethod& method, uint32_t method_idx); 319 static bool GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 320 MIR* move_result, const InlineMethod& method, uint32_t method_idx); 321 322 ReaderWriterMutex lock_; 323 /* 324 * Maps method indexes (for the particular DexFile) to Intrinsic defintions. 325 */ 326 SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_); 327 const DexFile* dex_file_; 328 329 DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner); 330 }; 331 332 } // namespace art 333 334 #endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ 335