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