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