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