dex_file_method_inliner.h revision dbb17e378b538133750e56375bbdbb217db7b248
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 "locks.h" 27 28namespace art { 29 30class CallInfo; 31class Mir2Lir; 32 33enum InlineMethodOpcode : uint16_t { 34 kIntrinsicDoubleCvt, 35 kIntrinsicFloatCvt, 36 kIntrinsicReverseBytes, 37 kIntrinsicAbsInt, 38 kIntrinsicAbsLong, 39 kIntrinsicAbsFloat, 40 kIntrinsicAbsDouble, 41 kIntrinsicMinMaxInt, 42 kIntrinsicSqrt, 43 kIntrinsicCharAt, 44 kIntrinsicCompareTo, 45 kIntrinsicIsEmptyOrLength, 46 kIntrinsicIndexOf, 47 kIntrinsicCurrentThread, 48 kIntrinsicPeek, 49 kIntrinsicPoke, 50 kIntrinsicCas, 51 kIntrinsicUnsafeGet, 52 kIntrinsicUnsafePut, 53 54 kInlineOpNop, 55 kInlineOpReturnArg, 56 kInlineOpConst, 57 kInlineOpIGet, 58 kInlineOpIPut, 59}; 60 61enum InlineMethodFlags : uint16_t { 62 kNoInlineMethodFlags = 0x0000, 63 kInlineIntrinsic = 0x0001, 64 kInlineSpecial = 0x0002, 65}; 66 67struct InlineMethod { 68 InlineMethodOpcode opcode; 69 InlineMethodFlags flags; 70 uint32_t data; 71}; 72 73// IntrinsicFlags are stored in InlineMethod::data 74enum IntrinsicFlags { 75 kIntrinsicFlagNone = 0, 76 77 // kIntrinsicMinMaxInt 78 kIntrinsicFlagMax = kIntrinsicFlagNone, 79 kIntrinsicFlagMin = 1, 80 81 // kIntrinsicIsEmptyOrLength 82 kIntrinsicFlagLength = kIntrinsicFlagNone, 83 kIntrinsicFlagIsEmpty = 1, 84 85 // kIntrinsicIndexOf 86 kIntrinsicFlagBase0 = 1, 87 88 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas 89 kIntrinsicFlagIsLong = 1, 90 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut 91 kIntrinsicFlagIsVolatile = 2, 92 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas 93 kIntrinsicFlagIsObject = 4, 94 // kIntrinsicUnsafePut 95 kIntrinsicFlagIsOrdered = 8, 96}; 97 98// Check that OpSize fits into 3 bits (at least the values the inliner uses). 99COMPILE_ASSERT(kWord < 8 && kLong < 8 && kSingle < 8 && kDouble < 8 && kUnsignedHalf < 8 && 100 kSignedHalf < 8 && kUnsignedByte < 8 && kSignedByte < 8, op_size_field_too_narrow); 101 102union InlineIGetIPutData { 103 uint32_t data; 104 struct { 105 uint16_t field; 106 uint32_t op_size : 3; // OpSize 107 uint32_t is_object : 1; 108 uint32_t object_arg : 4; 109 uint32_t src_arg : 4; // iput only 110 uint32_t reserved : 4; 111 } d; 112}; 113COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint32_t), InvalidSizeOfInlineIGetIPutData); 114 115union InlineReturnArgData { 116 uint32_t data; 117 struct { 118 uint16_t arg; 119 uint32_t op_size : 3; // OpSize 120 uint32_t reserved : 13; 121 } d; 122}; 123COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint32_t), InvalidSizeOfInlineReturnArgData); 124 125/** 126 * Handles inlining of methods from a particular DexFile. 127 * 128 * Intrinsics are a special case of inline methods. The DexFile indices for 129 * all the supported intrinsic methods are looked up once by the FindIntrinsics 130 * function and cached by this class for quick lookup by the method index. 131 * 132 * TODO: Detect short methods (at least getters, setters and empty functions) 133 * from the verifier and mark them for inlining. Inline these methods early 134 * during compilation to allow further optimizations. Similarly, provide 135 * additional information about intrinsics to the early phases of compilation. 136 */ 137class DexFileMethodInliner { 138 public: 139 DexFileMethodInliner(); 140 ~DexFileMethodInliner(); 141 142 /** 143 * Analyse method code to determine if the method is a candidate for inlining. 144 * If it is, record its data for later. 145 * 146 * @param method_idx the index of the inlining candidate. 147 * @param code_item a previously verified code item of the method. 148 */ 149 bool AnalyseMethodCode(uint32_t method_idx, 150 const DexFile::CodeItem* code_item) LOCKS_EXCLUDED(lock_); 151 152 /** 153 * Check whether a particular method index corresponds to an intrinsic function. 154 */ 155 bool IsIntrinsic(uint32_t method_index) LOCKS_EXCLUDED(lock_); 156 157 /** 158 * Generate code for an intrinsic function invocation. 159 */ 160 bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) LOCKS_EXCLUDED(lock_); 161 162 /** 163 * Check whether a particular method index corresponds to a special function. 164 */ 165 bool IsSpecial(uint32_t method_index) LOCKS_EXCLUDED(lock_); 166 167 /** 168 * Generate code for a special function. 169 */ 170 bool GenSpecial(Mir2Lir* backend, uint32_t method_idx); 171 172 private: 173 /** 174 * To avoid multiple lookups of a class by its descriptor, we cache its 175 * type index in the IndexCache. These are the indexes into the IndexCache 176 * class_indexes array. 177 */ 178 enum ClassCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 179 kClassCacheFirst = 0, 180 kClassCacheBoolean = kClassCacheFirst, 181 kClassCacheByte, 182 kClassCacheChar, 183 kClassCacheShort, 184 kClassCacheInt, 185 kClassCacheLong, 186 kClassCacheFloat, 187 kClassCacheDouble, 188 kClassCacheVoid, 189 kClassCacheJavaLangObject, 190 kClassCacheJavaLangString, 191 kClassCacheJavaLangDouble, 192 kClassCacheJavaLangFloat, 193 kClassCacheJavaLangInteger, 194 kClassCacheJavaLangLong, 195 kClassCacheJavaLangShort, 196 kClassCacheJavaLangMath, 197 kClassCacheJavaLangStrictMath, 198 kClassCacheJavaLangThread, 199 kClassCacheLibcoreIoMemory, 200 kClassCacheSunMiscUnsafe, 201 kClassCacheLast 202 }; 203 204 /** 205 * To avoid multiple lookups of a method name string, we cache its string 206 * index in the IndexCache. These are the indexes into the IndexCache 207 * name_indexes array. 208 */ 209 enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 210 kNameCacheFirst = 0, 211 kNameCacheReverseBytes = kNameCacheFirst, 212 kNameCacheDoubleToRawLongBits, 213 kNameCacheLongBitsToDouble, 214 kNameCacheFloatToRawIntBits, 215 kNameCacheIntBitsToFloat, 216 kNameCacheAbs, 217 kNameCacheMax, 218 kNameCacheMin, 219 kNameCacheSqrt, 220 kNameCacheCharAt, 221 kNameCacheCompareTo, 222 kNameCacheIsEmpty, 223 kNameCacheIndexOf, 224 kNameCacheLength, 225 kNameCacheCurrentThread, 226 kNameCachePeekByte, 227 kNameCachePeekIntNative, 228 kNameCachePeekLongNative, 229 kNameCachePeekShortNative, 230 kNameCachePokeByte, 231 kNameCachePokeIntNative, 232 kNameCachePokeLongNative, 233 kNameCachePokeShortNative, 234 kNameCacheCompareAndSwapInt, 235 kNameCacheCompareAndSwapLong, 236 kNameCacheCompareAndSwapObject, 237 kNameCacheGetInt, 238 kNameCacheGetIntVolatile, 239 kNameCachePutInt, 240 kNameCachePutIntVolatile, 241 kNameCachePutOrderedInt, 242 kNameCacheGetLong, 243 kNameCacheGetLongVolatile, 244 kNameCachePutLong, 245 kNameCachePutLongVolatile, 246 kNameCachePutOrderedLong, 247 kNameCacheGetObject, 248 kNameCacheGetObjectVolatile, 249 kNameCachePutObject, 250 kNameCachePutObjectVolatile, 251 kNameCachePutOrderedObject, 252 kNameCacheLast 253 }; 254 255 /** 256 * To avoid multiple lookups of a method signature, we cache its proto 257 * index in the IndexCache. These are the indexes into the IndexCache 258 * proto_indexes array. 259 */ 260 enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 261 kProtoCacheFirst = 0, 262 kProtoCacheI_I = kProtoCacheFirst, 263 kProtoCacheJ_J, 264 kProtoCacheS_S, 265 kProtoCacheD_D, 266 kProtoCacheF_F, 267 kProtoCacheD_J, 268 kProtoCacheJ_D, 269 kProtoCacheF_I, 270 kProtoCacheI_F, 271 kProtoCacheII_I, 272 kProtoCacheI_C, 273 kProtoCacheString_I, 274 kProtoCache_Z, 275 kProtoCache_I, 276 kProtoCache_Thread, 277 kProtoCacheJ_B, 278 kProtoCacheJ_I, 279 kProtoCacheJ_S, 280 kProtoCacheJB_V, 281 kProtoCacheJI_V, 282 kProtoCacheJJ_V, 283 kProtoCacheJS_V, 284 kProtoCacheObjectJII_Z, 285 kProtoCacheObjectJJJ_Z, 286 kProtoCacheObjectJObjectObject_Z, 287 kProtoCacheObjectJ_I, 288 kProtoCacheObjectJI_V, 289 kProtoCacheObjectJ_J, 290 kProtoCacheObjectJJ_V, 291 kProtoCacheObjectJ_Object, 292 kProtoCacheObjectJObject_V, 293 kProtoCacheLast 294 }; 295 296 /** 297 * The maximum number of method parameters we support in the ProtoDef. 298 */ 299 static constexpr uint32_t kProtoMaxParams = 6; 300 301 /** 302 * The method signature (proto) definition using cached class indexes. 303 * The return_type and params are used with the IndexCache to look up 304 * appropriate class indexes to be passed to DexFile::FindProtoId(). 305 */ 306 struct ProtoDef { 307 ClassCacheIndex return_type; 308 uint8_t param_count; 309 ClassCacheIndex params[kProtoMaxParams]; 310 }; 311 312 /** 313 * The method definition using cached class, name and proto indexes. 314 * The class index, method name index and proto index are used with 315 * IndexCache to look up appropriate parameters for DexFile::FindMethodId(). 316 */ 317 struct MethodDef { 318 ClassCacheIndex declaring_class; 319 NameCacheIndex name; 320 ProtoCacheIndex proto; 321 }; 322 323 /** 324 * The definition of an intrinsic function binds the method definition 325 * to an Intrinsic. 326 */ 327 struct IntrinsicDef { 328 MethodDef method_def; 329 InlineMethod intrinsic; 330 }; 331 332 /** 333 * Cache for class, method name and method signature indexes used during 334 * intrinsic function lookup to avoid multiple lookups of the same items. 335 * 336 * Many classes have multiple intrinsics and/or they are used in multiple 337 * method signatures and we want to avoid repeated lookups since they are 338 * not exactly cheap. The method names and method signatures are sometimes 339 * reused and therefore cached as well. 340 */ 341 struct IndexCache { 342 IndexCache(); 343 344 uint32_t class_indexes[kClassCacheLast - kClassCacheFirst]; 345 uint32_t name_indexes[kNameCacheLast - kNameCacheFirst]; 346 uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst]; 347 }; 348 349 static const char* const kClassCacheNames[]; 350 static const char* const kNameCacheNames[]; 351 static const ProtoDef kProtoCacheDefs[]; 352 static const IntrinsicDef kIntrinsicMethods[]; 353 354 static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1); 355 static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2); 356 357 static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache, 358 ClassCacheIndex index); 359 static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache, 360 NameCacheIndex index); 361 static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache, 362 ProtoCacheIndex index); 363 static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache, 364 const MethodDef& method_def); 365 366 /** 367 * Find all known intrinsic methods in the dex_file and cache their indices. 368 * 369 * Only DexFileToMethodInlinerMap may call this function to initialize the inliner. 370 */ 371 void FindIntrinsics(const DexFile* dex_file) EXCLUSIVE_LOCKS_REQUIRED(lock_); 372 373 friend class DexFileToMethodInlinerMap; 374 375 bool AddInlineMethod(int32_t method_idx, InlineMethodOpcode opcode, 376 InlineMethodFlags flags, uint32_t data) LOCKS_EXCLUDED(lock_); 377 378 bool AnalyseReturnMethod(int32_t method_idx, const DexFile::CodeItem* code_item, 379 OpSize size) LOCKS_EXCLUDED(lock_); 380 bool AnalyseConstMethod(int32_t method_idx, const DexFile::CodeItem* code_item) 381 LOCKS_EXCLUDED(lock_); 382 bool AnalyseIGetMethod(int32_t method_idx, const DexFile::CodeItem* code_item, 383 OpSize size, bool is_object) LOCKS_EXCLUDED(lock_); 384 bool AnalyseIPutMethod(int32_t method_idx, const DexFile::CodeItem* code_item, 385 OpSize size, bool is_object) LOCKS_EXCLUDED(lock_); 386 387 ReaderWriterMutex lock_; 388 /* 389 * Maps method indexes (for the particular DexFile) to Intrinsic defintions. 390 */ 391 SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_); 392 const DexFile* dex_file_; 393 394 DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner); 395}; 396 397} // namespace art 398 399#endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ 400