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