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 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. 39#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \ 40 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 50// Function that returns whether an intrinsic needs an environment or not. 51static 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" 59INTRINSICS_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. 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 98static 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 124static 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 519static 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. 569void 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 604std::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" 614INTRINSICS_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