blob: 4d4bbcf616f44f30ad853271ea3e36400dd6e0e3 [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;
Aart Bik2a6aad92016-02-25 11:32:32 -0800133 case kIntrinsicFloat2Int:
134 return Intrinsics::kFloatFloatToIntBits;
135 case kIntrinsicDouble2Long:
136 return Intrinsics::kDoubleDoubleToLongBits;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800137
Aart Bik59c94542016-01-25 14:20:58 -0800138 // Floating-point tests.
139 case kIntrinsicFloatIsInfinite:
140 return Intrinsics::kFloatIsInfinite;
141 case kIntrinsicDoubleIsInfinite:
142 return Intrinsics::kDoubleIsInfinite;
143 case kIntrinsicFloatIsNaN:
144 return Intrinsics::kFloatIsNaN;
145 case kIntrinsicDoubleIsNaN:
146 return Intrinsics::kDoubleIsNaN;
147
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800148 // Bit manipulations.
149 case kIntrinsicReverseBits:
150 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800151 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800152 return Intrinsics::kIntegerReverse;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800153 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800154 return Intrinsics::kLongReverse;
155 default:
156 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
157 UNREACHABLE();
158 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800159 case kIntrinsicReverseBytes:
160 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800161 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800162 return Intrinsics::kShortReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800163 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800164 return Intrinsics::kIntegerReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800165 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800166 return Intrinsics::kLongReverseBytes;
167 default:
168 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
169 UNREACHABLE();
170 }
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100171 case kIntrinsicRotateRight:
172 switch (GetType(method.d.data, true)) {
173 case Primitive::kPrimInt:
174 return Intrinsics::kIntegerRotateRight;
175 case Primitive::kPrimLong:
176 return Intrinsics::kLongRotateRight;
177 default:
178 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
179 UNREACHABLE();
180 }
181 case kIntrinsicRotateLeft:
182 switch (GetType(method.d.data, true)) {
183 case Primitive::kPrimInt:
184 return Intrinsics::kIntegerRotateLeft;
185 case Primitive::kPrimLong:
186 return Intrinsics::kLongRotateLeft;
187 default:
188 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
189 UNREACHABLE();
190 }
191
192 // Misc data processing.
Aart Bik3f67e692016-01-15 14:35:12 -0800193 case kIntrinsicBitCount:
194 switch (GetType(method.d.data, true)) {
195 case Primitive::kPrimInt:
196 return Intrinsics::kIntegerBitCount;
197 case Primitive::kPrimLong:
198 return Intrinsics::kLongBitCount;
199 default:
200 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
201 UNREACHABLE();
202 }
Aart Bik59c94542016-01-25 14:20:58 -0800203 case kIntrinsicCompare:
204 switch (GetType(method.d.data, true)) {
205 case Primitive::kPrimInt:
206 return Intrinsics::kIntegerCompare;
207 case Primitive::kPrimLong:
208 return Intrinsics::kLongCompare;
209 default:
210 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
211 UNREACHABLE();
212 }
213 case kIntrinsicHighestOneBit:
214 switch (GetType(method.d.data, true)) {
215 case Primitive::kPrimInt:
216 return Intrinsics::kIntegerHighestOneBit;
217 case Primitive::kPrimLong:
218 return Intrinsics::kLongHighestOneBit;
219 default:
220 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
221 UNREACHABLE();
222 }
223 case kIntrinsicLowestOneBit:
224 switch (GetType(method.d.data, true)) {
225 case Primitive::kPrimInt:
226 return Intrinsics::kIntegerLowestOneBit;
227 case Primitive::kPrimLong:
228 return Intrinsics::kLongLowestOneBit;
229 default:
230 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
231 UNREACHABLE();
232 }
Scott Wakeling611d3392015-07-10 11:42:06 +0100233 case kIntrinsicNumberOfLeadingZeros:
234 switch (GetType(method.d.data, true)) {
235 case Primitive::kPrimInt:
236 return Intrinsics::kIntegerNumberOfLeadingZeros;
237 case Primitive::kPrimLong:
238 return Intrinsics::kLongNumberOfLeadingZeros;
239 default:
240 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
241 UNREACHABLE();
242 }
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100243 case kIntrinsicNumberOfTrailingZeros:
244 switch (GetType(method.d.data, true)) {
245 case Primitive::kPrimInt:
246 return Intrinsics::kIntegerNumberOfTrailingZeros;
247 case Primitive::kPrimLong:
248 return Intrinsics::kLongNumberOfTrailingZeros;
249 default:
250 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
251 UNREACHABLE();
252 }
Aart Bik59c94542016-01-25 14:20:58 -0800253 case kIntrinsicSignum:
254 switch (GetType(method.d.data, true)) {
255 case Primitive::kPrimInt:
256 return Intrinsics::kIntegerSignum;
257 case Primitive::kPrimLong:
258 return Intrinsics::kLongSignum;
259 default:
260 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
261 UNREACHABLE();
262 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800263
264 // Abs.
265 case kIntrinsicAbsDouble:
266 return Intrinsics::kMathAbsDouble;
267 case kIntrinsicAbsFloat:
268 return Intrinsics::kMathAbsFloat;
269 case kIntrinsicAbsInt:
270 return Intrinsics::kMathAbsInt;
271 case kIntrinsicAbsLong:
272 return Intrinsics::kMathAbsLong;
273
274 // Min/max.
275 case kIntrinsicMinMaxDouble:
276 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
277 Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
278 case kIntrinsicMinMaxFloat:
279 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
280 Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
281 case kIntrinsicMinMaxInt:
282 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
283 Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
284 case kIntrinsicMinMaxLong:
285 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
286 Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
287
Mark Mendella4f12202015-08-06 15:23:34 -0400288 // More math builtins.
289 case kIntrinsicCos:
290 return Intrinsics::kMathCos;
291 case kIntrinsicSin:
292 return Intrinsics::kMathSin;
293 case kIntrinsicAcos:
294 return Intrinsics::kMathAcos;
295 case kIntrinsicAsin:
296 return Intrinsics::kMathAsin;
297 case kIntrinsicAtan:
298 return Intrinsics::kMathAtan;
299 case kIntrinsicAtan2:
300 return Intrinsics::kMathAtan2;
301 case kIntrinsicCbrt:
302 return Intrinsics::kMathCbrt;
303 case kIntrinsicCosh:
304 return Intrinsics::kMathCosh;
305 case kIntrinsicExp:
306 return Intrinsics::kMathExp;
307 case kIntrinsicExpm1:
308 return Intrinsics::kMathExpm1;
309 case kIntrinsicHypot:
310 return Intrinsics::kMathHypot;
311 case kIntrinsicLog:
312 return Intrinsics::kMathLog;
313 case kIntrinsicLog10:
314 return Intrinsics::kMathLog10;
315 case kIntrinsicNextAfter:
316 return Intrinsics::kMathNextAfter;
317 case kIntrinsicSinh:
318 return Intrinsics::kMathSinh;
319 case kIntrinsicTan:
320 return Intrinsics::kMathTan;
321 case kIntrinsicTanh:
322 return Intrinsics::kMathTanh;
323
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800324 // Misc math.
325 case kIntrinsicSqrt:
326 return Intrinsics::kMathSqrt;
327 case kIntrinsicCeil:
328 return Intrinsics::kMathCeil;
329 case kIntrinsicFloor:
330 return Intrinsics::kMathFloor;
331 case kIntrinsicRint:
332 return Intrinsics::kMathRint;
333 case kIntrinsicRoundDouble:
334 return Intrinsics::kMathRoundDouble;
335 case kIntrinsicRoundFloat:
336 return Intrinsics::kMathRoundFloat;
337
338 // System.arraycopy.
339 case kIntrinsicSystemArrayCopyCharArray:
340 return Intrinsics::kSystemArrayCopyChar;
341
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +0100342 case kIntrinsicSystemArrayCopy:
343 return Intrinsics::kSystemArrayCopy;
344
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800345 // Thread.currentThread.
346 case kIntrinsicCurrentThread:
Aart Bik5d75afe2015-12-14 11:57:01 -0800347 return Intrinsics::kThreadCurrentThread;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800348
349 // Memory.peek.
350 case kIntrinsicPeek:
351 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800352 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800353 return Intrinsics::kMemoryPeekByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800354 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800355 return Intrinsics::kMemoryPeekShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800356 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800357 return Intrinsics::kMemoryPeekIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800358 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800359 return Intrinsics::kMemoryPeekLongNative;
360 default:
361 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
362 UNREACHABLE();
363 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800364
365 // Memory.poke.
366 case kIntrinsicPoke:
367 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800368 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800369 return Intrinsics::kMemoryPokeByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800370 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800371 return Intrinsics::kMemoryPokeShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800372 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800373 return Intrinsics::kMemoryPokeIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800374 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800375 return Intrinsics::kMemoryPokeLongNative;
376 default:
377 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
378 UNREACHABLE();
379 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800380
381 // String.
382 case kIntrinsicCharAt:
383 return Intrinsics::kStringCharAt;
384 case kIntrinsicCompareTo:
385 return Intrinsics::kStringCompareTo;
agicsaki7da072f2015-08-12 20:30:17 -0700386 case kIntrinsicEquals:
387 return Intrinsics::kStringEquals;
Jeff Hao848f70a2014-01-15 13:49:50 -0800388 case kIntrinsicGetCharsNoCheck:
389 return Intrinsics::kStringGetCharsNoCheck;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800390 case kIntrinsicIsEmptyOrLength:
Vladimir Markodce016e2016-04-28 13:10:02 +0100391 return ((method.d.data & kIntrinsicFlagIsEmpty) == 0) ?
392 Intrinsics::kStringLength : Intrinsics::kStringIsEmpty;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800393 case kIntrinsicIndexOf:
394 return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
395 Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
Jeff Hao848f70a2014-01-15 13:49:50 -0800396 case kIntrinsicNewStringFromBytes:
397 return Intrinsics::kStringNewStringFromBytes;
398 case kIntrinsicNewStringFromChars:
399 return Intrinsics::kStringNewStringFromChars;
400 case kIntrinsicNewStringFromString:
401 return Intrinsics::kStringNewStringFromString;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800402
403 case kIntrinsicCas:
404 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800405 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800406 return Intrinsics::kUnsafeCASObject;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800407 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800408 return Intrinsics::kUnsafeCASInt;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800409 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800410 return Intrinsics::kUnsafeCASLong;
411 default:
412 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
413 UNREACHABLE();
414 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800415 case kIntrinsicUnsafeGet: {
416 const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
417 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800418 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800419 return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800420 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800421 return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800422 case Primitive::kPrimNot:
423 return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800424 default:
425 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
426 UNREACHABLE();
427 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800428 }
429 case kIntrinsicUnsafePut: {
430 enum Sync { kNoSync, kVolatile, kOrdered };
431 const Sync sync =
432 ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
433 ((method.d.data & kIntrinsicFlagIsOrdered) != 0) ? kOrdered :
434 kNoSync;
435 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800436 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800437 switch (sync) {
438 case kNoSync:
439 return Intrinsics::kUnsafePut;
440 case kVolatile:
441 return Intrinsics::kUnsafePutVolatile;
442 case kOrdered:
443 return Intrinsics::kUnsafePutOrdered;
444 }
445 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800446 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800447 switch (sync) {
448 case kNoSync:
449 return Intrinsics::kUnsafePutLong;
450 case kVolatile:
451 return Intrinsics::kUnsafePutLongVolatile;
452 case kOrdered:
453 return Intrinsics::kUnsafePutLongOrdered;
454 }
455 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800456 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800457 switch (sync) {
458 case kNoSync:
459 return Intrinsics::kUnsafePutObject;
460 case kVolatile:
461 return Intrinsics::kUnsafePutObjectVolatile;
462 case kOrdered:
463 return Intrinsics::kUnsafePutObjectOrdered;
464 }
465 break;
466 default:
467 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
468 UNREACHABLE();
469 }
470 break;
471 }
472
Aart Bik0e54c012016-03-04 12:08:31 -0800473 // 1.8.
474 case kIntrinsicUnsafeGetAndAddInt:
475 return Intrinsics::kUnsafeGetAndAddInt;
476 case kIntrinsicUnsafeGetAndAddLong:
477 return Intrinsics::kUnsafeGetAndAddLong;
478 case kIntrinsicUnsafeGetAndSetInt:
479 return Intrinsics::kUnsafeGetAndSetInt;
480 case kIntrinsicUnsafeGetAndSetLong:
481 return Intrinsics::kUnsafeGetAndSetLong;
482 case kIntrinsicUnsafeGetAndSetObject:
483 return Intrinsics::kUnsafeGetAndSetObject;
484 case kIntrinsicUnsafeLoadFence:
485 return Intrinsics::kUnsafeLoadFence;
486 case kIntrinsicUnsafeStoreFence:
487 return Intrinsics::kUnsafeStoreFence;
488 case kIntrinsicUnsafeFullFence:
489 return Intrinsics::kUnsafeFullFence;
490
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800491 // Virtual cases.
492
493 case kIntrinsicReferenceGetReferent:
494 return Intrinsics::kReferenceGetReferent;
495
496 // Quick inliner cases. Remove after refactoring. They are here so that we can use the
497 // compiler to warn on missing cases.
498
499 case kInlineOpNop:
500 case kInlineOpReturnArg:
501 case kInlineOpNonWideConst:
502 case kInlineOpIGet:
503 case kInlineOpIPut:
Vladimir Marko354efa62016-02-04 19:46:56 +0000504 case kInlineOpConstructor:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800505 return Intrinsics::kNone;
506
Jeff Hao848f70a2014-01-15 13:49:50 -0800507 // String init cases, not intrinsics.
508
509 case kInlineStringInit:
510 return Intrinsics::kNone;
511
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800512 // No default case to make the compiler warn on missing cases.
513 }
514 return Intrinsics::kNone;
515}
516
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000517static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800518 // The DexFileMethodInliner should have checked whether the methods are agreeing with
519 // what we expect, i.e., static methods are called as such. Add another check here for
520 // our expectations:
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000521 //
522 // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
523 //
524 // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
525 // failure occured. We might be in a situation where we have inlined a method that calls an
526 // intrinsic, but that method is in a different dex file on which we do not have a
527 // verified_method that would have helped the compiler driver sharpen the call. In that case,
528 // make sure that the intrinsic is actually for some final method (or in a final class), as
529 // otherwise the intrinsics setup is broken.
530 //
531 // For the last direction, we have intrinsics for virtual functions that will perform a check
532 // inline. If the precise type is known, however, the instruction will be sharpened to an
533 // InvokeStaticOrDirect.
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800534 InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +0100535 InvokeType invoke_type = invoke->GetInvokeType();
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800536 switch (intrinsic_type) {
537 case kStatic:
538 return (invoke_type == kStatic);
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000539
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800540 case kDirect:
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000541 if (invoke_type == kDirect) {
542 return true;
543 }
544 if (invoke_type == kVirtual) {
545 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
546 ScopedObjectAccess soa(Thread::Current());
547 ArtMethod* art_method =
548 class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
549 invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
550 return art_method != nullptr &&
551 (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
552 }
553 return false;
554
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800555 case kVirtual:
556 // Call might be devirtualized.
557 return (invoke_type == kVirtual || invoke_type == kDirect);
558
559 default:
560 return false;
561 }
562}
563
564// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
565void IntrinsicsRecognizer::Run() {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800566 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
567 HBasicBlock* block = it.Current();
568 for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
569 inst_it.Advance()) {
570 HInstruction* inst = inst_it.Current();
571 if (inst->IsInvoke()) {
572 HInvoke* invoke = inst->AsInvoke();
573 InlineMethod method;
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000574 const DexFile& dex_file = invoke->GetDexFile();
575 DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100576 DCHECK(inliner != nullptr);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800577 if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
Chris Larsen16ba2b42015-11-02 10:58:31 -0800578 Intrinsics intrinsic = GetIntrinsic(method);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800579
580 if (intrinsic != Intrinsics::kNone) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000581 if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
Andreas Gampea14b9fe2015-08-24 22:49:59 +0000582 LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000583 << intrinsic << " for "
584 << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
585 << invoke->DebugName();
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800586 } else {
Aart Bik5d75afe2015-12-14 11:57:01 -0800587 invoke->SetIntrinsic(intrinsic,
588 NeedsEnvironmentOrCache(intrinsic),
589 GetSideEffects(intrinsic),
590 GetExceptions(intrinsic));
Jean-Philippe Halimi38e9e802016-02-18 16:42:03 +0100591 MaybeRecordStat(MethodCompilationStat::kIntrinsicRecognized);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800592 }
593 }
594 }
595 }
596 }
597 }
598}
599
600std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
601 switch (intrinsic) {
602 case Intrinsics::kNone:
David Brazdil109c89a2015-07-31 17:10:43 +0100603 os << "None";
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800604 break;
Aart Bik5d75afe2015-12-14 11:57:01 -0800605#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800606 case Intrinsics::k ## Name: \
607 os << # Name; \
608 break;
609#include "intrinsics_list.h"
610INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
611#undef STATIC_INTRINSICS_LIST
612#undef VIRTUAL_INTRINSICS_LIST
613#undef OPTIMIZING_INTRINSICS
614 }
615 return os;
616}
617
618} // namespace art