Home | History | Annotate | Download | only in quick
      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