blob: 7fc6fa29c774ba92d47735e096b3056a5539c815 [file] [log] [blame]
Vladimir Marko5c96e6b2013-11-14 15:34:17 +00001/*
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
Vladimir Markoe3e02602014-03-12 15:42:41 +000017#include "dex_file_method_inliner.h"
18
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000019#include <algorithm>
Vladimir Markoe3e02602014-03-12 15:42:41 +000020
Andreas Gampe0b9203e2015-01-22 20:39:27 -080021#include "base/logging.h"
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000022#include "base/macros.h"
Vladimir Markoe13717e2013-11-20 12:44:55 +000023#include "base/mutex-inl.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080024#include "dex/compiler_ir.h"
Vladimir Markoe13717e2013-11-20 12:44:55 +000025#include "thread-inl.h"
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000026#include "dex/mir_graph.h"
Andreas Gampe53c913b2014-08-12 23:19:23 -070027#include "dex/quick/mir_to_lir.h"
Vladimir Marko5816ed42013-11-27 17:04:20 +000028#include "dex_instruction-inl.h"
Andreas Gampe53c913b2014-08-12 23:19:23 -070029#include "driver/dex_compilation_unit.h"
Vladimir Marko2bc47802014-02-10 09:43:07 +000030#include "verifier/method_verifier-inl.h"
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000031
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000032namespace art {
33
Vladimir Marko9820b7c2014-01-02 16:40:37 +000034namespace { // anonymous namespace
35
Vladimir Marko724c0fe2014-07-03 17:28:33 +010036static constexpr bool kIntrinsicIsStatic[] = {
37 true, // kIntrinsicDoubleCvt
38 true, // kIntrinsicFloatCvt
39 true, // kIntrinsicReverseBits
40 true, // kIntrinsicReverseBytes
Scott Wakeling611d3392015-07-10 11:42:06 +010041 true, // kIntrinsicNumberOfLeadingZeros
Vladimir Marko724c0fe2014-07-03 17:28:33 +010042 true, // kIntrinsicAbsInt
43 true, // kIntrinsicAbsLong
44 true, // kIntrinsicAbsFloat
45 true, // kIntrinsicAbsDouble
46 true, // kIntrinsicMinMaxInt
47 true, // kIntrinsicMinMaxLong
48 true, // kIntrinsicMinMaxFloat
49 true, // kIntrinsicMinMaxDouble
50 true, // kIntrinsicSqrt
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +010051 true, // kIntrinsicCeil
52 true, // kIntrinsicFloor
53 true, // kIntrinsicRint
54 true, // kIntrinsicRoundFloat
55 true, // kIntrinsicRoundDouble
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -070056 false, // kIntrinsicReferenceGetReferent
Vladimir Marko724c0fe2014-07-03 17:28:33 +010057 false, // kIntrinsicCharAt
58 false, // kIntrinsicCompareTo
Jeff Hao848f70a2014-01-15 13:49:50 -080059 false, // kIntrinsicGetCharsNoCheck
Vladimir Marko724c0fe2014-07-03 17:28:33 +010060 false, // kIntrinsicIsEmptyOrLength
61 false, // kIntrinsicIndexOf
Jeff Hao848f70a2014-01-15 13:49:50 -080062 true, // kIntrinsicNewStringFromBytes
63 true, // kIntrinsicNewStringFromChars
64 true, // kIntrinsicNewStringFromString
Vladimir Marko724c0fe2014-07-03 17:28:33 +010065 true, // kIntrinsicCurrentThread
66 true, // kIntrinsicPeek
67 true, // kIntrinsicPoke
68 false, // kIntrinsicCas
69 false, // kIntrinsicUnsafeGet
70 false, // kIntrinsicUnsafePut
Vladimir Marko460f4ef2014-07-08 17:34:04 +010071 true, // kIntrinsicSystemArrayCopyCharArray
Vladimir Marko724c0fe2014-07-03 17:28:33 +010072};
Andreas Gampe785d2f22014-11-03 22:57:30 -080073static_assert(arraysize(kIntrinsicIsStatic) == kInlineOpNop,
74 "arraysize of kIntrinsicIsStatic unexpected");
75static_assert(kIntrinsicIsStatic[kIntrinsicDoubleCvt], "DoubleCvt must be static");
76static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static");
77static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static");
78static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static");
Scott Wakeling611d3392015-07-10 11:42:06 +010079static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfLeadingZeros],
80 "NumberOfLeadingZeros must be static");
Andreas Gampe785d2f22014-11-03 22:57:30 -080081static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static");
82static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static");
83static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static");
84static_assert(kIntrinsicIsStatic[kIntrinsicAbsDouble], "AbsDouble must be static");
85static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxInt], "MinMaxInt must be static");
86static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxLong], "MinMaxLong_must_be_static");
87static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], "MinMaxFloat_must_be_static");
88static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], "MinMaxDouble_must_be_static");
89static_assert(kIntrinsicIsStatic[kIntrinsicSqrt], "Sqrt must be static");
90static_assert(kIntrinsicIsStatic[kIntrinsicCeil], "Ceil must be static");
91static_assert(kIntrinsicIsStatic[kIntrinsicFloor], "Floor must be static");
92static_assert(kIntrinsicIsStatic[kIntrinsicRint], "Rint must be static");
93static_assert(kIntrinsicIsStatic[kIntrinsicRoundFloat], "RoundFloat must be static");
94static_assert(kIntrinsicIsStatic[kIntrinsicRoundDouble], "RoundDouble must be static");
95static_assert(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], "Get must not be static");
96static_assert(!kIntrinsicIsStatic[kIntrinsicCharAt], "CharAt must not be static");
97static_assert(!kIntrinsicIsStatic[kIntrinsicCompareTo], "CompareTo must not be static");
Jeff Hao848f70a2014-01-15 13:49:50 -080098static_assert(!kIntrinsicIsStatic[kIntrinsicGetCharsNoCheck], "GetCharsNoCheck must not be static");
Andreas Gampe785d2f22014-11-03 22:57:30 -080099static_assert(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], "IsEmptyOrLength must not be static");
100static_assert(!kIntrinsicIsStatic[kIntrinsicIndexOf], "IndexOf must not be static");
Jeff Hao848f70a2014-01-15 13:49:50 -0800101static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromBytes],
102 "NewStringFromBytes must be static");
103static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromChars],
104 "NewStringFromChars must be static");
105static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromString],
106 "NewStringFromString must be static");
Andreas Gampe785d2f22014-11-03 22:57:30 -0800107static_assert(kIntrinsicIsStatic[kIntrinsicCurrentThread], "CurrentThread must be static");
108static_assert(kIntrinsicIsStatic[kIntrinsicPeek], "Peek must be static");
109static_assert(kIntrinsicIsStatic[kIntrinsicPoke], "Poke must be static");
110static_assert(!kIntrinsicIsStatic[kIntrinsicCas], "Cas must not be static");
111static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], "UnsafeGet_must_not_be_static");
112static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafePut], "UnsafePut must not be static");
113static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray],
114 "SystemArrayCopyCharArray must be static");
Vladimir Marko724c0fe2014-07-03 17:28:33 +0100115
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700116MIR* AllocReplacementMIR(MIRGraph* mir_graph, MIR* invoke) {
Jean Christophe Beyler3aa57732014-04-17 12:47:24 -0700117 MIR* insn = mir_graph->NewMIR();
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000118 insn->offset = invoke->offset;
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000119 insn->optimization_flags = MIR_CALLEE;
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000120 return insn;
121}
122
Vladimir Markob3e527b2014-04-04 12:37:07 +0100123uint32_t GetInvokeReg(MIR* invoke, uint32_t arg) {
124 DCHECK_LT(arg, invoke->dalvikInsn.vA);
Jean Christophe Beyler2ab40eb2014-06-02 09:03:14 -0700125 DCHECK(!MIR::DecodedInstruction::IsPseudoMirOp(invoke->dalvikInsn.opcode));
Vladimir Marko321b9872014-11-24 16:33:51 +0000126 if (IsInvokeInstructionRange(invoke->dalvikInsn.opcode)) {
127 return invoke->dalvikInsn.vC + arg; // Range invoke.
Vladimir Markob3e527b2014-04-04 12:37:07 +0100128 } else {
129 DCHECK_EQ(Instruction::FormatOf(invoke->dalvikInsn.opcode), Instruction::k35c);
Vladimir Marko321b9872014-11-24 16:33:51 +0000130 return invoke->dalvikInsn.arg[arg]; // Non-range invoke.
Vladimir Markob3e527b2014-04-04 12:37:07 +0100131 }
132}
133
134bool WideArgIsInConsecutiveDalvikRegs(MIR* invoke, uint32_t arg) {
135 DCHECK_LT(arg + 1, invoke->dalvikInsn.vA);
Jean Christophe Beyler2ab40eb2014-06-02 09:03:14 -0700136 DCHECK(!MIR::DecodedInstruction::IsPseudoMirOp(invoke->dalvikInsn.opcode));
Vladimir Marko321b9872014-11-24 16:33:51 +0000137 return IsInvokeInstructionRange(invoke->dalvikInsn.opcode) ||
Vladimir Markob3e527b2014-04-04 12:37:07 +0100138 invoke->dalvikInsn.arg[arg + 1u] == invoke->dalvikInsn.arg[arg] + 1u;
139}
140
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000141} // anonymous namespace
142
Mark Mendell45c11652013-12-11 12:27:35 -0800143const uint32_t DexFileMethodInliner::kIndexUnresolved;
Vladimir Marko5816ed42013-11-27 17:04:20 +0000144const char* const DexFileMethodInliner::kClassCacheNames[] = {
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000145 "Z", // kClassCacheBoolean
146 "B", // kClassCacheByte
147 "C", // kClassCacheChar
148 "S", // kClassCacheShort
149 "I", // kClassCacheInt
150 "J", // kClassCacheLong
151 "F", // kClassCacheFloat
152 "D", // kClassCacheDouble
153 "V", // kClassCacheVoid
Jeff Hao848f70a2014-01-15 13:49:50 -0800154 "[B", // kClassCacheJavaLangByteArray
155 "[C", // kClassCacheJavaLangCharArray
156 "[I", // kClassCacheJavaLangIntArray
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000157 "Ljava/lang/Object;", // kClassCacheJavaLangObject
Jeff Hao848f70a2014-01-15 13:49:50 -0800158 "Ljava/lang/ref/Reference;", // kClassCacheJavaLangRefReference
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000159 "Ljava/lang/String;", // kClassCacheJavaLangString
Jeff Hao848f70a2014-01-15 13:49:50 -0800160 "Ljava/lang/StringBuffer;", // kClassCacheJavaLangStringBuffer
161 "Ljava/lang/StringBuilder;", // kClassCacheJavaLangStringBuilder
162 "Ljava/lang/StringFactory;", // kClassCacheJavaLangStringFactory
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000163 "Ljava/lang/Double;", // kClassCacheJavaLangDouble
164 "Ljava/lang/Float;", // kClassCacheJavaLangFloat
165 "Ljava/lang/Integer;", // kClassCacheJavaLangInteger
166 "Ljava/lang/Long;", // kClassCacheJavaLangLong
167 "Ljava/lang/Short;", // kClassCacheJavaLangShort
168 "Ljava/lang/Math;", // kClassCacheJavaLangMath
169 "Ljava/lang/StrictMath;", // kClassCacheJavaLangStrictMath
170 "Ljava/lang/Thread;", // kClassCacheJavaLangThread
Jeff Hao848f70a2014-01-15 13:49:50 -0800171 "Ljava/nio/charset/Charset;", // kClassCacheJavaNioCharsetCharset
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000172 "Llibcore/io/Memory;", // kClassCacheLibcoreIoMemory
173 "Lsun/misc/Unsafe;", // kClassCacheSunMiscUnsafe
DaniilSokolov70c4f062014-06-24 17:34:00 -0700174 "Ljava/lang/System;", // kClassCacheJavaLangSystem
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000175};
176
Vladimir Marko5816ed42013-11-27 17:04:20 +0000177const char* const DexFileMethodInliner::kNameCacheNames[] = {
Serban Constantinescu23abec92014-07-02 16:13:38 +0100178 "reverse", // kNameCacheReverse
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000179 "reverseBytes", // kNameCacheReverseBytes
180 "doubleToRawLongBits", // kNameCacheDoubleToRawLongBits
181 "longBitsToDouble", // kNameCacheLongBitsToDouble
182 "floatToRawIntBits", // kNameCacheFloatToRawIntBits
183 "intBitsToFloat", // kNameCacheIntBitsToFloat
184 "abs", // kNameCacheAbs
185 "max", // kNameCacheMax
186 "min", // kNameCacheMin
187 "sqrt", // kNameCacheSqrt
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +0100188 "ceil", // kNameCacheCeil
189 "floor", // kNameCacheFloor
190 "rint", // kNameCacheRint
191 "round", // kNameCacheRound
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -0700192 "getReferent", // kNameCacheReferenceGet
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000193 "charAt", // kNameCacheCharAt
194 "compareTo", // kNameCacheCompareTo
Jeff Hao848f70a2014-01-15 13:49:50 -0800195 "getCharsNoCheck", // kNameCacheGetCharsNoCheck
Narayan Kamathba9ece92013-11-19 10:51:03 +0000196 "isEmpty", // kNameCacheIsEmpty
197 "indexOf", // kNameCacheIndexOf
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000198 "length", // kNameCacheLength
Jeff Hao848f70a2014-01-15 13:49:50 -0800199 "<init>", // kNameCacheInit
200 "newStringFromBytes", // kNameCacheNewStringFromBytes
201 "newStringFromChars", // kNameCacheNewStringFromChars
202 "newStringFromString", // kNameCacheNewStringFromString
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000203 "currentThread", // kNameCacheCurrentThread
204 "peekByte", // kNameCachePeekByte
205 "peekIntNative", // kNameCachePeekIntNative
206 "peekLongNative", // kNameCachePeekLongNative
207 "peekShortNative", // kNameCachePeekShortNative
208 "pokeByte", // kNameCachePokeByte
209 "pokeIntNative", // kNameCachePokeIntNative
210 "pokeLongNative", // kNameCachePokeLongNative
211 "pokeShortNative", // kNameCachePokeShortNative
212 "compareAndSwapInt", // kNameCacheCompareAndSwapInt
Vladimir Marko1c282e22013-11-21 14:49:47 +0000213 "compareAndSwapLong", // kNameCacheCompareAndSwapLong
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000214 "compareAndSwapObject", // kNameCacheCompareAndSwapObject
215 "getInt", // kNameCacheGetInt
216 "getIntVolatile", // kNameCacheGetIntVolatile
217 "putInt", // kNameCachePutInt
218 "putIntVolatile", // kNameCachePutIntVolatile
219 "putOrderedInt", // kNameCachePutOrderedInt
220 "getLong", // kNameCacheGetLong
221 "getLongVolatile", // kNameCacheGetLongVolatile
222 "putLong", // kNameCachePutLong
223 "putLongVolatile", // kNameCachePutLongVolatile
224 "putOrderedLong", // kNameCachePutOrderedLong
225 "getObject", // kNameCacheGetObject
226 "getObjectVolatile", // kNameCacheGetObjectVolatile
227 "putObject", // kNameCachePutObject
228 "putObjectVolatile", // kNameCachePutObjectVolatile
229 "putOrderedObject", // kNameCachePutOrderedObject
DaniilSokolov70c4f062014-06-24 17:34:00 -0700230 "arraycopy", // kNameCacheArrayCopy
Scott Wakeling611d3392015-07-10 11:42:06 +0100231 "numberOfLeadingZeros", // kNameCacheNumberOfLeadingZeros
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000232};
233
234const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
235 // kProtoCacheI_I
236 { kClassCacheInt, 1, { kClassCacheInt } },
237 // kProtoCacheJ_J
238 { kClassCacheLong, 1, { kClassCacheLong } },
239 // kProtoCacheS_S
240 { kClassCacheShort, 1, { kClassCacheShort } },
241 // kProtoCacheD_D
242 { kClassCacheDouble, 1, { kClassCacheDouble } },
Serban Constantinescu23abec92014-07-02 16:13:38 +0100243 // kProtoCacheDD_D
244 { kClassCacheDouble, 2, { kClassCacheDouble, kClassCacheDouble } },
Yixin Shoudbb17e32014-02-07 05:09:30 -0800245 // kProtoCacheF_F
246 { kClassCacheFloat, 1, { kClassCacheFloat } },
Serban Constantinescu23abec92014-07-02 16:13:38 +0100247 // kProtoCacheFF_F
248 { kClassCacheFloat, 2, { kClassCacheFloat, kClassCacheFloat } },
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000249 // kProtoCacheD_J
250 { kClassCacheLong, 1, { kClassCacheDouble } },
251 // kProtoCacheJ_D
252 { kClassCacheDouble, 1, { kClassCacheLong } },
253 // kProtoCacheF_I
254 { kClassCacheInt, 1, { kClassCacheFloat } },
255 // kProtoCacheI_F
256 { kClassCacheFloat, 1, { kClassCacheInt } },
257 // kProtoCacheII_I
258 { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } },
259 // kProtoCacheI_C
260 { kClassCacheChar, 1, { kClassCacheInt } },
261 // kProtoCacheString_I
262 { kClassCacheInt, 1, { kClassCacheJavaLangString } },
263 // kProtoCache_Z
264 { kClassCacheBoolean, 0, { } },
265 // kProtoCache_I
266 { kClassCacheInt, 0, { } },
Fred Shih4ee7a662014-07-11 09:59:27 -0700267 // kProtoCache_Object
268 { kClassCacheJavaLangObject, 0, { } },
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000269 // kProtoCache_Thread
270 { kClassCacheJavaLangThread, 0, { } },
271 // kProtoCacheJ_B
272 { kClassCacheByte, 1, { kClassCacheLong } },
273 // kProtoCacheJ_I
274 { kClassCacheInt, 1, { kClassCacheLong } },
275 // kProtoCacheJ_S
276 { kClassCacheShort, 1, { kClassCacheLong } },
277 // kProtoCacheJB_V
278 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } },
279 // kProtoCacheJI_V
280 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
Serban Constantinescu23abec92014-07-02 16:13:38 +0100281 // kProtoCacheJJ_J
282 { kClassCacheLong, 2, { kClassCacheLong, kClassCacheLong } },
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000283 // kProtoCacheJJ_V
284 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
285 // kProtoCacheJS_V
286 { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } },
287 // kProtoCacheObjectJII_Z
288 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
289 kClassCacheInt, kClassCacheInt } },
Vladimir Marko1c282e22013-11-21 14:49:47 +0000290 // kProtoCacheObjectJJJ_Z
291 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
292 kClassCacheLong, kClassCacheLong } },
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000293 // kProtoCacheObjectJObjectObject_Z
294 { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
295 kClassCacheJavaLangObject, kClassCacheJavaLangObject } },
296 // kProtoCacheObjectJ_I
297 { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
298 // kProtoCacheObjectJI_V
299 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
300 // kProtoCacheObjectJ_J
301 { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
302 // kProtoCacheObjectJJ_V
303 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
304 // kProtoCacheObjectJ_Object
305 { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
306 // kProtoCacheObjectJObject_V
307 { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong,
308 kClassCacheJavaLangObject } },
DaniilSokolov70c4f062014-06-24 17:34:00 -0700309 // kProtoCacheCharArrayICharArrayII_V
310 { kClassCacheVoid, 5, {kClassCacheJavaLangCharArray, kClassCacheInt,
Jeff Hao848f70a2014-01-15 13:49:50 -0800311 kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt} },
312 // kProtoCacheIICharArrayI_V
313 { kClassCacheVoid, 4, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray,
314 kClassCacheInt } },
315 // kProtoCacheByteArrayIII_String
316 { kClassCacheJavaLangString, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
317 kClassCacheInt } },
318 // kProtoCacheIICharArray_String
319 { kClassCacheJavaLangString, 3, { kClassCacheInt, kClassCacheInt,
320 kClassCacheJavaLangCharArray } },
321 // kProtoCacheString_String
322 { kClassCacheJavaLangString, 1, { kClassCacheJavaLangString } },
323 // kProtoCache_V
324 { kClassCacheVoid, 0, { } },
325 // kProtoCacheByteArray_V
326 { kClassCacheVoid, 1, { kClassCacheJavaLangByteArray } },
327 // kProtoCacheByteArrayI_V
328 { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheInt } },
329 // kProtoCacheByteArrayII_V
330 { kClassCacheVoid, 3, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt } },
331 // kProtoCacheByteArrayIII_V
332 { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
333 kClassCacheInt } },
334 // kProtoCacheByteArrayIIString_V
335 { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
336 kClassCacheJavaLangString } },
337 // kProtoCacheByteArrayString_V
338 { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaLangString } },
339 // kProtoCacheByteArrayIICharset_V
340 { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
341 kClassCacheJavaNioCharsetCharset } },
342 // kProtoCacheByteArrayCharset_V
343 { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaNioCharsetCharset } },
344 // kProtoCacheCharArray_V
345 { kClassCacheVoid, 1, { kClassCacheJavaLangCharArray } },
346 // kProtoCacheCharArrayII_V
347 { kClassCacheVoid, 3, { kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt } },
348 // kProtoCacheIICharArray_V
349 { kClassCacheVoid, 3, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray } },
350 // kProtoCacheIntArrayII_V
351 { kClassCacheVoid, 3, { kClassCacheJavaLangIntArray, kClassCacheInt, kClassCacheInt } },
352 // kProtoCacheString_V
353 { kClassCacheVoid, 1, { kClassCacheJavaLangString } },
354 // kProtoCacheStringBuffer_V
355 { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuffer } },
356 // kProtoCacheStringBuilder_V
357 { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuilder } },
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000358};
359
Vladimir Marko867a2b32013-12-10 13:01:13 +0000360const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
361#define INTRINSIC(c, n, p, o, d) \
Vladimir Marko2bc47802014-02-10 09:43:07 +0000362 { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } }
Vladimir Marko867a2b32013-12-10 13:01:13 +0000363
364 INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800365 INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, kIntrinsicFlagToFloatingPoint),
Vladimir Marko867a2b32013-12-10 13:01:13 +0000366 INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800367 INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, kIntrinsicFlagToFloatingPoint),
Vladimir Marko867a2b32013-12-10 13:01:13 +0000368
buzbee695d13a2014-04-19 13:32:20 -0700369 INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32),
370 INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64),
Vladimir Marko867a2b32013-12-10 13:01:13 +0000371 INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
Serban Constantinescu23abec92014-07-02 16:13:38 +0100372 INTRINSIC(JavaLangInteger, Reverse, I_I, kIntrinsicReverseBits, k32),
373 INTRINSIC(JavaLangLong, Reverse, J_J, kIntrinsicReverseBits, k64),
Vladimir Marko867a2b32013-12-10 13:01:13 +0000374
Scott Wakeling611d3392015-07-10 11:42:06 +0100375 INTRINSIC(JavaLangInteger, NumberOfLeadingZeros, I_I, kIntrinsicNumberOfLeadingZeros, k32),
376 INTRINSIC(JavaLangLong, NumberOfLeadingZeros, J_I, kIntrinsicNumberOfLeadingZeros, k64),
377
Vladimir Marko867a2b32013-12-10 13:01:13 +0000378 INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
379 INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
380 INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
381 INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
Yixin Shoudbb17e32014-02-07 05:09:30 -0800382 INTRINSIC(JavaLangMath, Abs, F_F, kIntrinsicAbsFloat, 0),
383 INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0),
384 INTRINSIC(JavaLangMath, Abs, D_D, kIntrinsicAbsDouble, 0),
385 INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0),
Vladimir Marko867a2b32013-12-10 13:01:13 +0000386 INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
387 INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
388 INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
389 INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
Serban Constantinescu23abec92014-07-02 16:13:38 +0100390 INTRINSIC(JavaLangMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin),
391 INTRINSIC(JavaLangStrictMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin),
392 INTRINSIC(JavaLangMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax),
393 INTRINSIC(JavaLangStrictMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax),
394 INTRINSIC(JavaLangMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin),
395 INTRINSIC(JavaLangStrictMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin),
396 INTRINSIC(JavaLangMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax),
397 INTRINSIC(JavaLangStrictMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax),
398 INTRINSIC(JavaLangMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin),
399 INTRINSIC(JavaLangStrictMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin),
400 INTRINSIC(JavaLangMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
401 INTRINSIC(JavaLangStrictMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
402
Vladimir Marko867a2b32013-12-10 13:01:13 +0000403 INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
404 INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
405
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +0100406 INTRINSIC(JavaLangMath, Ceil, D_D, kIntrinsicCeil, 0),
407 INTRINSIC(JavaLangStrictMath, Ceil, D_D, kIntrinsicCeil, 0),
408 INTRINSIC(JavaLangMath, Floor, D_D, kIntrinsicFloor, 0),
409 INTRINSIC(JavaLangStrictMath, Floor, D_D, kIntrinsicFloor, 0),
410 INTRINSIC(JavaLangMath, Rint, D_D, kIntrinsicRint, 0),
411 INTRINSIC(JavaLangStrictMath, Rint, D_D, kIntrinsicRint, 0),
412 INTRINSIC(JavaLangMath, Round, F_I, kIntrinsicRoundFloat, 0),
413 INTRINSIC(JavaLangStrictMath, Round, F_I, kIntrinsicRoundFloat, 0),
414 INTRINSIC(JavaLangMath, Round, D_J, kIntrinsicRoundDouble, 0),
415 INTRINSIC(JavaLangStrictMath, Round, D_J, kIntrinsicRoundDouble, 0),
416
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -0700417 INTRINSIC(JavaLangRefReference, ReferenceGetReferent, _Object, kIntrinsicReferenceGetReferent, 0),
Fred Shih4ee7a662014-07-11 09:59:27 -0700418
Vladimir Marko867a2b32013-12-10 13:01:13 +0000419 INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
420 INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
Jeff Hao848f70a2014-01-15 13:49:50 -0800421 INTRINSIC(JavaLangString, GetCharsNoCheck, IICharArrayI_V, kIntrinsicGetCharsNoCheck, 0),
Vladimir Marko867a2b32013-12-10 13:01:13 +0000422 INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
423 INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
424 INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
425 INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
426
427 INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
428
429 INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
buzbee695d13a2014-04-19 13:32:20 -0700430 INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, k32),
431 INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, k64),
Vladimir Marko867a2b32013-12-10 13:01:13 +0000432 INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
433 INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
buzbee695d13a2014-04-19 13:32:20 -0700434 INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, k32),
435 INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, k64),
Vladimir Marko867a2b32013-12-10 13:01:13 +0000436 INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
437
438 INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
439 kIntrinsicFlagNone),
440 INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
441 kIntrinsicFlagIsLong),
442 INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
443 kIntrinsicFlagIsObject),
444
445#define UNSAFE_GET_PUT(type, code, type_flags) \
446 INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
Vladimir Markofac10702015-04-22 11:51:52 +0100447 type_flags), \
Vladimir Marko867a2b32013-12-10 13:01:13 +0000448 INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
Vladimir Markofac10702015-04-22 11:51:52 +0100449 type_flags | kIntrinsicFlagIsVolatile), \
Vladimir Marko867a2b32013-12-10 13:01:13 +0000450 INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
451 type_flags), \
452 INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
453 type_flags | kIntrinsicFlagIsVolatile), \
454 INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
455 type_flags | kIntrinsicFlagIsOrdered)
456
457 UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
458 UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
459 UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
460#undef UNSAFE_GET_PUT
461
DaniilSokolov70c4f062014-06-24 17:34:00 -0700462 INTRINSIC(JavaLangSystem, ArrayCopy, CharArrayICharArrayII_V , kIntrinsicSystemArrayCopyCharArray,
463 0),
464
Vladimir Marko867a2b32013-12-10 13:01:13 +0000465#undef INTRINSIC
Jeff Hao848f70a2014-01-15 13:49:50 -0800466
467#define SPECIAL(c, n, p, o, d) \
468 { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineSpecial, { d } } }
469
470 SPECIAL(JavaLangString, Init, _V, kInlineStringInit, 0),
471 SPECIAL(JavaLangString, Init, ByteArray_V, kInlineStringInit, 1),
472 SPECIAL(JavaLangString, Init, ByteArrayI_V, kInlineStringInit, 2),
473 SPECIAL(JavaLangString, Init, ByteArrayII_V, kInlineStringInit, 3),
474 SPECIAL(JavaLangString, Init, ByteArrayIII_V, kInlineStringInit, 4),
475 SPECIAL(JavaLangString, Init, ByteArrayIIString_V, kInlineStringInit, 5),
476 SPECIAL(JavaLangString, Init, ByteArrayString_V, kInlineStringInit, 6),
477 SPECIAL(JavaLangString, Init, ByteArrayIICharset_V, kInlineStringInit, 7),
478 SPECIAL(JavaLangString, Init, ByteArrayCharset_V, kInlineStringInit, 8),
479 SPECIAL(JavaLangString, Init, CharArray_V, kInlineStringInit, 9),
480 SPECIAL(JavaLangString, Init, CharArrayII_V, kInlineStringInit, 10),
481 SPECIAL(JavaLangString, Init, IICharArray_V, kInlineStringInit, 11),
482 SPECIAL(JavaLangString, Init, IntArrayII_V, kInlineStringInit, 12),
483 SPECIAL(JavaLangString, Init, String_V, kInlineStringInit, 13),
484 SPECIAL(JavaLangString, Init, StringBuffer_V, kInlineStringInit, 14),
485 SPECIAL(JavaLangString, Init, StringBuilder_V, kInlineStringInit, 15),
486
487#undef SPECIAL
Vladimir Marko867a2b32013-12-10 13:01:13 +0000488};
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000489
490DexFileMethodInliner::DexFileMethodInliner()
Vladimir Markoe13717e2013-11-20 12:44:55 +0000491 : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock),
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700492 dex_file_(nullptr) {
Andreas Gampe785d2f22014-11-03 22:57:30 -0800493 static_assert(kClassCacheFirst == 0, "kClassCacheFirst not 0");
494 static_assert(arraysize(kClassCacheNames) == kClassCacheLast,
495 "bad arraysize for kClassCacheNames");
496 static_assert(kNameCacheFirst == 0, "kNameCacheFirst not 0");
497 static_assert(arraysize(kNameCacheNames) == kNameCacheLast,
498 "bad arraysize for kNameCacheNames");
499 static_assert(kProtoCacheFirst == 0, "kProtoCacheFirst not 0");
500 static_assert(arraysize(kProtoCacheDefs) == kProtoCacheLast,
501 "bad arraysize kProtoCacheNames");
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000502}
503
Vladimir Marko867a2b32013-12-10 13:01:13 +0000504DexFileMethodInliner::~DexFileMethodInliner() {
505}
506
Vladimir Marko2bc47802014-02-10 09:43:07 +0000507bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
Vladimir Marko84c072c2014-02-17 15:07:04 +0000508 InlineMethod method;
Vladimir Markoe3e02602014-03-12 15:42:41 +0000509 bool success = InlineMethodAnalyser::AnalyseMethodCode(verifier, &method);
Vladimir Marko84c072c2014-02-17 15:07:04 +0000510 return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
511}
512
Vladimir Marko87b7c522015-04-08 10:01:01 +0100513InlineMethodFlags DexFileMethodInliner::IsIntrinsicOrSpecial(uint32_t method_index) {
514 ReaderMutexLock mu(Thread::Current(), lock_);
515 auto it = inline_methods_.find(method_index);
516 if (it != inline_methods_.end()) {
517 DCHECK_NE(it->second.flags & (kInlineIntrinsic | kInlineSpecial), 0);
518 return it->second.flags;
519 } else {
520 return kNoInlineMethodFlags;
521 }
522}
523
Yixin Shou7071c8d2014-03-05 06:07:48 -0500524bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) {
Vladimir Markoe13717e2013-11-20 12:44:55 +0000525 ReaderMutexLock mu(Thread::Current(), lock_);
Vladimir Marko5816ed42013-11-27 17:04:20 +0000526 auto it = inline_methods_.find(method_index);
Yixin Shou7071c8d2014-03-05 06:07:48 -0500527 bool res = (it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0);
528 if (res && intrinsic != nullptr) {
529 *intrinsic = it->second;
530 }
531 return res;
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000532}
533
Vladimir Markoe13717e2013-11-20 12:44:55 +0000534bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
Vladimir Marko5816ed42013-11-27 17:04:20 +0000535 InlineMethod intrinsic;
Vladimir Markoe13717e2013-11-20 12:44:55 +0000536 {
537 ReaderMutexLock mu(Thread::Current(), lock_);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800538 auto it = inline_methods_.find(info->method_ref.dex_method_index);
Vladimir Marko5816ed42013-11-27 17:04:20 +0000539 if (it == inline_methods_.end() || (it->second.flags & kInlineIntrinsic) == 0) {
Vladimir Markoe13717e2013-11-20 12:44:55 +0000540 return false;
541 }
542 intrinsic = it->second;
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000543 }
Vladimir Marko724c0fe2014-07-03 17:28:33 +0100544 if (kIntrinsicIsStatic[intrinsic.opcode] != (info->type == kStatic)) {
545 // Invoke type mismatch.
546 return false;
547 }
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000548 switch (intrinsic.opcode) {
549 case kIntrinsicDoubleCvt:
550 return backend->GenInlinedDoubleCvt(info);
551 case kIntrinsicFloatCvt:
552 return backend->GenInlinedFloatCvt(info);
553 case kIntrinsicReverseBytes:
Vladimir Marko2bc47802014-02-10 09:43:07 +0000554 return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data));
Serban Constantinescu23abec92014-07-02 16:13:38 +0100555 case kIntrinsicReverseBits:
556 return backend->GenInlinedReverseBits(info, static_cast<OpSize>(intrinsic.d.data));
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000557 case kIntrinsicAbsInt:
558 return backend->GenInlinedAbsInt(info);
559 case kIntrinsicAbsLong:
560 return backend->GenInlinedAbsLong(info);
Yixin Shoudbb17e32014-02-07 05:09:30 -0800561 case kIntrinsicAbsFloat:
562 return backend->GenInlinedAbsFloat(info);
563 case kIntrinsicAbsDouble:
564 return backend->GenInlinedAbsDouble(info);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000565 case kIntrinsicMinMaxInt:
Serban Constantinescu23abec92014-07-02 16:13:38 +0100566 return backend->GenInlinedMinMax(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_long */);
567 case kIntrinsicMinMaxLong:
568 return backend->GenInlinedMinMax(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_long */);
569 case kIntrinsicMinMaxFloat:
570 return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_double */);
571 case kIntrinsicMinMaxDouble:
572 return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_double */);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000573 case kIntrinsicSqrt:
574 return backend->GenInlinedSqrt(info);
Serban Constantinescu2eba1fa2014-07-31 19:07:17 +0100575 case kIntrinsicCeil:
576 return backend->GenInlinedCeil(info);
577 case kIntrinsicFloor:
578 return backend->GenInlinedFloor(info);
579 case kIntrinsicRint:
580 return backend->GenInlinedRint(info);
581 case kIntrinsicRoundFloat:
582 return backend->GenInlinedRound(info, false /* is_double */);
583 case kIntrinsicRoundDouble:
584 return backend->GenInlinedRound(info, true /* is_double */);
Mathieu Chartiercd48f2d2014-09-09 13:51:09 -0700585 case kIntrinsicReferenceGetReferent:
586 return backend->GenInlinedReferenceGetReferent(info);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000587 case kIntrinsicCharAt:
588 return backend->GenInlinedCharAt(info);
589 case kIntrinsicCompareTo:
590 return backend->GenInlinedStringCompareTo(info);
Jeff Hao848f70a2014-01-15 13:49:50 -0800591 case kIntrinsicGetCharsNoCheck:
592 return backend->GenInlinedStringGetCharsNoCheck(info);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000593 case kIntrinsicIsEmptyOrLength:
Vladimir Marko2bc47802014-02-10 09:43:07 +0000594 return backend->GenInlinedStringIsEmptyOrLength(
595 info, intrinsic.d.data & kIntrinsicFlagIsEmpty);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000596 case kIntrinsicIndexOf:
Vladimir Marko2bc47802014-02-10 09:43:07 +0000597 return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0);
Jeff Hao848f70a2014-01-15 13:49:50 -0800598 case kIntrinsicNewStringFromBytes:
599 return backend->GenInlinedStringFactoryNewStringFromBytes(info);
600 case kIntrinsicNewStringFromChars:
601 return backend->GenInlinedStringFactoryNewStringFromChars(info);
602 case kIntrinsicNewStringFromString:
603 return backend->GenInlinedStringFactoryNewStringFromString(info);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000604 case kIntrinsicCurrentThread:
605 return backend->GenInlinedCurrentThread(info);
606 case kIntrinsicPeek:
Vladimir Marko2bc47802014-02-10 09:43:07 +0000607 return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data));
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000608 case kIntrinsicPoke:
Vladimir Marko2bc47802014-02-10 09:43:07 +0000609 return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data));
Vladimir Marko1c282e22013-11-21 14:49:47 +0000610 case kIntrinsicCas:
Vladimir Marko2bc47802014-02-10 09:43:07 +0000611 return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong,
612 intrinsic.d.data & kIntrinsicFlagIsObject);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000613 case kIntrinsicUnsafeGet:
Vladimir Marko2bc47802014-02-10 09:43:07 +0000614 return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong,
Vladimir Markofac10702015-04-22 11:51:52 +0100615 intrinsic.d.data & kIntrinsicFlagIsObject,
Vladimir Marko2bc47802014-02-10 09:43:07 +0000616 intrinsic.d.data & kIntrinsicFlagIsVolatile);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000617 case kIntrinsicUnsafePut:
Vladimir Marko2bc47802014-02-10 09:43:07 +0000618 return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong,
619 intrinsic.d.data & kIntrinsicFlagIsObject,
620 intrinsic.d.data & kIntrinsicFlagIsVolatile,
621 intrinsic.d.data & kIntrinsicFlagIsOrdered);
DaniilSokolov70c4f062014-06-24 17:34:00 -0700622 case kIntrinsicSystemArrayCopyCharArray:
623 return backend->GenInlinedArrayCopyCharArray(info);
Scott Wakeling611d3392015-07-10 11:42:06 +0100624 case kIntrinsicNumberOfLeadingZeros:
625 return false; // not implemented in quick
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000626 default:
627 LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
628 return false; // avoid warning "control reaches end of non-void function"
629 }
630}
631
Vladimir Marko5816ed42013-11-27 17:04:20 +0000632bool DexFileMethodInliner::IsSpecial(uint32_t method_index) {
633 ReaderMutexLock mu(Thread::Current(), lock_);
634 auto it = inline_methods_.find(method_index);
635 return it != inline_methods_.end() && (it->second.flags & kInlineSpecial) != 0;
636}
637
638bool DexFileMethodInliner::GenSpecial(Mir2Lir* backend, uint32_t method_idx) {
639 InlineMethod special;
640 {
641 ReaderMutexLock mu(Thread::Current(), lock_);
642 auto it = inline_methods_.find(method_idx);
643 if (it == inline_methods_.end() || (it->second.flags & kInlineSpecial) == 0) {
644 return false;
645 }
646 special = it->second;
647 }
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800648 return backend->SpecialMIR2LIR(special);
Vladimir Marko5816ed42013-11-27 17:04:20 +0000649}
650
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000651bool DexFileMethodInliner::GenInline(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
652 uint32_t method_idx) {
653 InlineMethod method;
654 {
655 ReaderMutexLock mu(Thread::Current(), lock_);
656 auto it = inline_methods_.find(method_idx);
657 if (it == inline_methods_.end() || (it->second.flags & kInlineSpecial) == 0) {
658 return false;
659 }
660 method = it->second;
661 }
662
663 MIR* move_result = nullptr;
664 bool result = true;
665 switch (method.opcode) {
666 case kInlineOpNop:
667 break;
668 case kInlineOpNonWideConst:
669 move_result = mir_graph->FindMoveResult(bb, invoke);
670 result = GenInlineConst(mir_graph, bb, invoke, move_result, method);
671 break;
672 case kInlineOpReturnArg:
673 move_result = mir_graph->FindMoveResult(bb, invoke);
674 result = GenInlineReturnArg(mir_graph, bb, invoke, move_result, method);
675 break;
676 case kInlineOpIGet:
677 move_result = mir_graph->FindMoveResult(bb, invoke);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700678 result = GenInlineIGet(mir_graph, bb, invoke, move_result, method);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000679 break;
680 case kInlineOpIPut:
Vladimir Markoe1fced12014-04-04 14:52:53 +0100681 move_result = mir_graph->FindMoveResult(bb, invoke);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700682 result = GenInlineIPut(mir_graph, bb, invoke, move_result, method);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000683 break;
Jeff Hao848f70a2014-01-15 13:49:50 -0800684 case kInlineStringInit:
685 return false;
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000686 default:
687 LOG(FATAL) << "Unexpected inline op: " << method.opcode;
Razvan A Lupusoru76423242014-08-04 09:38:46 -0700688 break;
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000689 }
690 if (result) {
Razvan A Lupusoru76423242014-08-04 09:38:46 -0700691 // If the invoke has not been eliminated yet, check now whether we should do it.
692 // This is done so that dataflow analysis does not get tripped up seeing nop invoke.
693 if (static_cast<int>(invoke->dalvikInsn.opcode) != kMirOpNop) {
Vladimir Marko321b9872014-11-24 16:33:51 +0000694 bool is_static = IsInstructionInvokeStatic(invoke->dalvikInsn.opcode);
Razvan A Lupusoru76423242014-08-04 09:38:46 -0700695 if (is_static || (invoke->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) {
696 // No null object register involved here so we can eliminate the invoke.
697 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
698 } else {
699 // Invoke was kept around because null check needed to be done.
700 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNullCheck);
701 // For invokes, the object register is in vC. For null check mir, it is in vA.
702 invoke->dalvikInsn.vA = invoke->dalvikInsn.vC;
703 }
704 }
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000705 if (move_result != nullptr) {
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000706 move_result->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
707 }
708 }
709 return result;
710}
711
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000712uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache,
713 ClassCacheIndex index) {
714 uint32_t* class_index = &cache->class_indexes[index];
715 if (*class_index != kIndexUnresolved) {
716 return *class_index;
717 }
718
719 const DexFile::StringId* string_id = dex_file->FindStringId(kClassCacheNames[index]);
720 if (string_id == nullptr) {
721 *class_index = kIndexNotFound;
722 return *class_index;
723 }
724 uint32_t string_index = dex_file->GetIndexForStringId(*string_id);
725
726 const DexFile::TypeId* type_id = dex_file->FindTypeId(string_index);
727 if (type_id == nullptr) {
728 *class_index = kIndexNotFound;
729 return *class_index;
730 }
731 *class_index = dex_file->GetIndexForTypeId(*type_id);
732 return *class_index;
733}
734
735uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache,
736 NameCacheIndex index) {
737 uint32_t* name_index = &cache->name_indexes[index];
738 if (*name_index != kIndexUnresolved) {
739 return *name_index;
740 }
741
742 const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]);
743 if (string_id == nullptr) {
744 *name_index = kIndexNotFound;
745 return *name_index;
746 }
747 *name_index = dex_file->GetIndexForStringId(*string_id);
748 return *name_index;
749}
750
751uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
752 ProtoCacheIndex index) {
753 uint32_t* proto_index = &cache->proto_indexes[index];
754 if (*proto_index != kIndexUnresolved) {
755 return *proto_index;
756 }
757
758 const ProtoDef& proto_def = kProtoCacheDefs[index];
759 uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type);
760 if (return_index == kIndexNotFound) {
761 *proto_index = kIndexNotFound;
762 return *proto_index;
763 }
764 uint16_t return_type = static_cast<uint16_t>(return_index);
765 DCHECK_EQ(static_cast<uint32_t>(return_type), return_index);
766
767 uint32_t signature_length = proto_def.param_count;
768 uint16_t signature_type_idxs[kProtoMaxParams];
769 for (uint32_t i = 0; i != signature_length; ++i) {
770 uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]);
771 if (param_index == kIndexNotFound) {
772 *proto_index = kIndexNotFound;
773 return *proto_index;
774 }
775 signature_type_idxs[i] = static_cast<uint16_t>(param_index);
776 DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index);
777 }
778
779 const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs,
780 signature_length);
781 if (proto_id == nullptr) {
782 *proto_index = kIndexNotFound;
783 return *proto_index;
784 }
785 *proto_index = dex_file->GetIndexForProtoId(*proto_id);
786 return *proto_index;
787}
788
789uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
790 const MethodDef& method_def) {
791 uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class);
792 if (declaring_class_index == kIndexNotFound) {
793 return kIndexNotFound;
794 }
795 uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name);
796 if (name_index == kIndexNotFound) {
797 return kIndexNotFound;
798 }
799 uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto);
800 if (proto_index == kIndexNotFound) {
801 return kIndexNotFound;
802 }
803 const DexFile::MethodId* method_id =
804 dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index),
805 dex_file->GetStringId(name_index),
806 dex_file->GetProtoId(proto_index));
807 if (method_id == nullptr) {
808 return kIndexNotFound;
809 }
810 return dex_file->GetIndexForMethodId(*method_id);
811}
812
813DexFileMethodInliner::IndexCache::IndexCache() {
814 std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved);
815 std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved);
816 std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
817}
818
Vladimir Marko867a2b32013-12-10 13:01:13 +0000819void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000820 DCHECK(dex_file != nullptr);
821 DCHECK(dex_file_ == nullptr);
Vladimir Marko867a2b32013-12-10 13:01:13 +0000822 IndexCache cache;
823 for (const IntrinsicDef& def : kIntrinsicMethods) {
Vladimir Marko5816ed42013-11-27 17:04:20 +0000824 uint32_t method_idx = FindMethodIndex(dex_file, &cache, def.method_def);
825 if (method_idx != kIndexNotFound) {
826 DCHECK(inline_methods_.find(method_idx) == inline_methods_.end());
Ian Rogersdce164a2014-01-02 17:00:38 -0800827 inline_methods_.Put(method_idx, def.intrinsic);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000828 }
829 }
830 dex_file_ = dex_file;
831}
832
Vladimir Marko2bc47802014-02-10 09:43:07 +0000833bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) {
Vladimir Marko5816ed42013-11-27 17:04:20 +0000834 WriterMutexLock mu(Thread::Current(), lock_);
Ian Rogersdce164a2014-01-02 17:00:38 -0800835 if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) {
Vladimir Marko2bc47802014-02-10 09:43:07 +0000836 inline_methods_.Put(method_idx, method);
Vladimir Marko5816ed42013-11-27 17:04:20 +0000837 return true;
838 } else {
Ian Rogersdce164a2014-01-02 17:00:38 -0800839 if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") {
840 // TODO: String.length is both kIntrinsicIsEmptyOrLength and kInlineOpIGet.
841 } else {
Mathieu Chartier71ef0442015-02-25 17:17:37 -0800842 LOG(WARNING) << "Inliner: " << PrettyMethod(method_idx, *dex_file_) << " already inline";
Ian Rogersdce164a2014-01-02 17:00:38 -0800843 }
Vladimir Marko5816ed42013-11-27 17:04:20 +0000844 return false;
845 }
846}
847
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000848bool DexFileMethodInliner::GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
849 MIR* move_result, const InlineMethod& method) {
850 if (move_result == nullptr) {
851 // Result is unused.
852 return true;
853 }
854
855 // Check the opcode and for MOVE_RESULT_OBJECT check also that the constant is null.
856 DCHECK(move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT ||
857 (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT &&
858 method.d.data == 0u));
859
860 // Insert the CONST instruction.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700861 MIR* insn = AllocReplacementMIR(mir_graph, invoke);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000862 insn->dalvikInsn.opcode = Instruction::CONST;
863 insn->dalvikInsn.vA = move_result->dalvikInsn.vA;
864 insn->dalvikInsn.vB = method.d.data;
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000865 insn->meta.method_lowering_info = invoke->meta.method_lowering_info; // Preserve type info.
Jean Christophe Beylercdacac42014-03-13 14:54:59 -0700866 bb->InsertMIRAfter(move_result, insn);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000867 return true;
868}
869
870bool DexFileMethodInliner::GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
871 MIR* move_result, const InlineMethod& method) {
872 if (move_result == nullptr) {
873 // Result is unused.
874 return true;
875 }
876
877 // Select opcode and argument.
878 const InlineReturnArgData& data = method.d.return_data;
879 Instruction::Code opcode = Instruction::MOVE_FROM16;
Vladimir Markob3e527b2014-04-04 12:37:07 +0100880 uint32_t arg = GetInvokeReg(invoke, data.arg);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000881 if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
882 DCHECK_EQ(data.is_object, 1u);
Vladimir Markob3e527b2014-04-04 12:37:07 +0100883 DCHECK_EQ(data.is_wide, 0u);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000884 opcode = Instruction::MOVE_OBJECT_FROM16;
885 } else if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE) {
886 DCHECK_EQ(data.is_wide, 1u);
Vladimir Markob3e527b2014-04-04 12:37:07 +0100887 DCHECK_EQ(data.is_object, 0u);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000888 opcode = Instruction::MOVE_WIDE_FROM16;
Vladimir Markob3e527b2014-04-04 12:37:07 +0100889 if (!WideArgIsInConsecutiveDalvikRegs(invoke, data.arg)) {
890 // The two halfs of the source value are not in consecutive dalvik registers in INVOKE.
891 return false;
892 }
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000893 } else {
894 DCHECK(move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT);
895 DCHECK_EQ(data.is_wide, 0u);
896 DCHECK_EQ(data.is_object, 0u);
897 }
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000898
899 // Insert the move instruction
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700900 MIR* insn = AllocReplacementMIR(mir_graph, invoke);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000901 insn->dalvikInsn.opcode = opcode;
902 insn->dalvikInsn.vA = move_result->dalvikInsn.vA;
903 insn->dalvikInsn.vB = arg;
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000904 insn->meta.method_lowering_info = invoke->meta.method_lowering_info; // Preserve type info.
Jean Christophe Beylercdacac42014-03-13 14:54:59 -0700905 bb->InsertMIRAfter(move_result, insn);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000906 return true;
907}
908
909bool DexFileMethodInliner::GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700910 MIR* move_result, const InlineMethod& method) {
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000911 CompilationUnit* cu = mir_graph->GetCurrentDexCompilationUnit()->GetCompilationUnit();
912 if (cu->enable_debug & (1 << kDebugSlowFieldPath)) {
913 return false;
914 }
915
916 const InlineIGetIPutData& data = method.d.ifield_data;
Vladimir Markob3e527b2014-04-04 12:37:07 +0100917 Instruction::Code opcode = static_cast<Instruction::Code>(Instruction::IGET + data.op_variant);
918 DCHECK_EQ(InlineMethodAnalyser::IGetVariant(opcode), data.op_variant);
919 uint32_t object_reg = GetInvokeReg(invoke, data.object_arg);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000920
921 if (move_result == nullptr) {
922 // Result is unused. If volatile, we still need to emit the IGET but we have no destination.
923 return !data.is_volatile;
924 }
925
Vladimir Marko321b9872014-11-24 16:33:51 +0000926 DCHECK_EQ(data.method_is_static != 0u, IsInstructionInvokeStatic(invoke->dalvikInsn.opcode));
Vladimir Markob3e527b2014-04-04 12:37:07 +0100927 bool object_is_this = (data.method_is_static == 0u && data.object_arg == 0u);
928 if (!object_is_this) {
929 // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE).
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100930 // Allow synthetic accessors. We don't care about losing their stack frame in NPE.
931 if (!InlineMethodAnalyser::IsSyntheticAccessor(
932 mir_graph->GetMethodLoweringInfo(invoke).GetTargetMethod())) {
933 return false;
934 }
Vladimir Markob3e527b2014-04-04 12:37:07 +0100935 }
936
937 if (object_is_this) {
938 // Mark invoke as NOP, null-check is done on IGET. No aborts after this.
939 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
940 }
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000941
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700942 MIR* insn = AllocReplacementMIR(mir_graph, invoke);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000943 insn->offset = invoke->offset;
944 insn->dalvikInsn.opcode = opcode;
945 insn->dalvikInsn.vA = move_result->dalvikInsn.vA;
Vladimir Markob3e527b2014-04-04 12:37:07 +0100946 insn->dalvikInsn.vB = object_reg;
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000947 mir_graph->ComputeInlineIFieldLoweringInfo(data.field_idx, invoke, insn);
948
949 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).IsResolved());
950 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).FastGet());
951 DCHECK_EQ(data.field_offset, mir_graph->GetIFieldLoweringInfo(insn).FieldOffset().Uint32Value());
952 DCHECK_EQ(data.is_volatile, mir_graph->GetIFieldLoweringInfo(insn).IsVolatile() ? 1u : 0u);
953
Jean Christophe Beylercdacac42014-03-13 14:54:59 -0700954 bb->InsertMIRAfter(move_result, insn);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000955 return true;
956}
957
958bool DexFileMethodInliner::GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700959 MIR* move_result, const InlineMethod& method) {
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000960 CompilationUnit* cu = mir_graph->GetCurrentDexCompilationUnit()->GetCompilationUnit();
961 if (cu->enable_debug & (1 << kDebugSlowFieldPath)) {
962 return false;
963 }
964
965 const InlineIGetIPutData& data = method.d.ifield_data;
Vladimir Markob3e527b2014-04-04 12:37:07 +0100966 Instruction::Code opcode = static_cast<Instruction::Code>(Instruction::IPUT + data.op_variant);
967 DCHECK_EQ(InlineMethodAnalyser::IPutVariant(opcode), data.op_variant);
968 uint32_t object_reg = GetInvokeReg(invoke, data.object_arg);
969 uint32_t src_reg = GetInvokeReg(invoke, data.src_arg);
Vladimir Markoe1fced12014-04-04 14:52:53 +0100970 uint32_t return_reg =
971 data.return_arg_plus1 != 0u ? GetInvokeReg(invoke, data.return_arg_plus1 - 1u) : 0u;
Vladimir Markob3e527b2014-04-04 12:37:07 +0100972
973 if (opcode == Instruction::IPUT_WIDE && !WideArgIsInConsecutiveDalvikRegs(invoke, data.src_arg)) {
974 // The two halfs of the source value are not in consecutive dalvik registers in INVOKE.
975 return false;
976 }
977
Vladimir Markoe1fced12014-04-04 14:52:53 +0100978 DCHECK(move_result == nullptr || data.return_arg_plus1 != 0u);
979 if (move_result != nullptr && move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE &&
980 !WideArgIsInConsecutiveDalvikRegs(invoke, data.return_arg_plus1 - 1u)) {
981 // The two halfs of the return value are not in consecutive dalvik registers in INVOKE.
982 return false;
983 }
984
Vladimir Marko321b9872014-11-24 16:33:51 +0000985 DCHECK_EQ(data.method_is_static != 0u, IsInstructionInvokeStatic(invoke->dalvikInsn.opcode));
Vladimir Markob3e527b2014-04-04 12:37:07 +0100986 bool object_is_this = (data.method_is_static == 0u && data.object_arg == 0u);
987 if (!object_is_this) {
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000988 // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE).
Vladimir Markoc8f60a62014-04-02 15:24:05 +0100989 // Allow synthetic accessors. We don't care about losing their stack frame in NPE.
990 if (!InlineMethodAnalyser::IsSyntheticAccessor(
991 mir_graph->GetMethodLoweringInfo(invoke).GetTargetMethod())) {
992 return false;
993 }
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000994 }
995
Vladimir Markob3e527b2014-04-04 12:37:07 +0100996 if (object_is_this) {
997 // Mark invoke as NOP, null-check is done on IPUT. No aborts after this.
998 invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
999 }
Vladimir Marko9820b7c2014-01-02 16:40:37 +00001000
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001001 MIR* insn = AllocReplacementMIR(mir_graph, invoke);
Vladimir Marko9820b7c2014-01-02 16:40:37 +00001002 insn->dalvikInsn.opcode = opcode;
Vladimir Markob3e527b2014-04-04 12:37:07 +01001003 insn->dalvikInsn.vA = src_reg;
1004 insn->dalvikInsn.vB = object_reg;
Vladimir Marko9820b7c2014-01-02 16:40:37 +00001005 mir_graph->ComputeInlineIFieldLoweringInfo(data.field_idx, invoke, insn);
1006
1007 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).IsResolved());
1008 DCHECK(mir_graph->GetIFieldLoweringInfo(insn).FastPut());
1009 DCHECK_EQ(data.field_offset, mir_graph->GetIFieldLoweringInfo(insn).FieldOffset().Uint32Value());
1010 DCHECK_EQ(data.is_volatile, mir_graph->GetIFieldLoweringInfo(insn).IsVolatile() ? 1u : 0u);
1011
Jean Christophe Beylercdacac42014-03-13 14:54:59 -07001012 bb->InsertMIRAfter(invoke, insn);
Vladimir Markoe1fced12014-04-04 14:52:53 +01001013
1014 if (move_result != nullptr) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001015 MIR* move = AllocReplacementMIR(mir_graph, invoke);
Vladimir Markoe1fced12014-04-04 14:52:53 +01001016 move->offset = move_result->offset;
Vladimir Markoe1fced12014-04-04 14:52:53 +01001017 if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT) {
1018 move->dalvikInsn.opcode = Instruction::MOVE_FROM16;
1019 } else if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
1020 move->dalvikInsn.opcode = Instruction::MOVE_OBJECT_FROM16;
1021 } else {
1022 DCHECK_EQ(move_result->dalvikInsn.opcode, Instruction::MOVE_RESULT_WIDE);
1023 move->dalvikInsn.opcode = Instruction::MOVE_WIDE_FROM16;
1024 }
1025 move->dalvikInsn.vA = move_result->dalvikInsn.vA;
1026 move->dalvikInsn.vB = return_reg;
Vladimir Markoc91df2d2015-04-23 09:29:21 +00001027 move->meta.method_lowering_info = invoke->meta.method_lowering_info; // Preserve type info.
Vladimir Markoe1fced12014-04-04 14:52:53 +01001028 bb->InsertMIRAfter(insn, move);
1029 }
Vladimir Marko9820b7c2014-01-02 16:40:37 +00001030 return true;
1031}
1032
Jeff Hao848f70a2014-01-15 13:49:50 -08001033uint32_t DexFileMethodInliner::GetOffsetForStringInit(uint32_t method_index, size_t pointer_size) {
1034 ReaderMutexLock mu(Thread::Current(), lock_);
1035 auto it = inline_methods_.find(method_index);
1036 if (it != inline_methods_.end() && (it->second.opcode == kInlineStringInit)) {
1037 uint32_t string_init_base_offset = Thread::QuickEntryPointOffsetWithSize(
1038 OFFSETOF_MEMBER(QuickEntryPoints, pNewEmptyString), pointer_size);
1039 return string_init_base_offset + it->second.d.data * pointer_size;
1040 }
1041 return 0;
1042}
1043
1044bool DexFileMethodInliner::IsStringInitMethodIndex(uint32_t method_index) {
1045 ReaderMutexLock mu(Thread::Current(), lock_);
1046 auto it = inline_methods_.find(method_index);
1047 return (it != inline_methods_.end()) && (it->second.opcode == kInlineStringInit);
1048}
1049
Vladimir Marko5c96e6b2013-11-14 15:34:17 +00001050} // namespace art