dex_file_method_inliner.cc revision 3bc01748ef1c3e43361bdf520947a9d656658bf8
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#include <algorithm> 18#include "base/macros.h" 19#include "base/mutex.h" 20#include "base/mutex-inl.h" 21#include "locks.h" 22#include "thread.h" 23#include "thread-inl.h" 24#include "dex/mir_graph.h" 25#include "dex_instruction.h" 26#include "dex_instruction-inl.h" 27#include "verifier/method_verifier.h" 28#include "verifier/method_verifier-inl.h" 29 30#include "dex_file_method_inliner.h" 31 32namespace art { 33 34namespace { // anonymous namespace 35 36constexpr uint8_t kIGetIPutOpSizes[] = { 37 kWord, // IGET, IPUT 38 kLong, // IGET_WIDE, IPUT_WIDE 39 kWord, // IGET_OBJECT, IPUT_OBJECT 40 kSignedByte, // IGET_BOOLEAN, IPUT_BOOLEAN 41 kSignedByte, // IGET_BYTE, IPUT_BYTE 42 kUnsignedHalf, // IGET_CHAR, IPUT_CHAR 43 kSignedHalf, // IGET_SHORT, IPUT_SHORT 44}; 45 46} // anonymous namespace 47 48const uint32_t DexFileMethodInliner::kIndexUnresolved; 49const char* const DexFileMethodInliner::kClassCacheNames[] = { 50 "Z", // kClassCacheBoolean 51 "B", // kClassCacheByte 52 "C", // kClassCacheChar 53 "S", // kClassCacheShort 54 "I", // kClassCacheInt 55 "J", // kClassCacheLong 56 "F", // kClassCacheFloat 57 "D", // kClassCacheDouble 58 "V", // kClassCacheVoid 59 "Ljava/lang/Object;", // kClassCacheJavaLangObject 60 "Ljava/lang/String;", // kClassCacheJavaLangString 61 "Ljava/lang/Double;", // kClassCacheJavaLangDouble 62 "Ljava/lang/Float;", // kClassCacheJavaLangFloat 63 "Ljava/lang/Integer;", // kClassCacheJavaLangInteger 64 "Ljava/lang/Long;", // kClassCacheJavaLangLong 65 "Ljava/lang/Short;", // kClassCacheJavaLangShort 66 "Ljava/lang/Math;", // kClassCacheJavaLangMath 67 "Ljava/lang/StrictMath;", // kClassCacheJavaLangStrictMath 68 "Ljava/lang/Thread;", // kClassCacheJavaLangThread 69 "Llibcore/io/Memory;", // kClassCacheLibcoreIoMemory 70 "Lsun/misc/Unsafe;", // kClassCacheSunMiscUnsafe 71}; 72 73const char* const DexFileMethodInliner::kNameCacheNames[] = { 74 "reverseBytes", // kNameCacheReverseBytes 75 "doubleToRawLongBits", // kNameCacheDoubleToRawLongBits 76 "longBitsToDouble", // kNameCacheLongBitsToDouble 77 "floatToRawIntBits", // kNameCacheFloatToRawIntBits 78 "intBitsToFloat", // kNameCacheIntBitsToFloat 79 "abs", // kNameCacheAbs 80 "max", // kNameCacheMax 81 "min", // kNameCacheMin 82 "sqrt", // kNameCacheSqrt 83 "charAt", // kNameCacheCharAt 84 "compareTo", // kNameCacheCompareTo 85 "isEmpty", // kNameCacheIsEmpty 86 "indexOf", // kNameCacheIndexOf 87 "length", // kNameCacheLength 88 "currentThread", // kNameCacheCurrentThread 89 "peekByte", // kNameCachePeekByte 90 "peekIntNative", // kNameCachePeekIntNative 91 "peekLongNative", // kNameCachePeekLongNative 92 "peekShortNative", // kNameCachePeekShortNative 93 "pokeByte", // kNameCachePokeByte 94 "pokeIntNative", // kNameCachePokeIntNative 95 "pokeLongNative", // kNameCachePokeLongNative 96 "pokeShortNative", // kNameCachePokeShortNative 97 "compareAndSwapInt", // kNameCacheCompareAndSwapInt 98 "compareAndSwapLong", // kNameCacheCompareAndSwapLong 99 "compareAndSwapObject", // kNameCacheCompareAndSwapObject 100 "getInt", // kNameCacheGetInt 101 "getIntVolatile", // kNameCacheGetIntVolatile 102 "putInt", // kNameCachePutInt 103 "putIntVolatile", // kNameCachePutIntVolatile 104 "putOrderedInt", // kNameCachePutOrderedInt 105 "getLong", // kNameCacheGetLong 106 "getLongVolatile", // kNameCacheGetLongVolatile 107 "putLong", // kNameCachePutLong 108 "putLongVolatile", // kNameCachePutLongVolatile 109 "putOrderedLong", // kNameCachePutOrderedLong 110 "getObject", // kNameCacheGetObject 111 "getObjectVolatile", // kNameCacheGetObjectVolatile 112 "putObject", // kNameCachePutObject 113 "putObjectVolatile", // kNameCachePutObjectVolatile 114 "putOrderedObject", // kNameCachePutOrderedObject 115}; 116 117const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { 118 // kProtoCacheI_I 119 { kClassCacheInt, 1, { kClassCacheInt } }, 120 // kProtoCacheJ_J 121 { kClassCacheLong, 1, { kClassCacheLong } }, 122 // kProtoCacheS_S 123 { kClassCacheShort, 1, { kClassCacheShort } }, 124 // kProtoCacheD_D 125 { kClassCacheDouble, 1, { kClassCacheDouble } }, 126 // kProtoCacheF_F 127 { kClassCacheFloat, 1, { kClassCacheFloat } }, 128 // kProtoCacheD_J 129 { kClassCacheLong, 1, { kClassCacheDouble } }, 130 // kProtoCacheJ_D 131 { kClassCacheDouble, 1, { kClassCacheLong } }, 132 // kProtoCacheF_I 133 { kClassCacheInt, 1, { kClassCacheFloat } }, 134 // kProtoCacheI_F 135 { kClassCacheFloat, 1, { kClassCacheInt } }, 136 // kProtoCacheII_I 137 { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } }, 138 // kProtoCacheI_C 139 { kClassCacheChar, 1, { kClassCacheInt } }, 140 // kProtoCacheString_I 141 { kClassCacheInt, 1, { kClassCacheJavaLangString } }, 142 // kProtoCache_Z 143 { kClassCacheBoolean, 0, { } }, 144 // kProtoCache_I 145 { kClassCacheInt, 0, { } }, 146 // kProtoCache_Thread 147 { kClassCacheJavaLangThread, 0, { } }, 148 // kProtoCacheJ_B 149 { kClassCacheByte, 1, { kClassCacheLong } }, 150 // kProtoCacheJ_I 151 { kClassCacheInt, 1, { kClassCacheLong } }, 152 // kProtoCacheJ_S 153 { kClassCacheShort, 1, { kClassCacheLong } }, 154 // kProtoCacheJB_V 155 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } }, 156 // kProtoCacheJI_V 157 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } }, 158 // kProtoCacheJJ_V 159 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } }, 160 // kProtoCacheJS_V 161 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } }, 162 // kProtoCacheObjectJII_Z 163 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, 164 kClassCacheInt, kClassCacheInt } }, 165 // kProtoCacheObjectJJJ_Z 166 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, 167 kClassCacheLong, kClassCacheLong } }, 168 // kProtoCacheObjectJObjectObject_Z 169 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, 170 kClassCacheJavaLangObject, kClassCacheJavaLangObject } }, 171 // kProtoCacheObjectJ_I 172 { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, 173 // kProtoCacheObjectJI_V 174 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } }, 175 // kProtoCacheObjectJ_J 176 { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, 177 // kProtoCacheObjectJJ_V 178 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } }, 179 // kProtoCacheObjectJ_Object 180 { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, 181 // kProtoCacheObjectJObject_V 182 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, 183 kClassCacheJavaLangObject } }, 184}; 185 186const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = { 187#define INTRINSIC(c, n, p, o, d) \ 188 { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } } 189 190 INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0), 191 INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0), 192 INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), 193 INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0), 194 195 INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord), 196 INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong), 197 INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf), 198 199 INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), 200 INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), 201 INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0), 202 INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0), 203 INTRINSIC(JavaLangMath, Abs, F_F, kIntrinsicAbsFloat, 0), 204 INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0), 205 INTRINSIC(JavaLangMath, Abs, D_D, kIntrinsicAbsDouble, 0), 206 INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0), 207 INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), 208 INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), 209 INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), 210 INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), 211 INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), 212 INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), 213 214 INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), 215 INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), 216 INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), 217 INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone), 218 INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0), 219 INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength), 220 221 INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0), 222 223 INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte), 224 INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord), 225 INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong), 226 INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf), 227 INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte), 228 INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord), 229 INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong), 230 INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf), 231 232 INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas, 233 kIntrinsicFlagNone), 234 INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas, 235 kIntrinsicFlagIsLong), 236 INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas, 237 kIntrinsicFlagIsObject), 238 239#define UNSAFE_GET_PUT(type, code, type_flags) \ 240 INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ 241 type_flags & ~kIntrinsicFlagIsObject), \ 242 INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ 243 (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \ 244 INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ 245 type_flags), \ 246 INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ 247 type_flags | kIntrinsicFlagIsVolatile), \ 248 INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ 249 type_flags | kIntrinsicFlagIsOrdered) 250 251 UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone), 252 UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong), 253 UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject), 254#undef UNSAFE_GET_PUT 255 256#undef INTRINSIC 257}; 258 259DexFileMethodInliner::DexFileMethodInliner() 260 : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock), 261 dex_file_(NULL) { 262 COMPILE_ASSERT(kClassCacheFirst == 0, kClassCacheFirst_not_0); 263 COMPILE_ASSERT(arraysize(kClassCacheNames) == kClassCacheLast, bad_arraysize_kClassCacheNames); 264 COMPILE_ASSERT(kNameCacheFirst == 0, kNameCacheFirst_not_0); 265 COMPILE_ASSERT(arraysize(kNameCacheNames) == kNameCacheLast, bad_arraysize_kNameCacheNames); 266 COMPILE_ASSERT(kProtoCacheFirst == 0, kProtoCacheFirst_not_0); 267 COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames); 268} 269 270DexFileMethodInliner::~DexFileMethodInliner() { 271} 272 273bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) { 274 // We currently support only plain return or 2-instruction methods. 275 276 const DexFile::CodeItem* code_item = verifier->CodeItem(); 277 DCHECK_NE(code_item->insns_size_in_code_units_, 0u); 278 const Instruction* instruction = Instruction::At(code_item->insns_); 279 Instruction::Code opcode = instruction->Opcode(); 280 281 InlineMethod method; 282 bool success; 283 switch (opcode) { 284 case Instruction::RETURN_VOID: 285 method.opcode = kInlineOpNop; 286 method.flags = kInlineSpecial; 287 method.d.data = 0u; 288 success = true; 289 break; 290 case Instruction::RETURN: 291 case Instruction::RETURN_OBJECT: 292 case Instruction::RETURN_WIDE: 293 success = AnalyseReturnMethod(code_item, &method); 294 break; 295 case Instruction::CONST: 296 case Instruction::CONST_4: 297 case Instruction::CONST_16: 298 case Instruction::CONST_HIGH16: 299 // TODO: Support wide constants (RETURN_WIDE). 300 success = AnalyseConstMethod(code_item, &method); 301 break; 302 case Instruction::IGET: 303 case Instruction::IGET_OBJECT: 304 case Instruction::IGET_BOOLEAN: 305 case Instruction::IGET_BYTE: 306 case Instruction::IGET_CHAR: 307 case Instruction::IGET_SHORT: 308 case Instruction::IGET_WIDE: 309 success = AnalyseIGetMethod(verifier, &method); 310 break; 311 case Instruction::IPUT: 312 case Instruction::IPUT_OBJECT: 313 case Instruction::IPUT_BOOLEAN: 314 case Instruction::IPUT_BYTE: 315 case Instruction::IPUT_CHAR: 316 case Instruction::IPUT_SHORT: 317 case Instruction::IPUT_WIDE: 318 success = AnalyseIPutMethod(verifier, &method); 319 break; 320 default: 321 success = false; 322 break; 323 } 324 return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method); 325} 326 327bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) { 328 ReaderMutexLock mu(Thread::Current(), lock_); 329 auto it = inline_methods_.find(method_index); 330 return it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0; 331} 332 333bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { 334 InlineMethod intrinsic; 335 { 336 ReaderMutexLock mu(Thread::Current(), lock_); 337 auto it = inline_methods_.find(info->index); 338 if (it == inline_methods_.end() || (it->second.flags & kInlineIntrinsic) == 0) { 339 return false; 340 } 341 intrinsic = it->second; 342 } 343 switch (intrinsic.opcode) { 344 case kIntrinsicDoubleCvt: 345 return backend->GenInlinedDoubleCvt(info); 346 case kIntrinsicFloatCvt: 347 return backend->GenInlinedFloatCvt(info); 348 case kIntrinsicReverseBytes: 349 return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data)); 350 case kIntrinsicAbsInt: 351 return backend->GenInlinedAbsInt(info); 352 case kIntrinsicAbsLong: 353 return backend->GenInlinedAbsLong(info); 354 case kIntrinsicAbsFloat: 355 return backend->GenInlinedAbsFloat(info); 356 case kIntrinsicAbsDouble: 357 return backend->GenInlinedAbsDouble(info); 358 case kIntrinsicMinMaxInt: 359 return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin); 360 case kIntrinsicSqrt: 361 return backend->GenInlinedSqrt(info); 362 case kIntrinsicCharAt: 363 return backend->GenInlinedCharAt(info); 364 case kIntrinsicCompareTo: 365 return backend->GenInlinedStringCompareTo(info); 366 case kIntrinsicIsEmptyOrLength: 367 return backend->GenInlinedStringIsEmptyOrLength( 368 info, intrinsic.d.data & kIntrinsicFlagIsEmpty); 369 case kIntrinsicIndexOf: 370 return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0); 371 case kIntrinsicCurrentThread: 372 return backend->GenInlinedCurrentThread(info); 373 case kIntrinsicPeek: 374 return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data)); 375 case kIntrinsicPoke: 376 return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data)); 377 case kIntrinsicCas: 378 return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong, 379 intrinsic.d.data & kIntrinsicFlagIsObject); 380 case kIntrinsicUnsafeGet: 381 return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong, 382 intrinsic.d.data & kIntrinsicFlagIsVolatile); 383 case kIntrinsicUnsafePut: 384 return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong, 385 intrinsic.d.data & kIntrinsicFlagIsObject, 386 intrinsic.d.data & kIntrinsicFlagIsVolatile, 387 intrinsic.d.data & kIntrinsicFlagIsOrdered); 388 default: 389 LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode; 390 return false; // avoid warning "control reaches end of non-void function" 391 } 392} 393 394bool DexFileMethodInliner::IsSpecial(uint32_t method_index) { 395 ReaderMutexLock mu(Thread::Current(), lock_); 396 auto it = inline_methods_.find(method_index); 397 return it != inline_methods_.end() && (it->second.flags & kInlineSpecial) != 0; 398} 399 400bool DexFileMethodInliner::GenSpecial(Mir2Lir* backend, uint32_t method_idx) { 401 InlineMethod special; 402 { 403 ReaderMutexLock mu(Thread::Current(), lock_); 404 auto it = inline_methods_.find(method_idx); 405 if (it == inline_methods_.end() || (it->second.flags & kInlineSpecial) == 0) { 406 return false; 407 } 408 special = it->second; 409 } 410 return backend->SpecialMIR2LIR(special); 411} 412 413uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache, 414 ClassCacheIndex index) { 415 uint32_t* class_index = &cache->class_indexes[index]; 416 if (*class_index != kIndexUnresolved) { 417 return *class_index; 418 } 419 420 const DexFile::StringId* string_id = dex_file->FindStringId(kClassCacheNames[index]); 421 if (string_id == nullptr) { 422 *class_index = kIndexNotFound; 423 return *class_index; 424 } 425 uint32_t string_index = dex_file->GetIndexForStringId(*string_id); 426 427 const DexFile::TypeId* type_id = dex_file->FindTypeId(string_index); 428 if (type_id == nullptr) { 429 *class_index = kIndexNotFound; 430 return *class_index; 431 } 432 *class_index = dex_file->GetIndexForTypeId(*type_id); 433 return *class_index; 434} 435 436uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache, 437 NameCacheIndex index) { 438 uint32_t* name_index = &cache->name_indexes[index]; 439 if (*name_index != kIndexUnresolved) { 440 return *name_index; 441 } 442 443 const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]); 444 if (string_id == nullptr) { 445 *name_index = kIndexNotFound; 446 return *name_index; 447 } 448 *name_index = dex_file->GetIndexForStringId(*string_id); 449 return *name_index; 450} 451 452uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache, 453 ProtoCacheIndex index) { 454 uint32_t* proto_index = &cache->proto_indexes[index]; 455 if (*proto_index != kIndexUnresolved) { 456 return *proto_index; 457 } 458 459 const ProtoDef& proto_def = kProtoCacheDefs[index]; 460 uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type); 461 if (return_index == kIndexNotFound) { 462 *proto_index = kIndexNotFound; 463 return *proto_index; 464 } 465 uint16_t return_type = static_cast<uint16_t>(return_index); 466 DCHECK_EQ(static_cast<uint32_t>(return_type), return_index); 467 468 uint32_t signature_length = proto_def.param_count; 469 uint16_t signature_type_idxs[kProtoMaxParams]; 470 for (uint32_t i = 0; i != signature_length; ++i) { 471 uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]); 472 if (param_index == kIndexNotFound) { 473 *proto_index = kIndexNotFound; 474 return *proto_index; 475 } 476 signature_type_idxs[i] = static_cast<uint16_t>(param_index); 477 DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index); 478 } 479 480 const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs, 481 signature_length); 482 if (proto_id == nullptr) { 483 *proto_index = kIndexNotFound; 484 return *proto_index; 485 } 486 *proto_index = dex_file->GetIndexForProtoId(*proto_id); 487 return *proto_index; 488} 489 490uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache, 491 const MethodDef& method_def) { 492 uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class); 493 if (declaring_class_index == kIndexNotFound) { 494 return kIndexNotFound; 495 } 496 uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name); 497 if (name_index == kIndexNotFound) { 498 return kIndexNotFound; 499 } 500 uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto); 501 if (proto_index == kIndexNotFound) { 502 return kIndexNotFound; 503 } 504 const DexFile::MethodId* method_id = 505 dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index), 506 dex_file->GetStringId(name_index), 507 dex_file->GetProtoId(proto_index)); 508 if (method_id == nullptr) { 509 return kIndexNotFound; 510 } 511 return dex_file->GetIndexForMethodId(*method_id); 512} 513 514DexFileMethodInliner::IndexCache::IndexCache() { 515 std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved); 516 std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved); 517 std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved); 518} 519 520void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { 521 DCHECK(dex_file != nullptr); 522 DCHECK(dex_file_ == nullptr); 523 IndexCache cache; 524 for (const IntrinsicDef& def : kIntrinsicMethods) { 525 uint32_t method_idx = FindMethodIndex(dex_file, &cache, def.method_def); 526 if (method_idx != kIndexNotFound) { 527 DCHECK(inline_methods_.find(method_idx) == inline_methods_.end()); 528 inline_methods_.Put(method_idx, def.intrinsic); 529 } 530 } 531 dex_file_ = dex_file; 532} 533 534bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) { 535 WriterMutexLock mu(Thread::Current(), lock_); 536 if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) { 537 inline_methods_.Put(method_idx, method); 538 return true; 539 } else { 540 if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") { 541 // TODO: String.length is both kIntrinsicIsEmptyOrLength and kInlineOpIGet. 542 } else { 543 LOG(ERROR) << "Inliner: " << PrettyMethod(method_idx, *dex_file_) << " already inline"; 544 } 545 return false; 546 } 547} 548 549bool DexFileMethodInliner::AnalyseReturnMethod(const DexFile::CodeItem* code_item, 550 InlineMethod* result) { 551 const Instruction* return_instruction = Instruction::At(code_item->insns_); 552 Instruction::Code return_opcode = return_instruction->Opcode(); 553 uint16_t size = (return_opcode == Instruction::RETURN_WIDE) ? kLong : kWord; 554 uint16_t is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u; 555 uint32_t reg = return_instruction->VRegA_11x(); 556 uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 557 DCHECK_GE(reg, arg_start); 558 DCHECK_LT(size == kLong ? reg + 1 : reg, code_item->registers_size_); 559 560 result->opcode = kInlineOpReturnArg; 561 result->flags = kInlineSpecial; 562 InlineReturnArgData* data = &result->d.return_data; 563 data->arg = reg - arg_start; 564 data->op_size = size; 565 data->is_object = is_object; 566 data->reserved = 0u; 567 data->reserved2 = 0u; 568 return true; 569} 570 571bool DexFileMethodInliner::AnalyseConstMethod(const DexFile::CodeItem* code_item, 572 InlineMethod* result) { 573 const Instruction* instruction = Instruction::At(code_item->insns_); 574 const Instruction* return_instruction = instruction->Next(); 575 Instruction::Code return_opcode = return_instruction->Opcode(); 576 if (return_opcode != Instruction::RETURN && 577 return_opcode != Instruction::RETURN_OBJECT) { 578 return false; 579 } 580 581 uint32_t return_reg = return_instruction->VRegA_11x(); 582 DCHECK_LT(return_reg, code_item->registers_size_); 583 584 uint32_t vA, vB, dummy; 585 uint64_t dummy_wide; 586 instruction->Decode(vA, vB, dummy_wide, dummy, nullptr); 587 if (instruction->Opcode() == Instruction::CONST_HIGH16) { 588 vB <<= 16; 589 } 590 DCHECK_LT(vA, code_item->registers_size_); 591 if (vA != return_reg) { 592 return false; // Not returning the value set by const? 593 } 594 if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) { 595 return false; // Returning non-null reference constant? 596 } 597 result->opcode = kInlineOpNonWideConst; 598 result->flags = kInlineSpecial; 599 result->d.data = static_cast<uint64_t>(vB); 600 return true; 601} 602 603bool DexFileMethodInliner::AnalyseIGetMethod(verifier::MethodVerifier* verifier, 604 InlineMethod* result) { 605 const DexFile::CodeItem* code_item = verifier->CodeItem(); 606 const Instruction* instruction = Instruction::At(code_item->insns_); 607 Instruction::Code opcode = instruction->Opcode(); 608 DCHECK_LT(static_cast<size_t>(opcode - Instruction::IGET), arraysize(kIGetIPutOpSizes)); 609 uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IGET]; 610 611 const Instruction* return_instruction = instruction->Next(); 612 Instruction::Code return_opcode = return_instruction->Opcode(); 613 if (!(return_opcode == Instruction::RETURN && size != kLong) && 614 !(return_opcode == Instruction::RETURN_WIDE && size == kLong) && 615 !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT)) { 616 return false; 617 } 618 619 uint32_t return_reg = return_instruction->VRegA_11x(); 620 DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg, 621 code_item->registers_size_); 622 623 uint32_t dst_reg = instruction->VRegA_22c(); 624 uint32_t object_reg = instruction->VRegB_22c(); 625 uint32_t field_idx = instruction->VRegC_22c(); 626 uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 627 DCHECK_GE(object_reg, arg_start); 628 DCHECK_LT(object_reg, code_item->registers_size_); 629 DCHECK_LT(size == kLong ? dst_reg + 1 : dst_reg, code_item->registers_size_); 630 if (dst_reg != return_reg) { 631 return false; // Not returning the value retrieved by IGET? 632 } 633 634 if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, false, verifier, 635 &result->d.ifield_data)) { 636 return false; 637 } 638 639 result->opcode = kInlineOpIGet; 640 result->flags = kInlineSpecial; 641 InlineIGetIPutData* data = &result->d.ifield_data; 642 data->op_size = size; 643 data->is_object = (opcode == Instruction::IGET_OBJECT) ? 1u : 0u; 644 data->object_arg = object_reg - arg_start; // Allow IGET on any register, not just "this". 645 data->src_arg = 0; 646 data->reserved = 0; 647 return true; 648} 649 650bool DexFileMethodInliner::AnalyseIPutMethod(verifier::MethodVerifier* verifier, 651 InlineMethod* result) { 652 const DexFile::CodeItem* code_item = verifier->CodeItem(); 653 const Instruction* instruction = Instruction::At(code_item->insns_); 654 Instruction::Code opcode = instruction->Opcode(); 655 DCHECK_LT(static_cast<size_t>(opcode - Instruction::IPUT), arraysize(kIGetIPutOpSizes)); 656 uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IPUT]; 657 658 const Instruction* return_instruction = instruction->Next(); 659 if (return_instruction->Opcode() != Instruction::RETURN_VOID) { 660 // TODO: Support returning an argument. 661 // This is needed by builder classes and generated accessor setters. 662 // builder.setX(value): iput value, this, fieldX; return-object this; 663 // object.access$nnn(value): iput value, this, fieldX; return value; 664 // Use InlineIGetIPutData::reserved to hold the information. 665 return false; 666 } 667 668 uint32_t src_reg = instruction->VRegA_22c(); 669 uint32_t object_reg = instruction->VRegB_22c(); 670 uint32_t field_idx = instruction->VRegC_22c(); 671 uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 672 DCHECK_GE(object_reg, arg_start); 673 DCHECK_LT(object_reg, code_item->registers_size_); 674 DCHECK_GE(src_reg, arg_start); 675 DCHECK_LT(size == kLong ? src_reg + 1 : src_reg, code_item->registers_size_); 676 677 if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, true, verifier, 678 &result->d.ifield_data)) { 679 return false; 680 } 681 682 result->opcode = kInlineOpIPut; 683 result->flags = kInlineSpecial; 684 InlineIGetIPutData* data = &result->d.ifield_data; 685 data->op_size = size; 686 data->is_object = (opcode == Instruction::IPUT_OBJECT) ? 1u : 0u; 687 data->object_arg = object_reg - arg_start; // Allow IPUT on any register, not just "this". 688 data->src_arg = src_reg - arg_start; 689 data->reserved = 0; 690 return true; 691} 692 693} // namespace art 694