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