• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
19 #include "art_method.h"
20 #include "class_linker.h"
21 #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"
25 #include "mirror/dex_cache-inl.h"
26 #include "nodes.h"
27 #include "quick/inline_method_analyser.h"
28 #include "scoped_thread_state_change.h"
29 #include "thread-inl.h"
30 #include "utils.h"
31 
32 namespace art {
33 
34 // Function that returns whether an intrinsic is static/direct or virtual.
GetIntrinsicInvokeType(Intrinsics i)35 static inline InvokeType GetIntrinsicInvokeType(Intrinsics i) {
36   switch (i) {
37     case Intrinsics::kNone:
38       return kInterface;  // Non-sensical for intrinsic.
39 #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
40     case Intrinsics::k ## Name: \
41       return IsStatic;
42 #include "intrinsics_list.h"
43 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
44 #undef INTRINSICS_LIST
45 #undef OPTIMIZING_INTRINSICS
46   }
47   return kInterface;
48 }
49 
50 // Function that returns whether an intrinsic needs an environment or not.
NeedsEnvironmentOrCache(Intrinsics i)51 static inline IntrinsicNeedsEnvironmentOrCache NeedsEnvironmentOrCache(Intrinsics i) {
52   switch (i) {
53     case Intrinsics::kNone:
54       return kNeedsEnvironmentOrCache;  // Non-sensical for intrinsic.
55 #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
56     case Intrinsics::k ## Name: \
57       return NeedsEnvironmentOrCache;
58 #include "intrinsics_list.h"
59 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
60 #undef INTRINSICS_LIST
61 #undef OPTIMIZING_INTRINSICS
62   }
63   return kNeedsEnvironmentOrCache;
64 }
65 
66 // Function that returns whether an intrinsic has side effects.
GetSideEffects(Intrinsics i)67 static 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"
75 INTRINSICS_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.
GetExceptions(Intrinsics i)83 static 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"
91 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
92 #undef INTRINSICS_LIST
93 #undef OPTIMIZING_INTRINSICS
94   }
95   return kCanThrow;
96 }
97 
GetType(uint64_t data,bool is_op_size)98 static Primitive::Type GetType(uint64_t data, bool is_op_size) {
99   if (is_op_size) {
100     switch (static_cast<OpSize>(data)) {
101       case kSignedByte:
102         return Primitive::kPrimByte;
103       case kSignedHalf:
104         return Primitive::kPrimShort;
105       case k32:
106         return Primitive::kPrimInt;
107       case k64:
108         return Primitive::kPrimLong;
109       default:
110         LOG(FATAL) << "Unknown/unsupported op size " << data;
111         UNREACHABLE();
112     }
113   } else {
114     if ((data & kIntrinsicFlagIsLong) != 0) {
115       return Primitive::kPrimLong;
116     }
117     if ((data & kIntrinsicFlagIsObject) != 0) {
118       return Primitive::kPrimNot;
119     }
120     return Primitive::kPrimInt;
121   }
122 }
123 
GetIntrinsic(InlineMethod method)124 static Intrinsics GetIntrinsic(InlineMethod method) {
125   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     case kIntrinsicFloat2Int:
134       return Intrinsics::kFloatFloatToIntBits;
135     case kIntrinsicDouble2Long:
136       return Intrinsics::kDoubleDoubleToLongBits;
137 
138     // 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 
148     // Bit manipulations.
149     case kIntrinsicReverseBits:
150       switch (GetType(method.d.data, true)) {
151         case Primitive::kPrimInt:
152           return Intrinsics::kIntegerReverse;
153         case Primitive::kPrimLong:
154           return Intrinsics::kLongReverse;
155         default:
156           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
157           UNREACHABLE();
158       }
159     case kIntrinsicReverseBytes:
160       switch (GetType(method.d.data, true)) {
161         case Primitive::kPrimShort:
162           return Intrinsics::kShortReverseBytes;
163         case Primitive::kPrimInt:
164           return Intrinsics::kIntegerReverseBytes;
165         case Primitive::kPrimLong:
166           return Intrinsics::kLongReverseBytes;
167         default:
168           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
169           UNREACHABLE();
170       }
171     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.
193     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       }
203     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       }
233     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       }
243     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       }
253     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       }
263 
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 
288     // 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 
324     // 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 
342     case kIntrinsicSystemArrayCopy:
343       return Intrinsics::kSystemArrayCopy;
344 
345     // Thread.currentThread.
346     case kIntrinsicCurrentThread:
347       return Intrinsics::kThreadCurrentThread;
348 
349     // Memory.peek.
350     case kIntrinsicPeek:
351       switch (GetType(method.d.data, true)) {
352         case Primitive::kPrimByte:
353           return Intrinsics::kMemoryPeekByte;
354         case Primitive::kPrimShort:
355           return Intrinsics::kMemoryPeekShortNative;
356         case Primitive::kPrimInt:
357           return Intrinsics::kMemoryPeekIntNative;
358         case Primitive::kPrimLong:
359           return Intrinsics::kMemoryPeekLongNative;
360         default:
361           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
362           UNREACHABLE();
363       }
364 
365     // Memory.poke.
366     case kIntrinsicPoke:
367       switch (GetType(method.d.data, true)) {
368         case Primitive::kPrimByte:
369           return Intrinsics::kMemoryPokeByte;
370         case Primitive::kPrimShort:
371           return Intrinsics::kMemoryPokeShortNative;
372         case Primitive::kPrimInt:
373           return Intrinsics::kMemoryPokeIntNative;
374         case Primitive::kPrimLong:
375           return Intrinsics::kMemoryPokeLongNative;
376         default:
377           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
378           UNREACHABLE();
379       }
380 
381     // String.
382     case kIntrinsicCharAt:
383       return Intrinsics::kStringCharAt;
384     case kIntrinsicCompareTo:
385       return Intrinsics::kStringCompareTo;
386     case kIntrinsicEquals:
387       return Intrinsics::kStringEquals;
388     case kIntrinsicGetCharsNoCheck:
389       return Intrinsics::kStringGetCharsNoCheck;
390     case kIntrinsicIsEmptyOrLength:
391       // The inliner can handle these two cases - and this is the preferred approach
392       // since after inlining the call is no longer visible (as opposed to waiting
393       // until codegen to handle intrinsic).
394       return Intrinsics::kNone;
395     case kIntrinsicIndexOf:
396       return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
397           Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
398     case kIntrinsicNewStringFromBytes:
399       return Intrinsics::kStringNewStringFromBytes;
400     case kIntrinsicNewStringFromChars:
401       return Intrinsics::kStringNewStringFromChars;
402     case kIntrinsicNewStringFromString:
403       return Intrinsics::kStringNewStringFromString;
404 
405     case kIntrinsicCas:
406       switch (GetType(method.d.data, false)) {
407         case Primitive::kPrimNot:
408           return Intrinsics::kUnsafeCASObject;
409         case Primitive::kPrimInt:
410           return Intrinsics::kUnsafeCASInt;
411         case Primitive::kPrimLong:
412           return Intrinsics::kUnsafeCASLong;
413         default:
414           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
415           UNREACHABLE();
416       }
417     case kIntrinsicUnsafeGet: {
418       const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
419       switch (GetType(method.d.data, false)) {
420         case Primitive::kPrimInt:
421           return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
422         case Primitive::kPrimLong:
423           return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
424         case Primitive::kPrimNot:
425           return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
426         default:
427           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
428           UNREACHABLE();
429       }
430     }
431     case kIntrinsicUnsafePut: {
432       enum Sync { kNoSync, kVolatile, kOrdered };
433       const Sync sync =
434           ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
435           ((method.d.data & kIntrinsicFlagIsOrdered) != 0)  ? kOrdered :
436                                                               kNoSync;
437       switch (GetType(method.d.data, false)) {
438         case Primitive::kPrimInt:
439           switch (sync) {
440             case kNoSync:
441               return Intrinsics::kUnsafePut;
442             case kVolatile:
443               return Intrinsics::kUnsafePutVolatile;
444             case kOrdered:
445               return Intrinsics::kUnsafePutOrdered;
446           }
447           break;
448         case Primitive::kPrimLong:
449           switch (sync) {
450             case kNoSync:
451               return Intrinsics::kUnsafePutLong;
452             case kVolatile:
453               return Intrinsics::kUnsafePutLongVolatile;
454             case kOrdered:
455               return Intrinsics::kUnsafePutLongOrdered;
456           }
457           break;
458         case Primitive::kPrimNot:
459           switch (sync) {
460             case kNoSync:
461               return Intrinsics::kUnsafePutObject;
462             case kVolatile:
463               return Intrinsics::kUnsafePutObjectVolatile;
464             case kOrdered:
465               return Intrinsics::kUnsafePutObjectOrdered;
466           }
467           break;
468         default:
469           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
470           UNREACHABLE();
471       }
472       break;
473     }
474 
475     // 1.8.
476     case kIntrinsicUnsafeGetAndAddInt:
477       return Intrinsics::kUnsafeGetAndAddInt;
478     case kIntrinsicUnsafeGetAndAddLong:
479       return Intrinsics::kUnsafeGetAndAddLong;
480     case kIntrinsicUnsafeGetAndSetInt:
481       return Intrinsics::kUnsafeGetAndSetInt;
482     case kIntrinsicUnsafeGetAndSetLong:
483       return Intrinsics::kUnsafeGetAndSetLong;
484     case kIntrinsicUnsafeGetAndSetObject:
485       return Intrinsics::kUnsafeGetAndSetObject;
486     case kIntrinsicUnsafeLoadFence:
487       return Intrinsics::kUnsafeLoadFence;
488     case kIntrinsicUnsafeStoreFence:
489       return Intrinsics::kUnsafeStoreFence;
490     case kIntrinsicUnsafeFullFence:
491       return Intrinsics::kUnsafeFullFence;
492 
493     // Virtual cases.
494 
495     case kIntrinsicReferenceGetReferent:
496       return Intrinsics::kReferenceGetReferent;
497 
498     // Quick inliner cases. Remove after refactoring. They are here so that we can use the
499     // compiler to warn on missing cases.
500 
501     case kInlineOpNop:
502     case kInlineOpReturnArg:
503     case kInlineOpNonWideConst:
504     case kInlineOpIGet:
505     case kInlineOpIPut:
506     case kInlineOpConstructor:
507       return Intrinsics::kNone;
508 
509     // String init cases, not intrinsics.
510 
511     case kInlineStringInit:
512       return Intrinsics::kNone;
513 
514     // No default case to make the compiler warn on missing cases.
515   }
516   return Intrinsics::kNone;
517 }
518 
CheckInvokeType(Intrinsics intrinsic,HInvoke * invoke,const DexFile & dex_file)519 static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
520   // The DexFileMethodInliner should have checked whether the methods are agreeing with
521   // what we expect, i.e., static methods are called as such. Add another check here for
522   // our expectations:
523   //
524   // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
525   //
526   // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
527   // failure occured. We might be in a situation where we have inlined a method that calls an
528   // intrinsic, but that method is in a different dex file on which we do not have a
529   // verified_method that would have helped the compiler driver sharpen the call. In that case,
530   // make sure that the intrinsic is actually for some final method (or in a final class), as
531   // otherwise the intrinsics setup is broken.
532   //
533   // For the last direction, we have intrinsics for virtual functions that will perform a check
534   // inline. If the precise type is known, however, the instruction will be sharpened to an
535   // InvokeStaticOrDirect.
536   InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
537   InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
538       invoke->AsInvokeStaticOrDirect()->GetOptimizedInvokeType() :
539       invoke->IsInvokeVirtual() ? kVirtual : kSuper;
540   switch (intrinsic_type) {
541     case kStatic:
542       return (invoke_type == kStatic);
543 
544     case kDirect:
545       if (invoke_type == kDirect) {
546         return true;
547       }
548       if (invoke_type == kVirtual) {
549         ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
550         ScopedObjectAccess soa(Thread::Current());
551         ArtMethod* art_method =
552             class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
553                 invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
554         return art_method != nullptr &&
555             (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
556       }
557       return false;
558 
559     case kVirtual:
560       // Call might be devirtualized.
561       return (invoke_type == kVirtual || invoke_type == kDirect);
562 
563     default:
564       return false;
565   }
566 }
567 
568 // TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
Run()569 void IntrinsicsRecognizer::Run() {
570   for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
571     HBasicBlock* block = it.Current();
572     for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
573          inst_it.Advance()) {
574       HInstruction* inst = inst_it.Current();
575       if (inst->IsInvoke()) {
576         HInvoke* invoke = inst->AsInvoke();
577         InlineMethod method;
578         const DexFile& dex_file = invoke->GetDexFile();
579         DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
580         DCHECK(inliner != nullptr);
581         if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
582           Intrinsics intrinsic = GetIntrinsic(method);
583 
584           if (intrinsic != Intrinsics::kNone) {
585             if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
586               LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
587                   << intrinsic << " for "
588                   << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
589                   << invoke->DebugName();
590             } else {
591               invoke->SetIntrinsic(intrinsic,
592                                    NeedsEnvironmentOrCache(intrinsic),
593                                    GetSideEffects(intrinsic),
594                                    GetExceptions(intrinsic));
595               MaybeRecordStat(MethodCompilationStat::kIntrinsicRecognized);
596             }
597           }
598         }
599       }
600     }
601   }
602 }
603 
operator <<(std::ostream & os,const Intrinsics & intrinsic)604 std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
605   switch (intrinsic) {
606     case Intrinsics::kNone:
607       os << "None";
608       break;
609 #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
610     case Intrinsics::k ## Name: \
611       os << # Name; \
612       break;
613 #include "intrinsics_list.h"
614 INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
615 #undef STATIC_INTRINSICS_LIST
616 #undef VIRTUAL_INTRINSICS_LIST
617 #undef OPTIMIZING_INTRINSICS
618   }
619   return os;
620 }
621 
622 }  // namespace art
623