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 33 namespace art { 34 35 namespace { // anonymous namespace 36 37 static constexpr bool kIntrinsicIsStatic[] = { 38 true, // kIntrinsicDoubleCvt 39 true, // kIntrinsicFloatCvt 40 true, // kIntrinsicReverseBits 41 true, // kIntrinsicReverseBytes 42 true, // kIntrinsicAbsInt 43 true, // kIntrinsicAbsLong 44 true, // kIntrinsicAbsFloat 45 true, // kIntrinsicAbsDouble 46 true, // kIntrinsicMinMaxInt 47 true, // kIntrinsicMinMaxLong 48 true, // kIntrinsicMinMaxFloat 49 true, // kIntrinsicMinMaxDouble 50 true, // kIntrinsicSqrt 51 true, // kIntrinsicCeil 52 true, // kIntrinsicFloor 53 true, // kIntrinsicRint 54 true, // kIntrinsicRoundFloat 55 true, // kIntrinsicRoundDouble 56 false, // kIntrinsicReferenceGetReferent 57 false, // kIntrinsicCharAt 58 false, // kIntrinsicCompareTo 59 false, // kIntrinsicIsEmptyOrLength 60 false, // kIntrinsicIndexOf 61 true, // kIntrinsicCurrentThread 62 true, // kIntrinsicPeek 63 true, // kIntrinsicPoke 64 false, // kIntrinsicCas 65 false, // kIntrinsicUnsafeGet 66 false, // kIntrinsicUnsafePut 67 true, // kIntrinsicSystemArrayCopyCharArray 68 }; 69 COMPILE_ASSERT(arraysize(kIntrinsicIsStatic) == kInlineOpNop, check_arraysize_kIntrinsicIsStatic); 70 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicDoubleCvt], DoubleCvt_must_be_static); 71 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicFloatCvt], FloatCvt_must_be_static); 72 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicReverseBits], ReverseBits_must_be_static); 73 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicReverseBytes], ReverseBytes_must_be_static); 74 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicAbsInt], AbsInt_must_be_static); 75 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicAbsLong], AbsLong_must_be_static); 76 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicAbsFloat], AbsFloat_must_be_static); 77 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicAbsDouble], AbsDouble_must_be_static); 78 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxInt], MinMaxInt_must_be_static); 79 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxLong], MinMaxLong_must_be_static); 80 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], MinMaxFloat_must_be_static); 81 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], MinMaxDouble_must_be_static); 82 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicSqrt], Sqrt_must_be_static); 83 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicCeil], Ceil_must_be_static); 84 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicFloor], Floor_must_be_static); 85 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRint], Rint_must_be_static); 86 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRoundFloat], RoundFloat_must_be_static); 87 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRoundDouble], RoundDouble_must_be_static); 88 COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], Get_must_not_be_static); 89 COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCharAt], CharAt_must_not_be_static); 90 COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCompareTo], CompareTo_must_not_be_static); 91 COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], IsEmptyOrLength_must_not_be_static); 92 COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicIndexOf], IndexOf_must_not_be_static); 93 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicCurrentThread], CurrentThread_must_be_static); 94 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicPeek], Peek_must_be_static); 95 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicPoke], Poke_must_be_static); 96 COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCas], Cas_must_not_be_static); 97 COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], UnsafeGet_must_not_be_static); 98 COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicUnsafePut], UnsafePut_must_not_be_static); 99 COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray], 100 SystemArrayCopyCharArray_must_be_static); 101 102 MIR* AllocReplacementMIR(MIRGraph* mir_graph, MIR* invoke, MIR* move_return) { 103 MIR* insn = mir_graph->NewMIR(); 104 insn->offset = invoke->offset; 105 insn->optimization_flags = MIR_CALLEE; 106 return insn; 107 } 108 109 uint32_t GetInvokeReg(MIR* invoke, uint32_t arg) { 110 DCHECK_LT(arg, invoke->dalvikInsn.vA); 111 DCHECK(!MIR::DecodedInstruction::IsPseudoMirOp(invoke->dalvikInsn.opcode)); 112 if (Instruction::FormatOf(invoke->dalvikInsn.opcode) == Instruction::k3rc) { 113 return invoke->dalvikInsn.vC + arg; // Non-range invoke. 114 } else { 115 DCHECK_EQ(Instruction::FormatOf(invoke->dalvikInsn.opcode), Instruction::k35c); 116 return invoke->dalvikInsn.arg[arg]; // Range invoke. 117 } 118 } 119 120 bool WideArgIsInConsecutiveDalvikRegs(MIR* invoke, uint32_t arg) { 121 DCHECK_LT(arg + 1, invoke->dalvikInsn.vA); 122 DCHECK(!MIR::DecodedInstruction::IsPseudoMirOp(invoke->dalvikInsn.opcode)); 123 return Instruction::FormatOf(invoke->dalvikInsn.opcode) == Instruction::k3rc || 124 invoke->dalvikInsn.arg[arg + 1u] == invoke->dalvikInsn.arg[arg] + 1u; 125 } 126 127 } // anonymous namespace 128 129 const uint32_t DexFileMethodInliner::kIndexUnresolved; 130 const char* const DexFileMethodInliner::kClassCacheNames[] = { 131 "Z", // kClassCacheBoolean 132 "B", // kClassCacheByte 133 "C", // kClassCacheChar 134 "S", // kClassCacheShort 135 "I", // kClassCacheInt 136 "J", // kClassCacheLong 137 "F", // kClassCacheFloat 138 "D", // kClassCacheDouble 139 "V", // kClassCacheVoid 140 "Ljava/lang/Object;", // kClassCacheJavaLangObject 141 "Ljava/lang/ref/Reference;", // kClassCacheJavaLangRefReference 142 "Ljava/lang/String;", // kClassCacheJavaLangString 143 "Ljava/lang/Double;", // kClassCacheJavaLangDouble 144 "Ljava/lang/Float;", // kClassCacheJavaLangFloat 145 "Ljava/lang/Integer;", // kClassCacheJavaLangInteger 146 "Ljava/lang/Long;", // kClassCacheJavaLangLong 147 "Ljava/lang/Short;", // kClassCacheJavaLangShort 148 "Ljava/lang/Math;", // kClassCacheJavaLangMath 149 "Ljava/lang/StrictMath;", // kClassCacheJavaLangStrictMath 150 "Ljava/lang/Thread;", // kClassCacheJavaLangThread 151 "Llibcore/io/Memory;", // kClassCacheLibcoreIoMemory 152 "Lsun/misc/Unsafe;", // kClassCacheSunMiscUnsafe 153 "Ljava/lang/System;", // kClassCacheJavaLangSystem 154 "[C" // kClassCacheJavaLangCharArray 155 }; 156 157 const char* const DexFileMethodInliner::kNameCacheNames[] = { 158 "reverse", // kNameCacheReverse 159 "reverseBytes", // kNameCacheReverseBytes 160 "doubleToRawLongBits", // kNameCacheDoubleToRawLongBits 161 "longBitsToDouble", // kNameCacheLongBitsToDouble 162 "floatToRawIntBits", // kNameCacheFloatToRawIntBits 163 "intBitsToFloat", // kNameCacheIntBitsToFloat 164 "abs", // kNameCacheAbs 165 "max", // kNameCacheMax 166 "min", // kNameCacheMin 167 "sqrt", // kNameCacheSqrt 168 "ceil", // kNameCacheCeil 169 "floor", // kNameCacheFloor 170 "rint", // kNameCacheRint 171 "round", // kNameCacheRound 172 "getReferent", // kNameCacheReferenceGet 173 "charAt", // kNameCacheCharAt 174 "compareTo", // kNameCacheCompareTo 175 "isEmpty", // kNameCacheIsEmpty 176 "indexOf", // kNameCacheIndexOf 177 "length", // kNameCacheLength 178 "currentThread", // kNameCacheCurrentThread 179 "peekByte", // kNameCachePeekByte 180 "peekIntNative", // kNameCachePeekIntNative 181 "peekLongNative", // kNameCachePeekLongNative 182 "peekShortNative", // kNameCachePeekShortNative 183 "pokeByte", // kNameCachePokeByte 184 "pokeIntNative", // kNameCachePokeIntNative 185 "pokeLongNative", // kNameCachePokeLongNative 186 "pokeShortNative", // kNameCachePokeShortNative 187 "compareAndSwapInt", // kNameCacheCompareAndSwapInt 188 "compareAndSwapLong", // kNameCacheCompareAndSwapLong 189 "compareAndSwapObject", // kNameCacheCompareAndSwapObject 190 "getInt", // kNameCacheGetInt 191 "getIntVolatile", // kNameCacheGetIntVolatile 192 "putInt", // kNameCachePutInt 193 "putIntVolatile", // kNameCachePutIntVolatile 194 "putOrderedInt", // kNameCachePutOrderedInt 195 "getLong", // kNameCacheGetLong 196 "getLongVolatile", // kNameCacheGetLongVolatile 197 "putLong", // kNameCachePutLong 198 "putLongVolatile", // kNameCachePutLongVolatile 199 "putOrderedLong", // kNameCachePutOrderedLong 200 "getObject", // kNameCacheGetObject 201 "getObjectVolatile", // kNameCacheGetObjectVolatile 202 "putObject", // kNameCachePutObject 203 "putObjectVolatile", // kNameCachePutObjectVolatile 204 "putOrderedObject", // kNameCachePutOrderedObject 205 "arraycopy", // kNameCacheArrayCopy 206 }; 207 208 const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { 209 // kProtoCacheI_I 210 { kClassCacheInt, 1, { kClassCacheInt } }, 211 // kProtoCacheJ_J 212 { kClassCacheLong, 1, { kClassCacheLong } }, 213 // kProtoCacheS_S 214 { kClassCacheShort, 1, { kClassCacheShort } }, 215 // kProtoCacheD_D 216 { kClassCacheDouble, 1, { kClassCacheDouble } }, 217 // kProtoCacheDD_D 218 { kClassCacheDouble, 2, { kClassCacheDouble, kClassCacheDouble } }, 219 // kProtoCacheF_F 220 { kClassCacheFloat, 1, { kClassCacheFloat } }, 221 // kProtoCacheFF_F 222 { kClassCacheFloat, 2, { kClassCacheFloat, kClassCacheFloat } }, 223 // kProtoCacheD_J 224 { kClassCacheLong, 1, { kClassCacheDouble } }, 225 // kProtoCacheJ_D 226 { kClassCacheDouble, 1, { kClassCacheLong } }, 227 // kProtoCacheF_I 228 { kClassCacheInt, 1, { kClassCacheFloat } }, 229 // kProtoCacheI_F 230 { kClassCacheFloat, 1, { kClassCacheInt } }, 231 // kProtoCacheII_I 232 { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } }, 233 // kProtoCacheI_C 234 { kClassCacheChar, 1, { kClassCacheInt } }, 235 // kProtoCacheString_I 236 { kClassCacheInt, 1, { kClassCacheJavaLangString } }, 237 // kProtoCache_Z 238 { kClassCacheBoolean, 0, { } }, 239 // kProtoCache_I 240 { kClassCacheInt, 0, { } }, 241 // kProtoCache_Object 242 { kClassCacheJavaLangObject, 0, { } }, 243 // kProtoCache_Thread 244 { kClassCacheJavaLangThread, 0, { } }, 245 // kProtoCacheJ_B 246 { kClassCacheByte, 1, { kClassCacheLong } }, 247 // kProtoCacheJ_I 248 { kClassCacheInt, 1, { kClassCacheLong } }, 249 // kProtoCacheJ_S 250 { kClassCacheShort, 1, { kClassCacheLong } }, 251 // kProtoCacheJB_V 252 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } }, 253 // kProtoCacheJI_V 254 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } }, 255 // kProtoCacheJJ_J 256 { kClassCacheLong, 2, { kClassCacheLong, kClassCacheLong } }, 257 // kProtoCacheJJ_V 258 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } }, 259 // kProtoCacheJS_V 260 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } }, 261 // kProtoCacheObjectJII_Z 262 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, 263 kClassCacheInt, kClassCacheInt } }, 264 // kProtoCacheObjectJJJ_Z 265 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, 266 kClassCacheLong, kClassCacheLong } }, 267 // kProtoCacheObjectJObjectObject_Z 268 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, 269 kClassCacheJavaLangObject, kClassCacheJavaLangObject } }, 270 // kProtoCacheObjectJ_I 271 { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, 272 // kProtoCacheObjectJI_V 273 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } }, 274 // kProtoCacheObjectJ_J 275 { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, 276 // kProtoCacheObjectJJ_V 277 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } }, 278 // kProtoCacheObjectJ_Object 279 { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, 280 // kProtoCacheObjectJObject_V 281 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, 282 kClassCacheJavaLangObject } }, 283 // kProtoCacheCharArrayICharArrayII_V 284 { kClassCacheVoid, 5, {kClassCacheJavaLangCharArray, kClassCacheInt, 285 kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt}} 286 }; 287 288 const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = { 289 #define INTRINSIC(c, n, p, o, d) \ 290 { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } } 291 292 INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0), 293 INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0), 294 INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), 295 INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0), 296 297 INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32), 298 INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64), 299 INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf), 300 INTRINSIC(JavaLangInteger, Reverse, I_I, kIntrinsicReverseBits, k32), 301 INTRINSIC(JavaLangLong, Reverse, J_J, kIntrinsicReverseBits, k64), 302 303 INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), 304 INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), 305 INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0), 306 INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0), 307 INTRINSIC(JavaLangMath, Abs, F_F, kIntrinsicAbsFloat, 0), 308 INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0), 309 INTRINSIC(JavaLangMath, Abs, D_D, kIntrinsicAbsDouble, 0), 310 INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0), 311 INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), 312 INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), 313 INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), 314 INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), 315 INTRINSIC(JavaLangMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin), 316 INTRINSIC(JavaLangStrictMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin), 317 INTRINSIC(JavaLangMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax), 318 INTRINSIC(JavaLangStrictMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax), 319 INTRINSIC(JavaLangMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin), 320 INTRINSIC(JavaLangStrictMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin), 321 INTRINSIC(JavaLangMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax), 322 INTRINSIC(JavaLangStrictMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax), 323 INTRINSIC(JavaLangMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin), 324 INTRINSIC(JavaLangStrictMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin), 325 INTRINSIC(JavaLangMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax), 326 INTRINSIC(JavaLangStrictMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax), 327 328 INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), 329 INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), 330 331 INTRINSIC(JavaLangMath, Ceil, D_D, kIntrinsicCeil, 0), 332 INTRINSIC(JavaLangStrictMath, Ceil, D_D, kIntrinsicCeil, 0), 333 INTRINSIC(JavaLangMath, Floor, D_D, kIntrinsicFloor, 0), 334 INTRINSIC(JavaLangStrictMath, Floor, D_D, kIntrinsicFloor, 0), 335 INTRINSIC(JavaLangMath, Rint, D_D, kIntrinsicRint, 0), 336 INTRINSIC(JavaLangStrictMath, Rint, D_D, kIntrinsicRint, 0), 337 INTRINSIC(JavaLangMath, Round, F_I, kIntrinsicRoundFloat, 0), 338 INTRINSIC(JavaLangStrictMath, Round, F_I, kIntrinsicRoundFloat, 0), 339 INTRINSIC(JavaLangMath, Round, D_J, kIntrinsicRoundDouble, 0), 340 INTRINSIC(JavaLangStrictMath, Round, D_J, kIntrinsicRoundDouble, 0), 341 342 INTRINSIC(JavaLangRefReference, ReferenceGetReferent, _Object, kIntrinsicReferenceGetReferent, 0), 343 344 INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), 345 INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), 346 INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), 347 INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone), 348 INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0), 349 INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength), 350 351 INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0), 352 353 INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte), 354 INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, k32), 355 INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, k64), 356 INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf), 357 INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte), 358 INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, k32), 359 INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, k64), 360 INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf), 361 362 INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas, 363 kIntrinsicFlagNone), 364 INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas, 365 kIntrinsicFlagIsLong), 366 INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas, 367 kIntrinsicFlagIsObject), 368 369 #define UNSAFE_GET_PUT(type, code, type_flags) \ 370 INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ 371 type_flags & ~kIntrinsicFlagIsObject), \ 372 INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ 373 (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \ 374 INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ 375 type_flags), \ 376 INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ 377 type_flags | kIntrinsicFlagIsVolatile), \ 378 INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ 379 type_flags | kIntrinsicFlagIsOrdered) 380 381 UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone), 382 UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong), 383 UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject), 384 #undef UNSAFE_GET_PUT 385 386 INTRINSIC(JavaLangSystem, ArrayCopy, CharArrayICharArrayII_V , kIntrinsicSystemArrayCopyCharArray, 387 0), 388 389 390 #undef INTRINSIC 391 }; 392 393 DexFileMethodInliner::DexFileMethodInliner() 394 : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock), 395 dex_file_(NULL) { 396 COMPILE_ASSERT(kClassCacheFirst == 0, kClassCacheFirst_not_0); 397 COMPILE_ASSERT(arraysize(kClassCacheNames) == kClassCacheLast, bad_arraysize_kClassCacheNames); 398 COMPILE_ASSERT(kNameCacheFirst == 0, kNameCacheFirst_not_0); 399 COMPILE_ASSERT(arraysize(kNameCacheNames) == kNameCacheLast, bad_arraysize_kNameCacheNames); 400 COMPILE_ASSERT(kProtoCacheFirst == 0, kProtoCacheFirst_not_0); 401 COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames); 402 } 403 404 DexFileMethodInliner::~DexFileMethodInliner() { 405 } 406 407 bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) { 408 InlineMethod method; 409 bool success = InlineMethodAnalyser::AnalyseMethodCode(verifier, &method); 410 return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method); 411 } 412 413 bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) { 414 ReaderMutexLock mu(Thread::Current(), lock_); 415 auto it = inline_methods_.find(method_index); 416 bool res = (it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0); 417 if (res && intrinsic != nullptr) { 418 *intrinsic = it->second; 419 } 420 return res; 421 } 422 423 bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { 424 InlineMethod intrinsic; 425 { 426 ReaderMutexLock mu(Thread::Current(), lock_); 427 auto it = inline_methods_.find(info->index); 428 if (it == inline_methods_.end() || (it->second.flags & kInlineIntrinsic) == 0) { 429 return false; 430 } 431 intrinsic = it->second; 432 } 433 if (kIntrinsicIsStatic[intrinsic.opcode] != (info->type == kStatic)) { 434 // Invoke type mismatch. 435 return false; 436 } 437 switch (intrinsic.opcode) { 438 case kIntrinsicDoubleCvt: 439 return backend->GenInlinedDoubleCvt(info); 440 case kIntrinsicFloatCvt: 441 return backend->GenInlinedFloatCvt(info); 442 case kIntrinsicReverseBytes: 443 return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data)); 444 case kIntrinsicReverseBits: 445 return backend->GenInlinedReverseBits(info, static_cast<OpSize>(intrinsic.d.data)); 446 case kIntrinsicAbsInt: 447 return backend->GenInlinedAbsInt(info); 448 case kIntrinsicAbsLong: 449 return backend->GenInlinedAbsLong(info); 450 case kIntrinsicAbsFloat: 451 return backend->GenInlinedAbsFloat(info); 452 case kIntrinsicAbsDouble: 453 return backend->GenInlinedAbsDouble(info); 454 case kIntrinsicMinMaxInt: 455 return backend->GenInlinedMinMax(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_long */); 456 case kIntrinsicMinMaxLong: 457 return backend->GenInlinedMinMax(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_long */); 458 case kIntrinsicMinMaxFloat: 459 return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_double */); 460 case kIntrinsicMinMaxDouble: 461 return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_double */); 462 case kIntrinsicSqrt: 463 return backend->GenInlinedSqrt(info); 464 case kIntrinsicCeil: 465 return backend->GenInlinedCeil(info); 466 case kIntrinsicFloor: 467 return backend->GenInlinedFloor(info); 468 case kIntrinsicRint: 469 return backend->GenInlinedRint(info); 470 case kIntrinsicRoundFloat: 471 return backend->GenInlinedRound(info, false /* is_double */); 472 case kIntrinsicRoundDouble: 473 return backend->GenInlinedRound(info, true /* is_double */); 474 case kIntrinsicReferenceGetReferent: 475 return backend->GenInlinedReferenceGetReferent(info); 476 case kIntrinsicCharAt: 477 return backend->GenInlinedCharAt(info); 478 case kIntrinsicCompareTo: 479 return backend->GenInlinedStringCompareTo(info); 480 case kIntrinsicIsEmptyOrLength: 481 return backend->GenInlinedStringIsEmptyOrLength( 482 info, intrinsic.d.data & kIntrinsicFlagIsEmpty); 483 case kIntrinsicIndexOf: 484 return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0); 485 case kIntrinsicCurrentThread: 486 return backend->GenInlinedCurrentThread(info); 487 case kIntrinsicPeek: 488 return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data)); 489 case kIntrinsicPoke: 490 return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data)); 491 case kIntrinsicCas: 492 return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong, 493 intrinsic.d.data & kIntrinsicFlagIsObject); 494 case kIntrinsicUnsafeGet: 495 return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong, 496 intrinsic.d.data & kIntrinsicFlagIsVolatile); 497 case kIntrinsicUnsafePut: 498 return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong, 499 intrinsic.d.data & kIntrinsicFlagIsObject, 500 intrinsic.d.data & kIntrinsicFlagIsVolatile, 501 intrinsic.d.data & kIntrinsicFlagIsOrdered); 502 case kIntrinsicSystemArrayCopyCharArray: 503 return backend->GenInlinedArrayCopyCharArray(info); 504 default: 505 LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode; 506 return false; // avoid warning "control reaches end of non-void function" 507 } 508 } 509 510 bool DexFileMethodInliner::IsSpecial(uint32_t method_index) { 511 ReaderMutexLock mu(Thread::Current(), lock_); 512 auto it = inline_methods_.find(method_index); 513 return it != inline_methods_.end() && (it->second.flags & kInlineSpecial) != 0; 514 } 515 516 bool DexFileMethodInliner::GenSpecial(Mir2Lir* backend, uint32_t method_idx) { 517 InlineMethod special; 518 { 519 ReaderMutexLock mu(Thread::Current(), lock_); 520 auto it = inline_methods_.find(method_idx); 521 if (it == inline_methods_.end() || (it->second.flags & kInlineSpecial) == 0) { 522 return false; 523 } 524 special = it->second; 525 } 526 return backend->SpecialMIR2LIR(special); 527 } 528 529 bool DexFileMethodInliner::GenInline(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 530 uint32_t method_idx) { 531 InlineMethod method; 532 { 533 ReaderMutexLock mu(Thread::Current(), lock_); 534 auto it = inline_methods_.find(method_idx); 535 if (it == inline_methods_.end() || (it->second.flags & kInlineSpecial) == 0) { 536 return false; 537 } 538 method = it->second; 539 } 540 541 MIR* move_result = nullptr; 542 bool result = true; 543 switch (method.opcode) { 544 case kInlineOpNop: 545 break; 546 case kInlineOpNonWideConst: 547 move_result = mir_graph->FindMoveResult(bb, invoke); 548 result = GenInlineConst(mir_graph, bb, invoke, move_result, method); 549 break; 550 case kInlineOpReturnArg: 551 move_result = mir_graph->FindMoveResult(bb, invoke); 552 result = GenInlineReturnArg(mir_graph, bb, invoke, move_result, method); 553 break; 554 case kInlineOpIGet: 555 move_result = mir_graph->FindMoveResult(bb, invoke); 556 result = GenInlineIGet(mir_graph, bb, invoke, move_result, method, method_idx); 557 break; 558 case kInlineOpIPut: 559 move_result = mir_graph->FindMoveResult(bb, invoke); 560 result = GenInlineIPut(mir_graph, bb, invoke, move_result, method, method_idx); 561 break; 562 default: 563 LOG(FATAL) << "Unexpected inline op: " << method.opcode; 564 } 565 if (result) { 566 invoke->optimization_flags |= MIR_INLINED; 567 if (move_result != nullptr) { 568 move_result->optimization_flags |= MIR_INLINED; 569 move_result->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); 570 } 571 } 572 return result; 573 } 574 575 uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache, 576 ClassCacheIndex index) { 577 uint32_t* class_index = &cache->class_indexes[index]; 578 if (*class_index != kIndexUnresolved) { 579 return *class_index; 580 } 581 582 const DexFile::StringId* string_id = dex_file->FindStringId(kClassCacheNames[index]); 583 if (string_id == nullptr) { 584 *class_index = kIndexNotFound; 585 return *class_index; 586 } 587 uint32_t string_index = dex_file->GetIndexForStringId(*string_id); 588 589 const DexFile::TypeId* type_id = dex_file->FindTypeId(string_index); 590 if (type_id == nullptr) { 591 *class_index = kIndexNotFound; 592 return *class_index; 593 } 594 *class_index = dex_file->GetIndexForTypeId(*type_id); 595 return *class_index; 596 } 597 598 uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache, 599 NameCacheIndex index) { 600 uint32_t* name_index = &cache->name_indexes[index]; 601 if (*name_index != kIndexUnresolved) { 602 return *name_index; 603 } 604 605 const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]); 606 if (string_id == nullptr) { 607 *name_index = kIndexNotFound; 608 return *name_index; 609 } 610 *name_index = dex_file->GetIndexForStringId(*string_id); 611 return *name_index; 612 } 613 614 uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache, 615 ProtoCacheIndex index) { 616 uint32_t* proto_index = &cache->proto_indexes[index]; 617 if (*proto_index != kIndexUnresolved) { 618 return *proto_index; 619 } 620 621 const ProtoDef& proto_def = kProtoCacheDefs[index]; 622 uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type); 623 if (return_index == kIndexNotFound) { 624 *proto_index = kIndexNotFound; 625 return *proto_index; 626 } 627 uint16_t return_type = static_cast<uint16_t>(return_index); 628 DCHECK_EQ(static_cast<uint32_t>(return_type), return_index); 629 630 uint32_t signature_length = proto_def.param_count; 631 uint16_t signature_type_idxs[kProtoMaxParams]; 632 for (uint32_t i = 0; i != signature_length; ++i) { 633 uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]); 634 if (param_index == kIndexNotFound) { 635 *proto_index = kIndexNotFound; 636 return *proto_index; 637 } 638 signature_type_idxs[i] = static_cast<uint16_t>(param_index); 639 DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index); 640 } 641 642 const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs, 643 signature_length); 644 if (proto_id == nullptr) { 645 *proto_index = kIndexNotFound; 646 return *proto_index; 647 } 648 *proto_index = dex_file->GetIndexForProtoId(*proto_id); 649 return *proto_index; 650 } 651 652 uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache, 653 const MethodDef& method_def) { 654 uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class); 655 if (declaring_class_index == kIndexNotFound) { 656 return kIndexNotFound; 657 } 658 uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name); 659 if (name_index == kIndexNotFound) { 660 return kIndexNotFound; 661 } 662 uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto); 663 if (proto_index == kIndexNotFound) { 664 return kIndexNotFound; 665 } 666 const DexFile::MethodId* method_id = 667 dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index), 668 dex_file->GetStringId(name_index), 669 dex_file->GetProtoId(proto_index)); 670 if (method_id == nullptr) { 671 return kIndexNotFound; 672 } 673 return dex_file->GetIndexForMethodId(*method_id); 674 } 675 676 DexFileMethodInliner::IndexCache::IndexCache() { 677 std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved); 678 std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved); 679 std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved); 680 } 681 682 void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { 683 DCHECK(dex_file != nullptr); 684 DCHECK(dex_file_ == nullptr); 685 IndexCache cache; 686 for (const IntrinsicDef& def : kIntrinsicMethods) { 687 uint32_t method_idx = FindMethodIndex(dex_file, &cache, def.method_def); 688 if (method_idx != kIndexNotFound) { 689 DCHECK(inline_methods_.find(method_idx) == inline_methods_.end()); 690 inline_methods_.Put(method_idx, def.intrinsic); 691 } 692 } 693 dex_file_ = dex_file; 694 } 695 696 bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) { 697 WriterMutexLock mu(Thread::Current(), lock_); 698 if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) { 699 inline_methods_.Put(method_idx, method); 700 return true; 701 } else { 702 if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") { 703 // TODO: String.length is both kIntrinsicIsEmptyOrLength and kInlineOpIGet. 704 } else { 705 LOG(ERROR) << "Inliner: " << PrettyMethod(method_idx, *dex_file_) << " already inline"; 706 } 707 return false; 708 } 709 } 710 711 bool DexFileMethodInliner::GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 712 MIR* move_result, const InlineMethod& method) { 713 if (move_result == nullptr) { 714 // Result is unused. 715 return true; 716 } 717 718 // Check the opcode and for MOVE_RESULT_OBJECT check also that the constant is null. 719 DCHECK(move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT || 720 (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT && 721 method.d.data == 0u)); 722 723 // Insert the CONST instruction. 724 MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result); 725 insn->dalvikInsn.opcode = Instruction::CONST; 726 insn->dalvikInsn.vA = move_result->dalvikInsn.vA; 727 insn->dalvikInsn.vB = method.d.data; 728 bb->InsertMIRAfter(move_result, insn); 729 return true; 730 } 731 732 bool DexFileMethodInliner::GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 733 MIR* move_result, const InlineMethod& method) { 734 if (move_result == nullptr) { 735 // Result is unused. 736 return true; 737 } 738 739 // Select opcode and argument. 740 const InlineReturnArgData& data = method.d.return_data; 741 Instruction::Code opcode = Instruction::MOVE_FROM16; 742 uint32_t arg = GetInvokeReg(invoke, data.arg); 743 if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { 744 DCHECK_EQ(data.is_object, 1u); 745 DCHECK_EQ(data.is_wide, 0u); 746 opcode = Instruction::MOVE_OBJECT_FROM16; 747 } else if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE) { 748 DCHECK_EQ(data.is_wide, 1u); 749 DCHECK_EQ(data.is_object, 0u); 750 opcode = Instruction::MOVE_WIDE_FROM16; 751 if (!WideArgIsInConsecutiveDalvikRegs(invoke, data.arg)) { 752 // The two halfs of the source value are not in consecutive dalvik registers in INVOKE. 753 return false; 754 } 755 } else { 756 DCHECK(move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT); 757 DCHECK_EQ(data.is_wide, 0u); 758 DCHECK_EQ(data.is_object, 0u); 759 } 760 761 // Insert the move instruction 762 MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result); 763 insn->dalvikInsn.opcode = opcode; 764 insn->dalvikInsn.vA = move_result->dalvikInsn.vA; 765 insn->dalvikInsn.vB = arg; 766 bb->InsertMIRAfter(move_result, insn); 767 return true; 768 } 769 770 bool DexFileMethodInliner::GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 771 MIR* move_result, const InlineMethod& method, 772 uint32_t method_idx) { 773 CompilationUnit* cu = mir_graph->GetCurrentDexCompilationUnit()->GetCompilationUnit(); 774 if (cu->enable_debug & (1 << kDebugSlowFieldPath)) { 775 return false; 776 } 777 778 const InlineIGetIPutData& data = method.d.ifield_data; 779 Instruction::Code opcode = static_cast<Instruction::Code>(Instruction::IGET + data.op_variant); 780 DCHECK_EQ(InlineMethodAnalyser::IGetVariant(opcode), data.op_variant); 781 uint32_t object_reg = GetInvokeReg(invoke, data.object_arg); 782 783 if (move_result == nullptr) { 784 // Result is unused. If volatile, we still need to emit the IGET but we have no destination. 785 return !data.is_volatile; 786 } 787 788 DCHECK_EQ(data.method_is_static != 0u, 789 invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC || 790 invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC_RANGE); 791 bool object_is_this = (data.method_is_static == 0u && data.object_arg == 0u); 792 if (!object_is_this) { 793 // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE). 794 // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 795 if (!InlineMethodAnalyser::IsSyntheticAccessor( 796 mir_graph->GetMethodLoweringInfo(invoke).GetTargetMethod())) { 797 return false; 798 } 799 } 800 801 if (object_is_this) { 802 // Mark invoke as NOP, null-check is done on IGET. No aborts after this. 803 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); 804 } 805 806 MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result); 807 insn->offset = invoke->offset; 808 insn->dalvikInsn.opcode = opcode; 809 insn->dalvikInsn.vA = move_result->dalvikInsn.vA; 810 insn->dalvikInsn.vB = object_reg; 811 mir_graph->ComputeInlineIFieldLoweringInfo(data.field_idx, invoke, insn); 812 813 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).IsResolved()); 814 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).FastGet()); 815 DCHECK_EQ(data.field_offset, mir_graph->GetIFieldLoweringInfo(insn).FieldOffset().Uint32Value()); 816 DCHECK_EQ(data.is_volatile, mir_graph->GetIFieldLoweringInfo(insn).IsVolatile() ? 1u : 0u); 817 818 bb->InsertMIRAfter(move_result, insn); 819 return true; 820 } 821 822 bool DexFileMethodInliner::GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 823 MIR* move_result, const InlineMethod& method, 824 uint32_t method_idx) { 825 CompilationUnit* cu = mir_graph->GetCurrentDexCompilationUnit()->GetCompilationUnit(); 826 if (cu->enable_debug & (1 << kDebugSlowFieldPath)) { 827 return false; 828 } 829 830 const InlineIGetIPutData& data = method.d.ifield_data; 831 Instruction::Code opcode = static_cast<Instruction::Code>(Instruction::IPUT + data.op_variant); 832 DCHECK_EQ(InlineMethodAnalyser::IPutVariant(opcode), data.op_variant); 833 uint32_t object_reg = GetInvokeReg(invoke, data.object_arg); 834 uint32_t src_reg = GetInvokeReg(invoke, data.src_arg); 835 uint32_t return_reg = 836 data.return_arg_plus1 != 0u ? GetInvokeReg(invoke, data.return_arg_plus1 - 1u) : 0u; 837 838 if (opcode == Instruction::IPUT_WIDE && !WideArgIsInConsecutiveDalvikRegs(invoke, data.src_arg)) { 839 // The two halfs of the source value are not in consecutive dalvik registers in INVOKE. 840 return false; 841 } 842 843 DCHECK(move_result == nullptr || data.return_arg_plus1 != 0u); 844 if (move_result != nullptr && move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE && 845 !WideArgIsInConsecutiveDalvikRegs(invoke, data.return_arg_plus1 - 1u)) { 846 // The two halfs of the return value are not in consecutive dalvik registers in INVOKE. 847 return false; 848 } 849 850 DCHECK_EQ(data.method_is_static != 0u, 851 invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC || 852 invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC_RANGE); 853 bool object_is_this = (data.method_is_static == 0u && data.object_arg == 0u); 854 if (!object_is_this) { 855 // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE). 856 // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 857 if (!InlineMethodAnalyser::IsSyntheticAccessor( 858 mir_graph->GetMethodLoweringInfo(invoke).GetTargetMethod())) { 859 return false; 860 } 861 } 862 863 if (object_is_this) { 864 // Mark invoke as NOP, null-check is done on IPUT. No aborts after this. 865 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); 866 } 867 868 MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result); 869 insn->dalvikInsn.opcode = opcode; 870 insn->dalvikInsn.vA = src_reg; 871 insn->dalvikInsn.vB = object_reg; 872 mir_graph->ComputeInlineIFieldLoweringInfo(data.field_idx, invoke, insn); 873 874 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).IsResolved()); 875 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).FastPut()); 876 DCHECK_EQ(data.field_offset, mir_graph->GetIFieldLoweringInfo(insn).FieldOffset().Uint32Value()); 877 DCHECK_EQ(data.is_volatile, mir_graph->GetIFieldLoweringInfo(insn).IsVolatile() ? 1u : 0u); 878 879 bb->InsertMIRAfter(invoke, insn); 880 881 if (move_result != nullptr) { 882 MIR* move = AllocReplacementMIR(mir_graph, invoke, move_result); 883 move->offset = move_result->offset; 884 if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT) { 885 move->dalvikInsn.opcode = Instruction::MOVE_FROM16; 886 } else if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { 887 move->dalvikInsn.opcode = Instruction::MOVE_OBJECT_FROM16; 888 } else { 889 DCHECK_EQ(move_result->dalvikInsn.opcode, Instruction::MOVE_RESULT_WIDE); 890 move->dalvikInsn.opcode = Instruction::MOVE_WIDE_FROM16; 891 } 892 move->dalvikInsn.vA = move_result->dalvikInsn.vA; 893 move->dalvikInsn.vB = return_reg; 894 bb->InsertMIRAfter(insn, move); 895 } 896 return true; 897 } 898 899 } // namespace art 900