blob: 7127215c51fc94fb13cd4f9f093fbaf67d3931e0 [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.
Agi Csaki05f20562015-08-19 14:58:14 -070039#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
Andreas Gampe71fb52f2014-12-29 17:43:08 -080040 case Intrinsics::k ## Name: \
41 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.
55#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
agicsaki57b81ec2015-08-11 17:39:37 -070056 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
66static Primitive::Type GetType(uint64_t data, bool is_op_size) {
67 if (is_op_size) {
68 switch (static_cast<OpSize>(data)) {
69 case kSignedByte:
Andreas Gampe878d58c2015-01-15 23:24:00 -080070 return Primitive::kPrimByte;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080071 case kSignedHalf:
Andreas Gampe878d58c2015-01-15 23:24:00 -080072 return Primitive::kPrimShort;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080073 case k32:
Andreas Gampe878d58c2015-01-15 23:24:00 -080074 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080075 case k64:
Andreas Gampe878d58c2015-01-15 23:24:00 -080076 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080077 default:
78 LOG(FATAL) << "Unknown/unsupported op size " << data;
79 UNREACHABLE();
80 }
81 } else {
82 if ((data & kIntrinsicFlagIsLong) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080083 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080084 }
85 if ((data & kIntrinsicFlagIsObject) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080086 return Primitive::kPrimNot;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080087 }
Andreas Gampe878d58c2015-01-15 23:24:00 -080088 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080089 }
90}
91
Chris Larsen16ba2b42015-11-02 10:58:31 -080092static Intrinsics GetIntrinsic(InlineMethod method) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -080093 switch (method.opcode) {
94 // Floating-point conversions.
95 case kIntrinsicDoubleCvt:
96 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
97 Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
98 case kIntrinsicFloatCvt:
99 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
100 Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
101
102 // Bit manipulations.
103 case kIntrinsicReverseBits:
104 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800105 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800106 return Intrinsics::kIntegerReverse;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800107 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800108 return Intrinsics::kLongReverse;
109 default:
110 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
111 UNREACHABLE();
112 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800113 case kIntrinsicReverseBytes:
114 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800115 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800116 return Intrinsics::kShortReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800117 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800118 return Intrinsics::kIntegerReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800119 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800120 return Intrinsics::kLongReverseBytes;
121 default:
122 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
123 UNREACHABLE();
124 }
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100125 case kIntrinsicRotateRight:
126 switch (GetType(method.d.data, true)) {
127 case Primitive::kPrimInt:
128 return Intrinsics::kIntegerRotateRight;
129 case Primitive::kPrimLong:
130 return Intrinsics::kLongRotateRight;
131 default:
132 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
133 UNREACHABLE();
134 }
135 case kIntrinsicRotateLeft:
136 switch (GetType(method.d.data, true)) {
137 case Primitive::kPrimInt:
138 return Intrinsics::kIntegerRotateLeft;
139 case Primitive::kPrimLong:
140 return Intrinsics::kLongRotateLeft;
141 default:
142 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
143 UNREACHABLE();
144 }
145
146 // Misc data processing.
Scott Wakeling611d3392015-07-10 11:42:06 +0100147 case kIntrinsicNumberOfLeadingZeros:
148 switch (GetType(method.d.data, true)) {
149 case Primitive::kPrimInt:
150 return Intrinsics::kIntegerNumberOfLeadingZeros;
151 case Primitive::kPrimLong:
152 return Intrinsics::kLongNumberOfLeadingZeros;
153 default:
154 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
155 UNREACHABLE();
156 }
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100157 case kIntrinsicNumberOfTrailingZeros:
158 switch (GetType(method.d.data, true)) {
159 case Primitive::kPrimInt:
160 return Intrinsics::kIntegerNumberOfTrailingZeros;
161 case Primitive::kPrimLong:
162 return Intrinsics::kLongNumberOfTrailingZeros;
163 default:
164 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
165 UNREACHABLE();
166 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800167
168 // Abs.
169 case kIntrinsicAbsDouble:
170 return Intrinsics::kMathAbsDouble;
171 case kIntrinsicAbsFloat:
172 return Intrinsics::kMathAbsFloat;
173 case kIntrinsicAbsInt:
174 return Intrinsics::kMathAbsInt;
175 case kIntrinsicAbsLong:
176 return Intrinsics::kMathAbsLong;
177
178 // Min/max.
179 case kIntrinsicMinMaxDouble:
180 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
181 Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
182 case kIntrinsicMinMaxFloat:
183 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
184 Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
185 case kIntrinsicMinMaxInt:
186 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
187 Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
188 case kIntrinsicMinMaxLong:
189 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
190 Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
191
Mark Mendella4f12202015-08-06 15:23:34 -0400192 // More math builtins.
193 case kIntrinsicCos:
194 return Intrinsics::kMathCos;
195 case kIntrinsicSin:
196 return Intrinsics::kMathSin;
197 case kIntrinsicAcos:
198 return Intrinsics::kMathAcos;
199 case kIntrinsicAsin:
200 return Intrinsics::kMathAsin;
201 case kIntrinsicAtan:
202 return Intrinsics::kMathAtan;
203 case kIntrinsicAtan2:
204 return Intrinsics::kMathAtan2;
205 case kIntrinsicCbrt:
206 return Intrinsics::kMathCbrt;
207 case kIntrinsicCosh:
208 return Intrinsics::kMathCosh;
209 case kIntrinsicExp:
210 return Intrinsics::kMathExp;
211 case kIntrinsicExpm1:
212 return Intrinsics::kMathExpm1;
213 case kIntrinsicHypot:
214 return Intrinsics::kMathHypot;
215 case kIntrinsicLog:
216 return Intrinsics::kMathLog;
217 case kIntrinsicLog10:
218 return Intrinsics::kMathLog10;
219 case kIntrinsicNextAfter:
220 return Intrinsics::kMathNextAfter;
221 case kIntrinsicSinh:
222 return Intrinsics::kMathSinh;
223 case kIntrinsicTan:
224 return Intrinsics::kMathTan;
225 case kIntrinsicTanh:
226 return Intrinsics::kMathTanh;
227
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800228 // Misc math.
229 case kIntrinsicSqrt:
230 return Intrinsics::kMathSqrt;
231 case kIntrinsicCeil:
232 return Intrinsics::kMathCeil;
233 case kIntrinsicFloor:
234 return Intrinsics::kMathFloor;
235 case kIntrinsicRint:
236 return Intrinsics::kMathRint;
237 case kIntrinsicRoundDouble:
238 return Intrinsics::kMathRoundDouble;
239 case kIntrinsicRoundFloat:
240 return Intrinsics::kMathRoundFloat;
241
242 // System.arraycopy.
243 case kIntrinsicSystemArrayCopyCharArray:
244 return Intrinsics::kSystemArrayCopyChar;
245
Nicolas Geoffrayee3cf072015-10-06 11:45:02 +0100246 case kIntrinsicSystemArrayCopy:
247 return Intrinsics::kSystemArrayCopy;
248
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800249 // Thread.currentThread.
250 case kIntrinsicCurrentThread:
251 return Intrinsics::kThreadCurrentThread;
252
253 // Memory.peek.
254 case kIntrinsicPeek:
255 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800256 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800257 return Intrinsics::kMemoryPeekByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800258 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800259 return Intrinsics::kMemoryPeekShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800260 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800261 return Intrinsics::kMemoryPeekIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800262 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800263 return Intrinsics::kMemoryPeekLongNative;
264 default:
265 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
266 UNREACHABLE();
267 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800268
269 // Memory.poke.
270 case kIntrinsicPoke:
271 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800272 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800273 return Intrinsics::kMemoryPokeByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800274 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800275 return Intrinsics::kMemoryPokeShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800276 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800277 return Intrinsics::kMemoryPokeIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800278 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800279 return Intrinsics::kMemoryPokeLongNative;
280 default:
281 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
282 UNREACHABLE();
283 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800284
285 // String.
286 case kIntrinsicCharAt:
287 return Intrinsics::kStringCharAt;
288 case kIntrinsicCompareTo:
289 return Intrinsics::kStringCompareTo;
agicsaki7da072f2015-08-12 20:30:17 -0700290 case kIntrinsicEquals:
291 return Intrinsics::kStringEquals;
Jeff Hao848f70a2014-01-15 13:49:50 -0800292 case kIntrinsicGetCharsNoCheck:
293 return Intrinsics::kStringGetCharsNoCheck;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800294 case kIntrinsicIsEmptyOrLength:
Razvan A Lupusoru3e90a962015-03-27 13:44:44 -0700295 // The inliner can handle these two cases - and this is the preferred approach
296 // since after inlining the call is no longer visible (as opposed to waiting
297 // until codegen to handle intrinsic).
298 return Intrinsics::kNone;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800299 case kIntrinsicIndexOf:
300 return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
301 Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
Jeff Hao848f70a2014-01-15 13:49:50 -0800302 case kIntrinsicNewStringFromBytes:
303 return Intrinsics::kStringNewStringFromBytes;
304 case kIntrinsicNewStringFromChars:
305 return Intrinsics::kStringNewStringFromChars;
306 case kIntrinsicNewStringFromString:
307 return Intrinsics::kStringNewStringFromString;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800308
309 case kIntrinsicCas:
310 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800311 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800312 return Intrinsics::kUnsafeCASObject;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800313 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800314 return Intrinsics::kUnsafeCASInt;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800315 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800316 return Intrinsics::kUnsafeCASLong;
317 default:
318 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
319 UNREACHABLE();
320 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800321 case kIntrinsicUnsafeGet: {
322 const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
323 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800324 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800325 return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800326 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800327 return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800328 case Primitive::kPrimNot:
329 return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800330 default:
331 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
332 UNREACHABLE();
333 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800334 }
335 case kIntrinsicUnsafePut: {
336 enum Sync { kNoSync, kVolatile, kOrdered };
337 const Sync sync =
338 ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
339 ((method.d.data & kIntrinsicFlagIsOrdered) != 0) ? kOrdered :
340 kNoSync;
341 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800342 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800343 switch (sync) {
344 case kNoSync:
345 return Intrinsics::kUnsafePut;
346 case kVolatile:
347 return Intrinsics::kUnsafePutVolatile;
348 case kOrdered:
349 return Intrinsics::kUnsafePutOrdered;
350 }
351 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800352 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800353 switch (sync) {
354 case kNoSync:
355 return Intrinsics::kUnsafePutLong;
356 case kVolatile:
357 return Intrinsics::kUnsafePutLongVolatile;
358 case kOrdered:
359 return Intrinsics::kUnsafePutLongOrdered;
360 }
361 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800362 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800363 switch (sync) {
364 case kNoSync:
365 return Intrinsics::kUnsafePutObject;
366 case kVolatile:
367 return Intrinsics::kUnsafePutObjectVolatile;
368 case kOrdered:
369 return Intrinsics::kUnsafePutObjectOrdered;
370 }
371 break;
372 default:
373 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
374 UNREACHABLE();
375 }
376 break;
377 }
378
379 // Virtual cases.
380
381 case kIntrinsicReferenceGetReferent:
382 return Intrinsics::kReferenceGetReferent;
383
384 // Quick inliner cases. Remove after refactoring. They are here so that we can use the
385 // compiler to warn on missing cases.
386
387 case kInlineOpNop:
388 case kInlineOpReturnArg:
389 case kInlineOpNonWideConst:
390 case kInlineOpIGet:
391 case kInlineOpIPut:
392 return Intrinsics::kNone;
393
Jeff Hao848f70a2014-01-15 13:49:50 -0800394 // String init cases, not intrinsics.
395
396 case kInlineStringInit:
397 return Intrinsics::kNone;
398
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800399 // No default case to make the compiler warn on missing cases.
400 }
401 return Intrinsics::kNone;
402}
403
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000404static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800405 // The DexFileMethodInliner should have checked whether the methods are agreeing with
406 // what we expect, i.e., static methods are called as such. Add another check here for
407 // our expectations:
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000408 //
409 // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
410 //
411 // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
412 // failure occured. We might be in a situation where we have inlined a method that calls an
413 // intrinsic, but that method is in a different dex file on which we do not have a
414 // verified_method that would have helped the compiler driver sharpen the call. In that case,
415 // make sure that the intrinsic is actually for some final method (or in a final class), as
416 // otherwise the intrinsics setup is broken.
417 //
418 // For the last direction, we have intrinsics for virtual functions that will perform a check
419 // inline. If the precise type is known, however, the instruction will be sharpened to an
420 // InvokeStaticOrDirect.
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800421 InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
422 InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
Nicolas Geoffraye5234232015-12-02 09:06:11 +0000423 invoke->AsInvokeStaticOrDirect()->GetOptimizedInvokeType() :
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800424 invoke->IsInvokeVirtual() ? kVirtual : kSuper;
425 switch (intrinsic_type) {
426 case kStatic:
427 return (invoke_type == kStatic);
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000428
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800429 case kDirect:
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000430 if (invoke_type == kDirect) {
431 return true;
432 }
433 if (invoke_type == kVirtual) {
434 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
435 ScopedObjectAccess soa(Thread::Current());
436 ArtMethod* art_method =
437 class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
438 invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
439 return art_method != nullptr &&
440 (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
441 }
442 return false;
443
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800444 case kVirtual:
445 // Call might be devirtualized.
446 return (invoke_type == kVirtual || invoke_type == kDirect);
447
448 default:
449 return false;
450 }
451}
452
453// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
454void IntrinsicsRecognizer::Run() {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800455 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
456 HBasicBlock* block = it.Current();
457 for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
458 inst_it.Advance()) {
459 HInstruction* inst = inst_it.Current();
460 if (inst->IsInvoke()) {
461 HInvoke* invoke = inst->AsInvoke();
462 InlineMethod method;
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000463 const DexFile& dex_file = invoke->GetDexFile();
464 DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100465 DCHECK(inliner != nullptr);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800466 if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
Chris Larsen16ba2b42015-11-02 10:58:31 -0800467 Intrinsics intrinsic = GetIntrinsic(method);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800468
469 if (intrinsic != Intrinsics::kNone) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000470 if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
Andreas Gampea14b9fe2015-08-24 22:49:59 +0000471 LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
Andreas Gampebfb5ba92015-09-01 15:45:02 +0000472 << intrinsic << " for "
473 << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
474 << invoke->DebugName();
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800475 } else {
Agi Csaki05f20562015-08-19 14:58:14 -0700476 invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800477 }
478 }
479 }
480 }
481 }
482 }
483}
484
485std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
486 switch (intrinsic) {
487 case Intrinsics::kNone:
David Brazdil109c89a2015-07-31 17:10:43 +0100488 os << "None";
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800489 break;
Agi Csaki05f20562015-08-19 14:58:14 -0700490#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800491 case Intrinsics::k ## Name: \
492 os << # Name; \
493 break;
494#include "intrinsics_list.h"
495INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
496#undef STATIC_INTRINSICS_LIST
497#undef VIRTUAL_INTRINSICS_LIST
498#undef OPTIMIZING_INTRINSICS
499 }
500 return os;
501}
502
503} // namespace art