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 
AllocReplacementMIR(MIRGraph * mir_graph,MIR * invoke,MIR * move_return)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 
GetInvokeReg(MIR * invoke,uint32_t arg)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 
WideArgIsInConsecutiveDalvikRegs(MIR * invoke,uint32_t arg)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 
DexFileMethodInliner()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 
~DexFileMethodInliner()404 DexFileMethodInliner::~DexFileMethodInliner() {
405 }
406 
AnalyseMethodCode(verifier::MethodVerifier * verifier)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 
IsIntrinsic(uint32_t method_index,InlineMethod * intrinsic)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 
GenIntrinsic(Mir2Lir * backend,CallInfo * info)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 
IsSpecial(uint32_t method_index)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 
GenSpecial(Mir2Lir * backend,uint32_t method_idx)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 
GenInline(MIRGraph * mir_graph,BasicBlock * bb,MIR * invoke,uint32_t method_idx)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 
FindClassIndex(const DexFile * dex_file,IndexCache * cache,ClassCacheIndex index)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 
FindNameIndex(const DexFile * dex_file,IndexCache * cache,NameCacheIndex index)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 
FindProtoIndex(const DexFile * dex_file,IndexCache * cache,ProtoCacheIndex index)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 
FindMethodIndex(const DexFile * dex_file,IndexCache * cache,const MethodDef & method_def)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 
IndexCache()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 
FindIntrinsics(const DexFile * dex_file)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 
AddInlineMethod(int32_t method_idx,const InlineMethod & method)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 
GenInlineConst(MIRGraph * mir_graph,BasicBlock * bb,MIR * invoke,MIR * move_result,const InlineMethod & method)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 
GenInlineReturnArg(MIRGraph * mir_graph,BasicBlock * bb,MIR * invoke,MIR * move_result,const InlineMethod & method)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 
GenInlineIGet(MIRGraph * mir_graph,BasicBlock * bb,MIR * invoke,MIR * move_result,const InlineMethod & method,uint32_t method_idx)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 
GenInlineIPut(MIRGraph * mir_graph,BasicBlock * bb,MIR * invoke,MIR * move_result,const InlineMethod & method,uint32_t method_idx)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