dex_file_method_inliner.cc revision c91df2d6339dd4adf2da582372451df19ce2ff44
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/logging.h" 22#include "base/macros.h" 23#include "base/mutex-inl.h" 24#include "dex/compiler_ir.h" 25#include "thread-inl.h" 26#include "dex/mir_graph.h" 27#include "dex/quick/mir_to_lir.h" 28#include "dex_instruction-inl.h" 29#include "driver/dex_compilation_unit.h" 30#include "verifier/method_verifier-inl.h" 31 32namespace art { 33 34namespace { // anonymous namespace 35 36static constexpr bool kIntrinsicIsStatic[] = { 37 true, // kIntrinsicDoubleCvt 38 true, // kIntrinsicFloatCvt 39 true, // kIntrinsicReverseBits 40 true, // kIntrinsicReverseBytes 41 true, // kIntrinsicAbsInt 42 true, // kIntrinsicAbsLong 43 true, // kIntrinsicAbsFloat 44 true, // kIntrinsicAbsDouble 45 true, // kIntrinsicMinMaxInt 46 true, // kIntrinsicMinMaxLong 47 true, // kIntrinsicMinMaxFloat 48 true, // kIntrinsicMinMaxDouble 49 true, // kIntrinsicSqrt 50 true, // kIntrinsicCeil 51 true, // kIntrinsicFloor 52 true, // kIntrinsicRint 53 true, // kIntrinsicRoundFloat 54 true, // kIntrinsicRoundDouble 55 false, // kIntrinsicReferenceGetReferent 56 false, // kIntrinsicCharAt 57 false, // kIntrinsicCompareTo 58 false, // kIntrinsicIsEmptyOrLength 59 false, // kIntrinsicIndexOf 60 true, // kIntrinsicCurrentThread 61 true, // kIntrinsicPeek 62 true, // kIntrinsicPoke 63 false, // kIntrinsicCas 64 false, // kIntrinsicUnsafeGet 65 false, // kIntrinsicUnsafePut 66 true, // kIntrinsicSystemArrayCopyCharArray 67}; 68static_assert(arraysize(kIntrinsicIsStatic) == kInlineOpNop, 69 "arraysize of kIntrinsicIsStatic unexpected"); 70static_assert(kIntrinsicIsStatic[kIntrinsicDoubleCvt], "DoubleCvt must be static"); 71static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static"); 72static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static"); 73static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static"); 74static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static"); 75static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static"); 76static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static"); 77static_assert(kIntrinsicIsStatic[kIntrinsicAbsDouble], "AbsDouble must be static"); 78static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxInt], "MinMaxInt must be static"); 79static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxLong], "MinMaxLong_must_be_static"); 80static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], "MinMaxFloat_must_be_static"); 81static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], "MinMaxDouble_must_be_static"); 82static_assert(kIntrinsicIsStatic[kIntrinsicSqrt], "Sqrt must be static"); 83static_assert(kIntrinsicIsStatic[kIntrinsicCeil], "Ceil must be static"); 84static_assert(kIntrinsicIsStatic[kIntrinsicFloor], "Floor must be static"); 85static_assert(kIntrinsicIsStatic[kIntrinsicRint], "Rint must be static"); 86static_assert(kIntrinsicIsStatic[kIntrinsicRoundFloat], "RoundFloat must be static"); 87static_assert(kIntrinsicIsStatic[kIntrinsicRoundDouble], "RoundDouble must be static"); 88static_assert(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], "Get must not be static"); 89static_assert(!kIntrinsicIsStatic[kIntrinsicCharAt], "CharAt must not be static"); 90static_assert(!kIntrinsicIsStatic[kIntrinsicCompareTo], "CompareTo must not be static"); 91static_assert(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], "IsEmptyOrLength must not be static"); 92static_assert(!kIntrinsicIsStatic[kIntrinsicIndexOf], "IndexOf must not be static"); 93static_assert(kIntrinsicIsStatic[kIntrinsicCurrentThread], "CurrentThread must be static"); 94static_assert(kIntrinsicIsStatic[kIntrinsicPeek], "Peek must be static"); 95static_assert(kIntrinsicIsStatic[kIntrinsicPoke], "Poke must be static"); 96static_assert(!kIntrinsicIsStatic[kIntrinsicCas], "Cas must not be static"); 97static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], "UnsafeGet_must_not_be_static"); 98static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafePut], "UnsafePut must not be static"); 99static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray], 100 "SystemArrayCopyCharArray must be static"); 101 102MIR* AllocReplacementMIR(MIRGraph* mir_graph, MIR* invoke) { 103 MIR* insn = mir_graph->NewMIR(); 104 insn->offset = invoke->offset; 105 insn->optimization_flags = MIR_CALLEE; 106 return insn; 107} 108 109uint32_t GetInvokeReg(MIR* invoke, uint32_t arg) { 110 DCHECK_LT(arg, invoke->dalvikInsn.vA); 111 DCHECK(!MIR::DecodedInstruction::IsPseudoMirOp(invoke->dalvikInsn.opcode)); 112 if (IsInvokeInstructionRange(invoke->dalvikInsn.opcode)) { 113 return invoke->dalvikInsn.vC + arg; // Range invoke. 114 } else { 115 DCHECK_EQ(Instruction::FormatOf(invoke->dalvikInsn.opcode), Instruction::k35c); 116 return invoke->dalvikInsn.arg[arg]; // Non-range invoke. 117 } 118} 119 120bool WideArgIsInConsecutiveDalvikRegs(MIR* invoke, uint32_t arg) { 121 DCHECK_LT(arg + 1, invoke->dalvikInsn.vA); 122 DCHECK(!MIR::DecodedInstruction::IsPseudoMirOp(invoke->dalvikInsn.opcode)); 123 return IsInvokeInstructionRange(invoke->dalvikInsn.opcode) || 124 invoke->dalvikInsn.arg[arg + 1u] == invoke->dalvikInsn.arg[arg] + 1u; 125} 126 127} // anonymous namespace 128 129const uint32_t DexFileMethodInliner::kIndexUnresolved; 130const 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 157const 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 208const 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 288const 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, kIntrinsicFlagToFloatingPoint), 294 INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), 295 INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, kIntrinsicFlagToFloatingPoint), 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), \ 372 INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ 373 type_flags | kIntrinsicFlagIsVolatile), \ 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 393DexFileMethodInliner::DexFileMethodInliner() 394 : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock), 395 dex_file_(nullptr) { 396 static_assert(kClassCacheFirst == 0, "kClassCacheFirst not 0"); 397 static_assert(arraysize(kClassCacheNames) == kClassCacheLast, 398 "bad arraysize for kClassCacheNames"); 399 static_assert(kNameCacheFirst == 0, "kNameCacheFirst not 0"); 400 static_assert(arraysize(kNameCacheNames) == kNameCacheLast, 401 "bad arraysize for kNameCacheNames"); 402 static_assert(kProtoCacheFirst == 0, "kProtoCacheFirst not 0"); 403 static_assert(arraysize(kProtoCacheDefs) == kProtoCacheLast, 404 "bad arraysize kProtoCacheNames"); 405} 406 407DexFileMethodInliner::~DexFileMethodInliner() { 408} 409 410bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) { 411 InlineMethod method; 412 bool success = InlineMethodAnalyser::AnalyseMethodCode(verifier, &method); 413 return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method); 414} 415 416InlineMethodFlags DexFileMethodInliner::IsIntrinsicOrSpecial(uint32_t method_index) { 417 ReaderMutexLock mu(Thread::Current(), lock_); 418 auto it = inline_methods_.find(method_index); 419 if (it != inline_methods_.end()) { 420 DCHECK_NE(it->second.flags & (kInlineIntrinsic | kInlineSpecial), 0); 421 return it->second.flags; 422 } else { 423 return kNoInlineMethodFlags; 424 } 425} 426 427bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) { 428 ReaderMutexLock mu(Thread::Current(), lock_); 429 auto it = inline_methods_.find(method_index); 430 bool res = (it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0); 431 if (res && intrinsic != nullptr) { 432 *intrinsic = it->second; 433 } 434 return res; 435} 436 437bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { 438 InlineMethod intrinsic; 439 { 440 ReaderMutexLock mu(Thread::Current(), lock_); 441 auto it = inline_methods_.find(info->method_ref.dex_method_index); 442 if (it == inline_methods_.end() || (it->second.flags & kInlineIntrinsic) == 0) { 443 return false; 444 } 445 intrinsic = it->second; 446 } 447 if (kIntrinsicIsStatic[intrinsic.opcode] != (info->type == kStatic)) { 448 // Invoke type mismatch. 449 return false; 450 } 451 switch (intrinsic.opcode) { 452 case kIntrinsicDoubleCvt: 453 return backend->GenInlinedDoubleCvt(info); 454 case kIntrinsicFloatCvt: 455 return backend->GenInlinedFloatCvt(info); 456 case kIntrinsicReverseBytes: 457 return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data)); 458 case kIntrinsicReverseBits: 459 return backend->GenInlinedReverseBits(info, static_cast<OpSize>(intrinsic.d.data)); 460 case kIntrinsicAbsInt: 461 return backend->GenInlinedAbsInt(info); 462 case kIntrinsicAbsLong: 463 return backend->GenInlinedAbsLong(info); 464 case kIntrinsicAbsFloat: 465 return backend->GenInlinedAbsFloat(info); 466 case kIntrinsicAbsDouble: 467 return backend->GenInlinedAbsDouble(info); 468 case kIntrinsicMinMaxInt: 469 return backend->GenInlinedMinMax(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_long */); 470 case kIntrinsicMinMaxLong: 471 return backend->GenInlinedMinMax(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_long */); 472 case kIntrinsicMinMaxFloat: 473 return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_double */); 474 case kIntrinsicMinMaxDouble: 475 return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_double */); 476 case kIntrinsicSqrt: 477 return backend->GenInlinedSqrt(info); 478 case kIntrinsicCeil: 479 return backend->GenInlinedCeil(info); 480 case kIntrinsicFloor: 481 return backend->GenInlinedFloor(info); 482 case kIntrinsicRint: 483 return backend->GenInlinedRint(info); 484 case kIntrinsicRoundFloat: 485 return backend->GenInlinedRound(info, false /* is_double */); 486 case kIntrinsicRoundDouble: 487 return backend->GenInlinedRound(info, true /* is_double */); 488 case kIntrinsicReferenceGetReferent: 489 return backend->GenInlinedReferenceGetReferent(info); 490 case kIntrinsicCharAt: 491 return backend->GenInlinedCharAt(info); 492 case kIntrinsicCompareTo: 493 return backend->GenInlinedStringCompareTo(info); 494 case kIntrinsicIsEmptyOrLength: 495 return backend->GenInlinedStringIsEmptyOrLength( 496 info, intrinsic.d.data & kIntrinsicFlagIsEmpty); 497 case kIntrinsicIndexOf: 498 return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0); 499 case kIntrinsicCurrentThread: 500 return backend->GenInlinedCurrentThread(info); 501 case kIntrinsicPeek: 502 return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data)); 503 case kIntrinsicPoke: 504 return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data)); 505 case kIntrinsicCas: 506 return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong, 507 intrinsic.d.data & kIntrinsicFlagIsObject); 508 case kIntrinsicUnsafeGet: 509 return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong, 510 intrinsic.d.data & kIntrinsicFlagIsObject, 511 intrinsic.d.data & kIntrinsicFlagIsVolatile); 512 case kIntrinsicUnsafePut: 513 return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong, 514 intrinsic.d.data & kIntrinsicFlagIsObject, 515 intrinsic.d.data & kIntrinsicFlagIsVolatile, 516 intrinsic.d.data & kIntrinsicFlagIsOrdered); 517 case kIntrinsicSystemArrayCopyCharArray: 518 return backend->GenInlinedArrayCopyCharArray(info); 519 default: 520 LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode; 521 return false; // avoid warning "control reaches end of non-void function" 522 } 523} 524 525bool DexFileMethodInliner::IsSpecial(uint32_t method_index) { 526 ReaderMutexLock mu(Thread::Current(), lock_); 527 auto it = inline_methods_.find(method_index); 528 return it != inline_methods_.end() && (it->second.flags & kInlineSpecial) != 0; 529} 530 531bool DexFileMethodInliner::GenSpecial(Mir2Lir* backend, uint32_t method_idx) { 532 InlineMethod special; 533 { 534 ReaderMutexLock mu(Thread::Current(), lock_); 535 auto it = inline_methods_.find(method_idx); 536 if (it == inline_methods_.end() || (it->second.flags & kInlineSpecial) == 0) { 537 return false; 538 } 539 special = it->second; 540 } 541 return backend->SpecialMIR2LIR(special); 542} 543 544bool DexFileMethodInliner::GenInline(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 545 uint32_t method_idx) { 546 InlineMethod method; 547 { 548 ReaderMutexLock mu(Thread::Current(), lock_); 549 auto it = inline_methods_.find(method_idx); 550 if (it == inline_methods_.end() || (it->second.flags & kInlineSpecial) == 0) { 551 return false; 552 } 553 method = it->second; 554 } 555 556 MIR* move_result = nullptr; 557 bool result = true; 558 switch (method.opcode) { 559 case kInlineOpNop: 560 break; 561 case kInlineOpNonWideConst: 562 move_result = mir_graph->FindMoveResult(bb, invoke); 563 result = GenInlineConst(mir_graph, bb, invoke, move_result, method); 564 break; 565 case kInlineOpReturnArg: 566 move_result = mir_graph->FindMoveResult(bb, invoke); 567 result = GenInlineReturnArg(mir_graph, bb, invoke, move_result, method); 568 break; 569 case kInlineOpIGet: 570 move_result = mir_graph->FindMoveResult(bb, invoke); 571 result = GenInlineIGet(mir_graph, bb, invoke, move_result, method); 572 break; 573 case kInlineOpIPut: 574 move_result = mir_graph->FindMoveResult(bb, invoke); 575 result = GenInlineIPut(mir_graph, bb, invoke, move_result, method); 576 break; 577 default: 578 LOG(FATAL) << "Unexpected inline op: " << method.opcode; 579 break; 580 } 581 if (result) { 582 // If the invoke has not been eliminated yet, check now whether we should do it. 583 // This is done so that dataflow analysis does not get tripped up seeing nop invoke. 584 if (static_cast<int>(invoke->dalvikInsn.opcode) != kMirOpNop) { 585 bool is_static = IsInstructionInvokeStatic(invoke->dalvikInsn.opcode); 586 if (is_static || (invoke->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) { 587 // No null object register involved here so we can eliminate the invoke. 588 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); 589 } else { 590 // Invoke was kept around because null check needed to be done. 591 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNullCheck); 592 // For invokes, the object register is in vC. For null check mir, it is in vA. 593 invoke->dalvikInsn.vA = invoke->dalvikInsn.vC; 594 } 595 } 596 if (move_result != nullptr) { 597 move_result->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); 598 } 599 } 600 return result; 601} 602 603uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache, 604 ClassCacheIndex index) { 605 uint32_t* class_index = &cache->class_indexes[index]; 606 if (*class_index != kIndexUnresolved) { 607 return *class_index; 608 } 609 610 const DexFile::StringId* string_id = dex_file->FindStringId(kClassCacheNames[index]); 611 if (string_id == nullptr) { 612 *class_index = kIndexNotFound; 613 return *class_index; 614 } 615 uint32_t string_index = dex_file->GetIndexForStringId(*string_id); 616 617 const DexFile::TypeId* type_id = dex_file->FindTypeId(string_index); 618 if (type_id == nullptr) { 619 *class_index = kIndexNotFound; 620 return *class_index; 621 } 622 *class_index = dex_file->GetIndexForTypeId(*type_id); 623 return *class_index; 624} 625 626uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache, 627 NameCacheIndex index) { 628 uint32_t* name_index = &cache->name_indexes[index]; 629 if (*name_index != kIndexUnresolved) { 630 return *name_index; 631 } 632 633 const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]); 634 if (string_id == nullptr) { 635 *name_index = kIndexNotFound; 636 return *name_index; 637 } 638 *name_index = dex_file->GetIndexForStringId(*string_id); 639 return *name_index; 640} 641 642uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache, 643 ProtoCacheIndex index) { 644 uint32_t* proto_index = &cache->proto_indexes[index]; 645 if (*proto_index != kIndexUnresolved) { 646 return *proto_index; 647 } 648 649 const ProtoDef& proto_def = kProtoCacheDefs[index]; 650 uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type); 651 if (return_index == kIndexNotFound) { 652 *proto_index = kIndexNotFound; 653 return *proto_index; 654 } 655 uint16_t return_type = static_cast<uint16_t>(return_index); 656 DCHECK_EQ(static_cast<uint32_t>(return_type), return_index); 657 658 uint32_t signature_length = proto_def.param_count; 659 uint16_t signature_type_idxs[kProtoMaxParams]; 660 for (uint32_t i = 0; i != signature_length; ++i) { 661 uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]); 662 if (param_index == kIndexNotFound) { 663 *proto_index = kIndexNotFound; 664 return *proto_index; 665 } 666 signature_type_idxs[i] = static_cast<uint16_t>(param_index); 667 DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index); 668 } 669 670 const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs, 671 signature_length); 672 if (proto_id == nullptr) { 673 *proto_index = kIndexNotFound; 674 return *proto_index; 675 } 676 *proto_index = dex_file->GetIndexForProtoId(*proto_id); 677 return *proto_index; 678} 679 680uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache, 681 const MethodDef& method_def) { 682 uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class); 683 if (declaring_class_index == kIndexNotFound) { 684 return kIndexNotFound; 685 } 686 uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name); 687 if (name_index == kIndexNotFound) { 688 return kIndexNotFound; 689 } 690 uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto); 691 if (proto_index == kIndexNotFound) { 692 return kIndexNotFound; 693 } 694 const DexFile::MethodId* method_id = 695 dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index), 696 dex_file->GetStringId(name_index), 697 dex_file->GetProtoId(proto_index)); 698 if (method_id == nullptr) { 699 return kIndexNotFound; 700 } 701 return dex_file->GetIndexForMethodId(*method_id); 702} 703 704DexFileMethodInliner::IndexCache::IndexCache() { 705 std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved); 706 std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved); 707 std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved); 708} 709 710void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { 711 DCHECK(dex_file != nullptr); 712 DCHECK(dex_file_ == nullptr); 713 IndexCache cache; 714 for (const IntrinsicDef& def : kIntrinsicMethods) { 715 uint32_t method_idx = FindMethodIndex(dex_file, &cache, def.method_def); 716 if (method_idx != kIndexNotFound) { 717 DCHECK(inline_methods_.find(method_idx) == inline_methods_.end()); 718 inline_methods_.Put(method_idx, def.intrinsic); 719 } 720 } 721 dex_file_ = dex_file; 722} 723 724bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) { 725 WriterMutexLock mu(Thread::Current(), lock_); 726 if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) { 727 inline_methods_.Put(method_idx, method); 728 return true; 729 } else { 730 if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") { 731 // TODO: String.length is both kIntrinsicIsEmptyOrLength and kInlineOpIGet. 732 } else { 733 LOG(WARNING) << "Inliner: " << PrettyMethod(method_idx, *dex_file_) << " already inline"; 734 } 735 return false; 736 } 737} 738 739bool DexFileMethodInliner::GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 740 MIR* move_result, const InlineMethod& method) { 741 if (move_result == nullptr) { 742 // Result is unused. 743 return true; 744 } 745 746 // Check the opcode and for MOVE_RESULT_OBJECT check also that the constant is null. 747 DCHECK(move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT || 748 (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT && 749 method.d.data == 0u)); 750 751 // Insert the CONST instruction. 752 MIR* insn = AllocReplacementMIR(mir_graph, invoke); 753 insn->dalvikInsn.opcode = Instruction::CONST; 754 insn->dalvikInsn.vA = move_result->dalvikInsn.vA; 755 insn->dalvikInsn.vB = method.d.data; 756 insn->meta.method_lowering_info = invoke->meta.method_lowering_info; // Preserve type info. 757 bb->InsertMIRAfter(move_result, insn); 758 return true; 759} 760 761bool DexFileMethodInliner::GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 762 MIR* move_result, const InlineMethod& method) { 763 if (move_result == nullptr) { 764 // Result is unused. 765 return true; 766 } 767 768 // Select opcode and argument. 769 const InlineReturnArgData& data = method.d.return_data; 770 Instruction::Code opcode = Instruction::MOVE_FROM16; 771 uint32_t arg = GetInvokeReg(invoke, data.arg); 772 if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { 773 DCHECK_EQ(data.is_object, 1u); 774 DCHECK_EQ(data.is_wide, 0u); 775 opcode = Instruction::MOVE_OBJECT_FROM16; 776 } else if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE) { 777 DCHECK_EQ(data.is_wide, 1u); 778 DCHECK_EQ(data.is_object, 0u); 779 opcode = Instruction::MOVE_WIDE_FROM16; 780 if (!WideArgIsInConsecutiveDalvikRegs(invoke, data.arg)) { 781 // The two halfs of the source value are not in consecutive dalvik registers in INVOKE. 782 return false; 783 } 784 } else { 785 DCHECK(move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT); 786 DCHECK_EQ(data.is_wide, 0u); 787 DCHECK_EQ(data.is_object, 0u); 788 } 789 790 // Insert the move instruction 791 MIR* insn = AllocReplacementMIR(mir_graph, invoke); 792 insn->dalvikInsn.opcode = opcode; 793 insn->dalvikInsn.vA = move_result->dalvikInsn.vA; 794 insn->dalvikInsn.vB = arg; 795 insn->meta.method_lowering_info = invoke->meta.method_lowering_info; // Preserve type info. 796 bb->InsertMIRAfter(move_result, insn); 797 return true; 798} 799 800bool DexFileMethodInliner::GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 801 MIR* move_result, const InlineMethod& method) { 802 CompilationUnit* cu = mir_graph->GetCurrentDexCompilationUnit()->GetCompilationUnit(); 803 if (cu->enable_debug & (1 << kDebugSlowFieldPath)) { 804 return false; 805 } 806 807 const InlineIGetIPutData& data = method.d.ifield_data; 808 Instruction::Code opcode = static_cast<Instruction::Code>(Instruction::IGET + data.op_variant); 809 DCHECK_EQ(InlineMethodAnalyser::IGetVariant(opcode), data.op_variant); 810 uint32_t object_reg = GetInvokeReg(invoke, data.object_arg); 811 812 if (move_result == nullptr) { 813 // Result is unused. If volatile, we still need to emit the IGET but we have no destination. 814 return !data.is_volatile; 815 } 816 817 DCHECK_EQ(data.method_is_static != 0u, IsInstructionInvokeStatic(invoke->dalvikInsn.opcode)); 818 bool object_is_this = (data.method_is_static == 0u && data.object_arg == 0u); 819 if (!object_is_this) { 820 // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE). 821 // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 822 if (!InlineMethodAnalyser::IsSyntheticAccessor( 823 mir_graph->GetMethodLoweringInfo(invoke).GetTargetMethod())) { 824 return false; 825 } 826 } 827 828 if (object_is_this) { 829 // Mark invoke as NOP, null-check is done on IGET. No aborts after this. 830 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); 831 } 832 833 MIR* insn = AllocReplacementMIR(mir_graph, invoke); 834 insn->offset = invoke->offset; 835 insn->dalvikInsn.opcode = opcode; 836 insn->dalvikInsn.vA = move_result->dalvikInsn.vA; 837 insn->dalvikInsn.vB = object_reg; 838 mir_graph->ComputeInlineIFieldLoweringInfo(data.field_idx, invoke, insn); 839 840 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).IsResolved()); 841 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).FastGet()); 842 DCHECK_EQ(data.field_offset, mir_graph->GetIFieldLoweringInfo(insn).FieldOffset().Uint32Value()); 843 DCHECK_EQ(data.is_volatile, mir_graph->GetIFieldLoweringInfo(insn).IsVolatile() ? 1u : 0u); 844 845 bb->InsertMIRAfter(move_result, insn); 846 return true; 847} 848 849bool DexFileMethodInliner::GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, 850 MIR* move_result, const InlineMethod& method) { 851 CompilationUnit* cu = mir_graph->GetCurrentDexCompilationUnit()->GetCompilationUnit(); 852 if (cu->enable_debug & (1 << kDebugSlowFieldPath)) { 853 return false; 854 } 855 856 const InlineIGetIPutData& data = method.d.ifield_data; 857 Instruction::Code opcode = static_cast<Instruction::Code>(Instruction::IPUT + data.op_variant); 858 DCHECK_EQ(InlineMethodAnalyser::IPutVariant(opcode), data.op_variant); 859 uint32_t object_reg = GetInvokeReg(invoke, data.object_arg); 860 uint32_t src_reg = GetInvokeReg(invoke, data.src_arg); 861 uint32_t return_reg = 862 data.return_arg_plus1 != 0u ? GetInvokeReg(invoke, data.return_arg_plus1 - 1u) : 0u; 863 864 if (opcode == Instruction::IPUT_WIDE && !WideArgIsInConsecutiveDalvikRegs(invoke, data.src_arg)) { 865 // The two halfs of the source value are not in consecutive dalvik registers in INVOKE. 866 return false; 867 } 868 869 DCHECK(move_result == nullptr || data.return_arg_plus1 != 0u); 870 if (move_result != nullptr && move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE && 871 !WideArgIsInConsecutiveDalvikRegs(invoke, data.return_arg_plus1 - 1u)) { 872 // The two halfs of the return value are not in consecutive dalvik registers in INVOKE. 873 return false; 874 } 875 876 DCHECK_EQ(data.method_is_static != 0u, IsInstructionInvokeStatic(invoke->dalvikInsn.opcode)); 877 bool object_is_this = (data.method_is_static == 0u && data.object_arg == 0u); 878 if (!object_is_this) { 879 // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE). 880 // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 881 if (!InlineMethodAnalyser::IsSyntheticAccessor( 882 mir_graph->GetMethodLoweringInfo(invoke).GetTargetMethod())) { 883 return false; 884 } 885 } 886 887 if (object_is_this) { 888 // Mark invoke as NOP, null-check is done on IPUT. No aborts after this. 889 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); 890 } 891 892 MIR* insn = AllocReplacementMIR(mir_graph, invoke); 893 insn->dalvikInsn.opcode = opcode; 894 insn->dalvikInsn.vA = src_reg; 895 insn->dalvikInsn.vB = object_reg; 896 mir_graph->ComputeInlineIFieldLoweringInfo(data.field_idx, invoke, insn); 897 898 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).IsResolved()); 899 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).FastPut()); 900 DCHECK_EQ(data.field_offset, mir_graph->GetIFieldLoweringInfo(insn).FieldOffset().Uint32Value()); 901 DCHECK_EQ(data.is_volatile, mir_graph->GetIFieldLoweringInfo(insn).IsVolatile() ? 1u : 0u); 902 903 bb->InsertMIRAfter(invoke, insn); 904 905 if (move_result != nullptr) { 906 MIR* move = AllocReplacementMIR(mir_graph, invoke); 907 move->offset = move_result->offset; 908 if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT) { 909 move->dalvikInsn.opcode = Instruction::MOVE_FROM16; 910 } else if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) { 911 move->dalvikInsn.opcode = Instruction::MOVE_OBJECT_FROM16; 912 } else { 913 DCHECK_EQ(move_result->dalvikInsn.opcode, Instruction::MOVE_RESULT_WIDE); 914 move->dalvikInsn.opcode = Instruction::MOVE_WIDE_FROM16; 915 } 916 move->dalvikInsn.vA = move_result->dalvikInsn.vA; 917 move->dalvikInsn.vB = return_reg; 918 move->meta.method_lowering_info = invoke->meta.method_lowering_info; // Preserve type info. 919 bb->InsertMIRAfter(insn, move); 920 } 921 return true; 922} 923 924} // namespace art 925