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