blob: 5caf0778581573e1b4e567e54db7025f3b09b5df [file] [log] [blame]
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001/*
2 * Copyright (C) 2015 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 "intrinsics.h"
18
Andreas Gampebfb5ba92015-09-01 15:45:02 +000019#include "art_method.h"
20#include "class_linker.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080021#include "dex/quick/dex_file_method_inliner.h"
22#include "dex/quick/dex_file_to_method_inliner_map.h"
23#include "driver/compiler_driver.h"
24#include "invoke_type.h"
Andreas Gampebfb5ba92015-09-01 15:45:02 +000025#include "mirror/dex_cache-inl.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080026#include "nodes.h"
27#include "quick/inline_method_analyser.h"
Andreas Gampebfb5ba92015-09-01 15:45:02 +000028#include "scoped_thread_state_change.h"
29#include "thread-inl.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010030#include "utils.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080031
32namespace art {
33
34// Function that returns whether an intrinsic is static/direct or virtual.
35static inline InvokeType GetIntrinsicInvokeType(Intrinsics i) {
36 switch (i) {
37 case Intrinsics::kNone:
38 return kInterface; // Non-sensical for intrinsic.
Aart Bik5d75afe2015-12-14 11:57:01 -080039#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
40 case Intrinsics::k ## Name: \
Andreas Gampe71fb52f2014-12-29 17:43:08 -080041 return IsStatic;
42#include "intrinsics_list.h"
43INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
44#undef INTRINSICS_LIST
45#undef OPTIMIZING_INTRINSICS
46 }
47 return kInterface;
48}
49
agicsaki57b81ec2015-08-11 17:39:37 -070050// Function that returns whether an intrinsic needs an environment or not.
Agi Csaki05f20562015-08-19 14:58:14 -070051static inline IntrinsicNeedsEnvironmentOrCache NeedsEnvironmentOrCache(Intrinsics i) {
agicsaki57b81ec2015-08-11 17:39:37 -070052 switch (i) {
53 case Intrinsics::kNone:
Agi Csaki05f20562015-08-19 14:58:14 -070054 return kNeedsEnvironmentOrCache; // Non-sensical for intrinsic.
Aart Bik5d75afe2015-12-14 11:57:01 -080055#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
56 case Intrinsics::k ## Name: \
Agi Csaki05f20562015-08-19 14:58:14 -070057 return NeedsEnvironmentOrCache;
agicsaki57b81ec2015-08-11 17:39:37 -070058#include "intrinsics_list.h"
59INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
60#undef INTRINSICS_LIST
61#undef OPTIMIZING_INTRINSICS
62 }
Agi Csaki05f20562015-08-19 14:58:14 -070063 return kNeedsEnvironmentOrCache;
agicsaki57b81ec2015-08-11 17:39:37 -070064}
Andreas Gampe71fb52f2014-12-29 17:43:08 -080065
Aart Bik5d75afe2015-12-14 11:57:01 -080066// Function that returns whether an intrinsic has side effects.
67static inline IntrinsicSideEffects GetSideEffects(Intrinsics i) {
68 switch (i) {
69 case Intrinsics::kNone:
70 return kAllSideEffects;
71#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
72 case Intrinsics::k ## Name: \
73 return SideEffects;
74#include "intrinsics_list.h"
75INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
76#undef INTRINSICS_LIST
77#undef OPTIMIZING_INTRINSICS
78 }
79 return kAllSideEffects;
80}
81
82// Function that returns whether an intrinsic can throw exceptions.
83static inline IntrinsicExceptions GetExceptions(Intrinsics i) {
84 switch (i) {
85 case Intrinsics::kNone:
86 return kCanThrow;
87#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
88 case Intrinsics::k ## Name: \
89 return Exceptions;
90#include "intrinsics_list.h"
91INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
92#undef INTRINSICS_LIST
93#undef OPTIMIZING_INTRINSICS
94 }
95 return kCanThrow;
96}
97
Andreas Gampe71fb52f2014-12-29 17:43:08 -080098static Primitive::Type GetType(uint64_t data, bool is_op_size) {
99 if (is_op_size) {
100 switch (static_cast<OpSize>(data)) {
101 case kSignedByte:
Andreas Gampe878d58c2015-01-15 23:24:00 -0800102 return Primitive::kPrimByte;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800103 case kSignedHalf:
Andreas Gampe878d58c2015-01-15 23:24:00 -0800104 return Primitive::kPrimShort;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800105 case k32:
Andreas Gampe878d58c2015-01-15 23:24:00 -0800106 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800107 case k64:
Andreas Gampe878d58c2015-01-15 23:24:00 -0800108 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800109 default:
110 LOG(FATAL) << "Unknown/unsupported op size " << data;
111 UNREACHABLE();
112 }
113 } else {
114 if ((data & kIntrinsicFlagIsLong) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800115 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800116 }
117 if ((data & kIntrinsicFlagIsObject) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800118 return Primitive::kPrimNot;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800119 }
Andreas Gampe878d58c2015-01-15 23:24:00 -0800120 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800121 }
122}
123
Chris Larsen16ba2b42015-11-02 10:58:31 -0800124static Intrinsics GetIntrinsic(InlineMethod method) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800125 switch (method.opcode) {
126 // Floating-point conversions.
127 case kIntrinsicDoubleCvt:
128 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
129 Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
130 case kIntrinsicFloatCvt:
131 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
132 Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
133
134 // Bit manipulations.
135 case kIntrinsicReverseBits:
136 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800137 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800138 return Intrinsics::kIntegerReverse;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800139 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800140 return Intrinsics::kLongReverse;
141 default:
142 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
143 UNREACHABLE();
144 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800145 case kIntrinsicReverseBytes:
146 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800147 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800148 return Intrinsics::kShortReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800149 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800150 return Intrinsics::kIntegerReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800151 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800152 return Intrinsics::kLongReverseBytes;
153 default:
154 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
155 UNREACHABLE();
156 }
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100157 case kIntrinsicRotateRight:
158 switch (GetType(method.d.data, true)) {
159 case Primitive::kPrimInt:
160 return Intrinsics::kIntegerRotateRight;
161 case Primitive::kPrimLong:
162 return Intrinsics::kLongRotateRight;
163 default:
164 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
165 UNREACHABLE();
166 }
167 case kIntrinsicRotateLeft:
168 switch (GetType(method.d.data, true)) {
169 case Primitive::kPrimInt:
170 return Intrinsics::kIntegerRotateLeft;
171 case Primitive::kPrimLong:
172 return Intrinsics::kLongRotateLeft;
173 default:
174 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
175 UNREACHABLE();
176 }
177
178 // Misc data processing.
Aart Bik3f67e692016-01-15 14:35:12 -0800179 case kIntrinsicBitCount:
180 switch (GetType(method.d.data, true)) {
181 case Primitive::kPrimInt:
182 return Intrinsics::kIntegerBitCount;
183 case Primitive::kPrimLong:
184 return Intrinsics::kLongBitCount;
185 default:
186 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
187 UNREACHABLE();
188 }
Scott Wakeling611d3392015-07-10 11:42:06 +0100189 case kIntrinsicNumberOfLeadingZeros:
190 switch (GetType(method.d.data, true)) {
191 case Primitive::kPrimInt:
192 return Intrinsics::kIntegerNumberOfLeadingZeros;
193 case Primitive::kPrimLong:
194 return Intrinsics::kLongNumberOfLeadingZeros;
195 default:
196 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
197 UNREACHABLE();
198 }
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100199 case kIntrinsicNumberOfTrailingZeros:
200 switch (GetType(method.d.data, true)) {
201 case Primitive::kPrimInt:
202 return Intrinsics::kIntegerNumberOfTrailingZeros;
203 case Primitive::kPrimLong:
204 return Intrinsics::kLongNumberOfTrailingZeros;
205 default:
206 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
207 UNREACHABLE();
208 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800209
210 // Abs.
211 case kIntrinsicAbsDouble:
212 return Intrinsics::kMathAbsDouble;
213 case kIntrinsicAbsFloat:
214 return Intrinsics::kMathAbsFloat;
215 case kIntrinsicAbsInt:
216 return Intrinsics::kMathAbsInt;
217 case kIntrinsicAbsLong:
218 return Intrinsics::kMathAbsLong;
219
220 // Min/max.
221 case kIntrinsicMinMaxDouble:
222 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
223 Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
224 case kIntrinsicMinMaxFloat:
225 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
226 Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
227 case kIntrinsicMinMaxInt:
228 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
229 Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
230 case kIntrinsicMinMaxLong:
231 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
232 Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
233
Mark Mendella4f12202015-08-06 15:23:34 -0400234 // More math builtins.
235 case kIntrinsicCos:
236 return Intrinsics::kMathCos;
237 case kIntrinsicSin:
238 return Intrinsics::kMathSin;
239 case kIntrinsicAcos:
240 return Intrinsics::kMathAcos;
241 case kIntrinsicAsin:
242 return Intrinsics::kMathAsin;
243 case kIntrinsicAtan:
244 return Intrinsics::kMathAtan;
245 case kIntrinsicAtan2:
246 return Intrinsics::kMathAtan2;
247 case kIntrinsicCbrt:
248 return Intrinsics::kMathCbrt;
249 case kIntrinsicCosh:
250 return Intrinsics::kMathCosh;
251 case kIntrinsicExp:
252 return Intrinsics::kMathExp;
253 case kIntrinsicExpm1:
254 return Intrinsics::kMathExpm1;
255 case kIntrinsicHypot:
256 return Intrinsics::kMathHypot;
257 case kIntrinsicLog:
258 return Intrinsics::kMathLog;
259 case kIntrinsicLog10:
260 return Intrinsics::kMathLog10;
261 case kIntrinsicNextAfter:
262 return Intrinsics::kMathNextAfter;
263 case kIntrinsicSinh:
264 return Intrinsics::kMathSinh;
265 case kIntrinsicTan:
266 return Intrinsics::kMathTan;
267 case kIntrinsicTanh:
268 return Intrinsics::kMathTanh;
269
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800270 // Misc math.
271 case kIntrinsicSqrt:
272 return Intrinsics::kMathSqrt;
273 case kIntrinsicCeil:
274 return Intrinsics::kMathCeil;
275 case kIntrinsicFloor:
276 return Intrinsics::kMathFloor;
277 case kIntrinsicRint:
278 return Intrinsics::kMathRint;
279 case kIntrinsicRoundDouble:
280 return Intrinsics::kMathRoundDouble;
281 case kIntrinsicRoundFloat:
282 return Intrinsics::kMathRoundFloat;
283
284 // System.arraycopy.
285 case kIntrinsicSystemArrayCopyCharArray:
286 return Intrinsics::kSystemArrayCopyChar;
287
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +0100288 case kIntrinsicSystemArrayCopy:
289 return Intrinsics::kSystemArrayCopy;
290
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800291 // Thread.currentThread.
292 case kIntrinsicCurrentThread:
Aart Bik5d75afe2015-12-14 11:57:01 -0800293 return Intrinsics::kThreadCurrentThread;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800294
295 // Memory.peek.
296 case kIntrinsicPeek:
297 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800298 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800299 return Intrinsics::kMemoryPeekByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800300 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800301 return Intrinsics::kMemoryPeekShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800302 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800303 return Intrinsics::kMemoryPeekIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800304 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800305 return Intrinsics::kMemoryPeekLongNative;
306 default:
307 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
308 UNREACHABLE();
309 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800310
311 // Memory.poke.
312 case kIntrinsicPoke:
313 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800314 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800315 return Intrinsics::kMemoryPokeByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800316 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800317 return Intrinsics::kMemoryPokeShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800318 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800319 return Intrinsics::kMemoryPokeIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800320 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800321 return Intrinsics::kMemoryPokeLongNative;
322 default:
323 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
324 UNREACHABLE();
325 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800326
327 // String.
328 case kIntrinsicCharAt:
329 return Intrinsics::kStringCharAt;
330 case kIntrinsicCompareTo:
331 return Intrinsics::kStringCompareTo;
agicsaki7da072f2015-08-12 20:30:17 -0700332 case kIntrinsicEquals:
333 return Intrinsics::kStringEquals;
Jeff Hao848f70a2014-01-15 13:49:50 -0800334 case kIntrinsicGetCharsNoCheck:
335 return Intrinsics::kStringGetCharsNoCheck;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800336 case kIntrinsicIsEmptyOrLength:
Razvan A Lupusoru3e90a962015-03-27 13:44:44 -0700337 // The inliner can handle these two cases - and this is the preferred approach
338 // since after inlining the call is no longer visible (as opposed to waiting
339 // until codegen to handle intrinsic).
340 return Intrinsics::kNone;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800341 case kIntrinsicIndexOf:
342 return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
343 Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
Jeff Hao848f70a2014-01-15 13:49:50 -0800344 case kIntrinsicNewStringFromBytes:
345 return Intrinsics::kStringNewStringFromBytes;
346 case kIntrinsicNewStringFromChars:
347 return Intrinsics::kStringNewStringFromChars;
348 case kIntrinsicNewStringFromString:
349 return Intrinsics::kStringNewStringFromString;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800350
351 case kIntrinsicCas:
352 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800353 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800354 return Intrinsics::kUnsafeCASObject;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800355 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800356 return Intrinsics::kUnsafeCASInt;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800357 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800358 return Intrinsics::kUnsafeCASLong;
359 default:
360 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
361 UNREACHABLE();
362 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800363 case kIntrinsicUnsafeGet: {
364 const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
365 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800366 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800367 return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800368 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800369 return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800370 case Primitive::kPrimNot:
371 return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800372 default:
373 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
374 UNREACHABLE();
375 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800376 }
377 case kIntrinsicUnsafePut: {
378 enum Sync { kNoSync, kVolatile, kOrdered };
379 const Sync sync =
380 ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
381 ((method.d.data & kIntrinsicFlagIsOrdered) != 0) ? kOrdered :
382 kNoSync;
383 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800384 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800385 switch (sync) {
386 case kNoSync:
387 return Intrinsics::kUnsafePut;
388 case kVolatile:
389 return Intrinsics::kUnsafePutVolatile;
390 case kOrdered:
391 return Intrinsics::kUnsafePutOrdered;
392 }
393 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800394 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800395 switch (sync) {
396 case kNoSync:
397 return Intrinsics::kUnsafePutLong;
398 case kVolatile:
399 return Intrinsics::kUnsafePutLongVolatile;
400 case kOrdered:
401 return Intrinsics::kUnsafePutLongOrdered;
402 }
403 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800404 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800405 switch (sync) {
406 case kNoSync:
407 return Intrinsics::kUnsafePutObject;
408 case kVolatile:
409 return Intrinsics::kUnsafePutObjectVolatile;
410 case kOrdered:
411 return Intrinsics::kUnsafePutObjectOrdered;
412 }
413 break;
414 default:
415 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
416 UNREACHABLE();
417 }
418 break;
419 }
420
421 // Virtual cases.
422
423 case kIntrinsicReferenceGetReferent:
424 return Intrinsics::kReferenceGetReferent;
425
426 // Quick inliner cases. Remove after refactoring. They are here so that we can use the
427 // compiler to warn on missing cases.
428
429 case kInlineOpNop:
430 case kInlineOpReturnArg:
431 case kInlineOpNonWideConst:
432 case kInlineOpIGet:
433 case kInlineOpIPut:
434 return Intrinsics::kNone;
435
Jeff Hao848f70a2014-01-15 13:49:50 -0800436 // String init cases, not intrinsics.
437
438 case kInlineStringInit:
439 return Intrinsics::kNone;
440
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800441 // No default case to make the compiler warn on missing cases.
442 }
443 return Intrinsics::kNone;
444}
445
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000446static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800447 // The DexFileMethodInliner should have checked whether the methods are agreeing with
448 // what we expect, i.e., static methods are called as such. Add another check here for
449 // our expectations:
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000450 //
451 // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
452 //
453 // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
454 // failure occured. We might be in a situation where we have inlined a method that calls an
455 // intrinsic, but that method is in a different dex file on which we do not have a
456 // verified_method that would have helped the compiler driver sharpen the call. In that case,
457 // make sure that the intrinsic is actually for some final method (or in a final class), as
458 // otherwise the intrinsics setup is broken.
459 //
460 // For the last direction, we have intrinsics for virtual functions that will perform a check
461 // inline. If the precise type is known, however, the instruction will be sharpened to an
462 // InvokeStaticOrDirect.
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800463 InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
464 InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
Nicolas Geoffraye5234232015-12-02 09:06:11 +0000465 invoke->AsInvokeStaticOrDirect()->GetOptimizedInvokeType() :
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800466 invoke->IsInvokeVirtual() ? kVirtual : kSuper;
467 switch (intrinsic_type) {
468 case kStatic:
469 return (invoke_type == kStatic);
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000470
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800471 case kDirect:
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000472 if (invoke_type == kDirect) {
473 return true;
474 }
475 if (invoke_type == kVirtual) {
476 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
477 ScopedObjectAccess soa(Thread::Current());
478 ArtMethod* art_method =
479 class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
480 invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
481 return art_method != nullptr &&
482 (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
483 }
484 return false;
485
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800486 case kVirtual:
487 // Call might be devirtualized.
488 return (invoke_type == kVirtual || invoke_type == kDirect);
489
490 default:
491 return false;
492 }
493}
494
495// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
496void IntrinsicsRecognizer::Run() {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800497 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
498 HBasicBlock* block = it.Current();
499 for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
500 inst_it.Advance()) {
501 HInstruction* inst = inst_it.Current();
502 if (inst->IsInvoke()) {
503 HInvoke* invoke = inst->AsInvoke();
504 InlineMethod method;
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000505 const DexFile& dex_file = invoke->GetDexFile();
506 DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100507 DCHECK(inliner != nullptr);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800508 if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
Chris Larsen16ba2b42015-11-02 10:58:31 -0800509 Intrinsics intrinsic = GetIntrinsic(method);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800510
511 if (intrinsic != Intrinsics::kNone) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000512 if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
Andreas Gampea14b9fe2015-08-24 22:49:59 +0000513 LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000514 << intrinsic << " for "
515 << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
516 << invoke->DebugName();
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800517 } else {
Aart Bik5d75afe2015-12-14 11:57:01 -0800518 invoke->SetIntrinsic(intrinsic,
519 NeedsEnvironmentOrCache(intrinsic),
520 GetSideEffects(intrinsic),
521 GetExceptions(intrinsic));
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800522 }
523 }
524 }
525 }
526 }
527 }
528}
529
530std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
531 switch (intrinsic) {
532 case Intrinsics::kNone:
David Brazdil109c89a2015-07-31 17:10:43 +0100533 os << "None";
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800534 break;
Aart Bik5d75afe2015-12-14 11:57:01 -0800535#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800536 case Intrinsics::k ## Name: \
537 os << # Name; \
538 break;
539#include "intrinsics_list.h"
540INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
541#undef STATIC_INTRINSICS_LIST
542#undef VIRTUAL_INTRINSICS_LIST
543#undef OPTIMIZING_INTRINSICS
544 }
545 return os;
546}
547
548} // namespace art