blob: feaaaf45ec6e8f5292bccef529f07ede063bffc0 [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
Nicolas Geoffray4daa0b42015-08-20 14:05:14 +010019#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"
Nicolas Geoffray4daa0b42015-08-20 14:05:14 +010025#include "mirror/dex_cache-inl.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080026#include "nodes.h"
27#include "quick/inline_method_analyser.h"
Nicolas Geoffray4daa0b42015-08-20 14:05:14 +010028#include "scoped_thread_state_change.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010029#include "utils.h"
Andreas Gampe71fb52f2014-12-29 17:43:08 -080030
31namespace art {
32
33// Function that returns whether an intrinsic is static/direct or virtual.
34static inline InvokeType GetIntrinsicInvokeType(Intrinsics i) {
35 switch (i) {
36 case Intrinsics::kNone:
37 return kInterface; // Non-sensical for intrinsic.
Agi Csaki05f20562015-08-19 14:58:14 -070038#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
Andreas Gampe71fb52f2014-12-29 17:43:08 -080039 case Intrinsics::k ## Name: \
40 return IsStatic;
41#include "intrinsics_list.h"
42INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
43#undef INTRINSICS_LIST
44#undef OPTIMIZING_INTRINSICS
45 }
46 return kInterface;
47}
48
agicsaki57b81ec2015-08-11 17:39:37 -070049// Function that returns whether an intrinsic needs an environment or not.
Agi Csaki05f20562015-08-19 14:58:14 -070050static inline IntrinsicNeedsEnvironmentOrCache NeedsEnvironmentOrCache(Intrinsics i) {
agicsaki57b81ec2015-08-11 17:39:37 -070051 switch (i) {
52 case Intrinsics::kNone:
Agi Csaki05f20562015-08-19 14:58:14 -070053 return kNeedsEnvironmentOrCache; // Non-sensical for intrinsic.
54#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
agicsaki57b81ec2015-08-11 17:39:37 -070055 case Intrinsics::k ## Name: \
Agi Csaki05f20562015-08-19 14:58:14 -070056 return NeedsEnvironmentOrCache;
agicsaki57b81ec2015-08-11 17:39:37 -070057#include "intrinsics_list.h"
58INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
59#undef INTRINSICS_LIST
60#undef OPTIMIZING_INTRINSICS
61 }
Agi Csaki05f20562015-08-19 14:58:14 -070062 return kNeedsEnvironmentOrCache;
agicsaki57b81ec2015-08-11 17:39:37 -070063}
Andreas Gampe71fb52f2014-12-29 17:43:08 -080064
65static Primitive::Type GetType(uint64_t data, bool is_op_size) {
66 if (is_op_size) {
67 switch (static_cast<OpSize>(data)) {
68 case kSignedByte:
Andreas Gampe878d58c2015-01-15 23:24:00 -080069 return Primitive::kPrimByte;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080070 case kSignedHalf:
Andreas Gampe878d58c2015-01-15 23:24:00 -080071 return Primitive::kPrimShort;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080072 case k32:
Andreas Gampe878d58c2015-01-15 23:24:00 -080073 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080074 case k64:
Andreas Gampe878d58c2015-01-15 23:24:00 -080075 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080076 default:
77 LOG(FATAL) << "Unknown/unsupported op size " << data;
78 UNREACHABLE();
79 }
80 } else {
81 if ((data & kIntrinsicFlagIsLong) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080082 return Primitive::kPrimLong;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080083 }
84 if ((data & kIntrinsicFlagIsObject) != 0) {
Andreas Gampe878d58c2015-01-15 23:24:00 -080085 return Primitive::kPrimNot;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080086 }
Andreas Gampe878d58c2015-01-15 23:24:00 -080087 return Primitive::kPrimInt;
Andreas Gampe71fb52f2014-12-29 17:43:08 -080088 }
89}
90
agicsaki6cff09a2015-08-12 21:20:43 -070091static Intrinsics GetIntrinsic(InlineMethod method, InstructionSet instruction_set) {
92 if (instruction_set == kMips || instruction_set == kMips64) {
93 return Intrinsics::kNone;
94 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -080095 switch (method.opcode) {
96 // Floating-point conversions.
97 case kIntrinsicDoubleCvt:
98 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
99 Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
100 case kIntrinsicFloatCvt:
101 return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
102 Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
103
104 // Bit manipulations.
105 case kIntrinsicReverseBits:
106 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800107 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800108 return Intrinsics::kIntegerReverse;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800109 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800110 return Intrinsics::kLongReverse;
111 default:
112 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
113 UNREACHABLE();
114 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800115 case kIntrinsicReverseBytes:
116 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800117 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800118 return Intrinsics::kShortReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800119 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800120 return Intrinsics::kIntegerReverseBytes;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800121 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800122 return Intrinsics::kLongReverseBytes;
123 default:
124 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
125 UNREACHABLE();
126 }
Scott Wakeling611d3392015-07-10 11:42:06 +0100127 case kIntrinsicNumberOfLeadingZeros:
128 switch (GetType(method.d.data, true)) {
129 case Primitive::kPrimInt:
130 return Intrinsics::kIntegerNumberOfLeadingZeros;
131 case Primitive::kPrimLong:
132 return Intrinsics::kLongNumberOfLeadingZeros;
133 default:
134 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
135 UNREACHABLE();
136 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800137
138 // Abs.
139 case kIntrinsicAbsDouble:
140 return Intrinsics::kMathAbsDouble;
141 case kIntrinsicAbsFloat:
142 return Intrinsics::kMathAbsFloat;
143 case kIntrinsicAbsInt:
144 return Intrinsics::kMathAbsInt;
145 case kIntrinsicAbsLong:
146 return Intrinsics::kMathAbsLong;
147
148 // Min/max.
149 case kIntrinsicMinMaxDouble:
150 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
151 Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
152 case kIntrinsicMinMaxFloat:
153 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
154 Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
155 case kIntrinsicMinMaxInt:
156 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
157 Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
158 case kIntrinsicMinMaxLong:
159 return ((method.d.data & kIntrinsicFlagMin) == 0) ?
160 Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
161
162 // Misc math.
163 case kIntrinsicSqrt:
164 return Intrinsics::kMathSqrt;
165 case kIntrinsicCeil:
166 return Intrinsics::kMathCeil;
167 case kIntrinsicFloor:
168 return Intrinsics::kMathFloor;
169 case kIntrinsicRint:
170 return Intrinsics::kMathRint;
171 case kIntrinsicRoundDouble:
172 return Intrinsics::kMathRoundDouble;
173 case kIntrinsicRoundFloat:
174 return Intrinsics::kMathRoundFloat;
175
176 // System.arraycopy.
177 case kIntrinsicSystemArrayCopyCharArray:
178 return Intrinsics::kSystemArrayCopyChar;
179
180 // Thread.currentThread.
181 case kIntrinsicCurrentThread:
182 return Intrinsics::kThreadCurrentThread;
183
184 // Memory.peek.
185 case kIntrinsicPeek:
186 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800187 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800188 return Intrinsics::kMemoryPeekByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800189 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800190 return Intrinsics::kMemoryPeekShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800191 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800192 return Intrinsics::kMemoryPeekIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800193 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800194 return Intrinsics::kMemoryPeekLongNative;
195 default:
196 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
197 UNREACHABLE();
198 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800199
200 // Memory.poke.
201 case kIntrinsicPoke:
202 switch (GetType(method.d.data, true)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800203 case Primitive::kPrimByte:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800204 return Intrinsics::kMemoryPokeByte;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800205 case Primitive::kPrimShort:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800206 return Intrinsics::kMemoryPokeShortNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800207 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800208 return Intrinsics::kMemoryPokeIntNative;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800209 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800210 return Intrinsics::kMemoryPokeLongNative;
211 default:
212 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
213 UNREACHABLE();
214 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800215
216 // String.
217 case kIntrinsicCharAt:
218 return Intrinsics::kStringCharAt;
219 case kIntrinsicCompareTo:
220 return Intrinsics::kStringCompareTo;
agicsaki7da072f2015-08-12 20:30:17 -0700221 case kIntrinsicEquals:
222 return Intrinsics::kStringEquals;
Jeff Hao848f70a2014-01-15 13:49:50 -0800223 case kIntrinsicGetCharsNoCheck:
224 return Intrinsics::kStringGetCharsNoCheck;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800225 case kIntrinsicIsEmptyOrLength:
Razvan A Lupusoru3e90a962015-03-27 13:44:44 -0700226 // The inliner can handle these two cases - and this is the preferred approach
227 // since after inlining the call is no longer visible (as opposed to waiting
228 // until codegen to handle intrinsic).
229 return Intrinsics::kNone;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800230 case kIntrinsicIndexOf:
231 return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
232 Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
Jeff Hao848f70a2014-01-15 13:49:50 -0800233 case kIntrinsicNewStringFromBytes:
234 return Intrinsics::kStringNewStringFromBytes;
235 case kIntrinsicNewStringFromChars:
236 return Intrinsics::kStringNewStringFromChars;
237 case kIntrinsicNewStringFromString:
238 return Intrinsics::kStringNewStringFromString;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800239
240 case kIntrinsicCas:
241 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800242 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800243 return Intrinsics::kUnsafeCASObject;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800244 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800245 return Intrinsics::kUnsafeCASInt;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800246 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800247 return Intrinsics::kUnsafeCASLong;
248 default:
249 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
250 UNREACHABLE();
251 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800252 case kIntrinsicUnsafeGet: {
253 const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
254 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800255 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800256 return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800257 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800258 return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800259 case Primitive::kPrimNot:
260 return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800261 default:
262 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
263 UNREACHABLE();
264 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800265 }
266 case kIntrinsicUnsafePut: {
267 enum Sync { kNoSync, kVolatile, kOrdered };
268 const Sync sync =
269 ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
270 ((method.d.data & kIntrinsicFlagIsOrdered) != 0) ? kOrdered :
271 kNoSync;
272 switch (GetType(method.d.data, false)) {
Andreas Gampe878d58c2015-01-15 23:24:00 -0800273 case Primitive::kPrimInt:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800274 switch (sync) {
275 case kNoSync:
276 return Intrinsics::kUnsafePut;
277 case kVolatile:
278 return Intrinsics::kUnsafePutVolatile;
279 case kOrdered:
280 return Intrinsics::kUnsafePutOrdered;
281 }
282 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800283 case Primitive::kPrimLong:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800284 switch (sync) {
285 case kNoSync:
286 return Intrinsics::kUnsafePutLong;
287 case kVolatile:
288 return Intrinsics::kUnsafePutLongVolatile;
289 case kOrdered:
290 return Intrinsics::kUnsafePutLongOrdered;
291 }
292 break;
Andreas Gampe878d58c2015-01-15 23:24:00 -0800293 case Primitive::kPrimNot:
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800294 switch (sync) {
295 case kNoSync:
296 return Intrinsics::kUnsafePutObject;
297 case kVolatile:
298 return Intrinsics::kUnsafePutObjectVolatile;
299 case kOrdered:
300 return Intrinsics::kUnsafePutObjectOrdered;
301 }
302 break;
303 default:
304 LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
305 UNREACHABLE();
306 }
307 break;
308 }
309
310 // Virtual cases.
311
312 case kIntrinsicReferenceGetReferent:
313 return Intrinsics::kReferenceGetReferent;
314
315 // Quick inliner cases. Remove after refactoring. They are here so that we can use the
316 // compiler to warn on missing cases.
317
318 case kInlineOpNop:
319 case kInlineOpReturnArg:
320 case kInlineOpNonWideConst:
321 case kInlineOpIGet:
322 case kInlineOpIPut:
323 return Intrinsics::kNone;
324
Jeff Hao848f70a2014-01-15 13:49:50 -0800325 // String init cases, not intrinsics.
326
327 case kInlineStringInit:
328 return Intrinsics::kNone;
329
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800330 // No default case to make the compiler warn on missing cases.
331 }
332 return Intrinsics::kNone;
333}
334
335static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
336 // The DexFileMethodInliner should have checked whether the methods are agreeing with
337 // what we expect, i.e., static methods are called as such. Add another check here for
338 // our expectations:
339 // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
340 // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
341 // functions that will perform a check inline. If the precise type is known, however,
342 // the instruction will be sharpened to an InvokeStaticOrDirect.
343 InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
344 InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
345 invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
346 invoke->IsInvokeVirtual() ? kVirtual : kSuper;
347 switch (intrinsic_type) {
348 case kStatic:
349 return (invoke_type == kStatic);
350 case kDirect:
351 return (invoke_type == kDirect);
352 case kVirtual:
353 // Call might be devirtualized.
354 return (invoke_type == kVirtual || invoke_type == kDirect);
355
356 default:
357 return false;
358 }
359}
360
361// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
362void IntrinsicsRecognizer::Run() {
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800363 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
364 HBasicBlock* block = it.Current();
365 for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
366 inst_it.Advance()) {
367 HInstruction* inst = inst_it.Current();
368 if (inst->IsInvoke()) {
369 HInvoke* invoke = inst->AsInvoke();
370 InlineMethod method;
Nicolas Geoffray4daa0b42015-08-20 14:05:14 +0100371 const DexFile& dex_file = invoke->GetDexFile();
372 DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100373 DCHECK(inliner != nullptr);
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800374 if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
agicsaki6cff09a2015-08-12 21:20:43 -0700375 Intrinsics intrinsic = GetIntrinsic(method, graph_->GetInstructionSet());
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800376
377 if (intrinsic != Intrinsics::kNone) {
378 if (!CheckInvokeType(intrinsic, invoke)) {
Nicolas Geoffray4daa0b42015-08-20 14:05:14 +0100379 // We might be in a situation where we have inlined a method that calls an intrinsic,
380 // but that method is in a different dex file on which we do not have a
381 // verified_method that would have helped the compiler driver sharpen the call.
382 // We can still ensure the invoke types match by checking whether the called method
383 // is final or is in a final class.
384 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
385 {
386 ScopedObjectAccess soa(Thread::Current());
387 ArtMethod* art_method = class_linker->FindDexCache(dex_file)->GetResolvedMethod(
388 invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
389 DCHECK(art_method != nullptr);
390 if (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal()) {
391 invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
392 } else {
393 LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
394 << intrinsic << " for "
395 << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
396 << invoke->DebugName();
397 }
398 }
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800399 } else {
Agi Csaki05f20562015-08-19 14:58:14 -0700400 invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800401 }
402 }
403 }
404 }
405 }
406 }
407}
408
409std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
410 switch (intrinsic) {
411 case Intrinsics::kNone:
David Brazdil109c89a2015-07-31 17:10:43 +0100412 os << "None";
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800413 break;
Agi Csaki05f20562015-08-19 14:58:14 -0700414#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \
Andreas Gampe71fb52f2014-12-29 17:43:08 -0800415 case Intrinsics::k ## Name: \
416 os << # Name; \
417 break;
418#include "intrinsics_list.h"
419INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
420#undef STATIC_INTRINSICS_LIST
421#undef VIRTUAL_INTRINSICS_LIST
422#undef OPTIMIZING_INTRINSICS
423 }
424 return os;
425}
426
427} // namespace art