171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe/*
271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * Copyright (C) 2015 The Android Open Source Project
371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe *
471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License");
571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * you may not use this file except in compliance with the License.
671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * You may obtain a copy of the License at
771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe *
871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe *      http://www.apache.org/licenses/LICENSE-2.0
971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe *
1071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * Unless required by applicable law or agreed to in writing, software
1171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS,
1271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * See the License for the specific language governing permissions and
1471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe * limitations under the License.
1571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe */
1671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
1771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "intrinsics.h"
1871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
1971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "dex/quick/dex_file_method_inliner.h"
2071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "dex/quick/dex_file_to_method_inliner_map.h"
2171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "driver/compiler_driver.h"
2271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "invoke_type.h"
2371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "nodes.h"
2471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "quick/inline_method_analyser.h"
2541b175aba41c9365a1c53b8a1afbd17129c87c14Vladimir Marko#include "utils.h"
2671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
2771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampenamespace art {
2871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
2971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe// Function that returns whether an intrinsic is static/direct or virtual.
3071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampestatic inline InvokeType GetIntrinsicInvokeType(Intrinsics i) {
3171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  switch (i) {
3271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case Intrinsics::kNone:
3371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return kInterface;  // Non-sensical for intrinsic.
3471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#define OPTIMIZING_INTRINSICS(Name, IsStatic) \
3571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case Intrinsics::k ## Name:               \
3671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return IsStatic;
3771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "intrinsics_list.h"
3871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas GampeINTRINSICS_LIST(OPTIMIZING_INTRINSICS)
3971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#undef INTRINSICS_LIST
4071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#undef OPTIMIZING_INTRINSICS
4171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  }
4271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  return kInterface;
4371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe}
4471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
4571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
4671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
4771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampestatic Primitive::Type GetType(uint64_t data, bool is_op_size) {
4871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  if (is_op_size) {
4971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    switch (static_cast<OpSize>(data)) {
5071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      case kSignedByte:
51878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        return Primitive::kPrimByte;
5271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      case kSignedHalf:
53878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        return Primitive::kPrimShort;
5471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      case k32:
55878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        return Primitive::kPrimInt;
5671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      case k64:
57878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        return Primitive::kPrimLong;
5871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      default:
5971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        LOG(FATAL) << "Unknown/unsupported op size " << data;
6071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        UNREACHABLE();
6171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    }
6271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  } else {
6371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    if ((data & kIntrinsicFlagIsLong) != 0) {
64878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe      return Primitive::kPrimLong;
6571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    }
6671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    if ((data & kIntrinsicFlagIsObject) != 0) {
67878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe      return Primitive::kPrimNot;
6871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    }
69878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe    return Primitive::kPrimInt;
7071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  }
7171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe}
7271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
7371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampestatic Intrinsics GetIntrinsic(InlineMethod method) {
7471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  switch (method.opcode) {
7571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Floating-point conversions.
7671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicDoubleCvt:
7771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
7871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
7971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicFloatCvt:
8071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
8171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
8271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
8371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Bit manipulations.
8471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicReverseBits:
8571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      switch (GetType(method.d.data, true)) {
86878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimInt:
8771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kIntegerReverse;
88878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimLong:
8971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kLongReverse;
9071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        default:
9171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
9271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          UNREACHABLE();
9371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      }
9471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicReverseBytes:
9571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      switch (GetType(method.d.data, true)) {
96878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimShort:
9771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kShortReverseBytes;
98878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimInt:
9971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kIntegerReverseBytes;
100878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimLong:
10171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kLongReverseBytes;
10271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        default:
10371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
10471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          UNREACHABLE();
10571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      }
10671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
10771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Abs.
10871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicAbsDouble:
10971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathAbsDouble;
11071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicAbsFloat:
11171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathAbsFloat;
11271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicAbsInt:
11371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathAbsInt;
11471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicAbsLong:
11571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathAbsLong;
11671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
11771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Min/max.
11871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicMinMaxDouble:
11971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
12071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
12171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicMinMaxFloat:
12271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
12371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
12471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicMinMaxInt:
12571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
12671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
12771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicMinMaxLong:
12871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
12971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
13071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
13171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Misc math.
13271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicSqrt:
13371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathSqrt;
13471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicCeil:
13571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathCeil;
13671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicFloor:
13771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathFloor;
13871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicRint:
13971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathRint;
14071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicRoundDouble:
14171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathRoundDouble;
14271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicRoundFloat:
14371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kMathRoundFloat;
14471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
14571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // System.arraycopy.
14671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicSystemArrayCopyCharArray:
14771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kSystemArrayCopyChar;
14871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
14971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Thread.currentThread.
15071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicCurrentThread:
15171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return  Intrinsics::kThreadCurrentThread;
15271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
15371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Memory.peek.
15471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicPeek:
15571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      switch (GetType(method.d.data, true)) {
156878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimByte:
15771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kMemoryPeekByte;
158878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimShort:
15971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kMemoryPeekShortNative;
160878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimInt:
16171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kMemoryPeekIntNative;
162878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimLong:
16371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kMemoryPeekLongNative;
16471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        default:
16571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
16671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          UNREACHABLE();
16771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      }
16871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
16971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Memory.poke.
17071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicPoke:
17171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      switch (GetType(method.d.data, true)) {
172878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimByte:
17371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kMemoryPokeByte;
174878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimShort:
17571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kMemoryPokeShortNative;
176878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimInt:
17771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kMemoryPokeIntNative;
178878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimLong:
17971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kMemoryPokeLongNative;
18071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        default:
18171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
18271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          UNREACHABLE();
18371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      }
18471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
18571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // String.
18671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicCharAt:
18771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kStringCharAt;
18871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicCompareTo:
18971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kStringCompareTo;
190848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao    case kIntrinsicGetCharsNoCheck:
191848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao      return Intrinsics::kStringGetCharsNoCheck;
19271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicIsEmptyOrLength:
1933e90a96f403cbc353731e6687fe12a088f996ceeRazvan A Lupusoru      // The inliner can handle these two cases - and this is the preferred approach
1943e90a96f403cbc353731e6687fe12a088f996ceeRazvan A Lupusoru      // since after inlining the call is no longer visible (as opposed to waiting
1953e90a96f403cbc353731e6687fe12a088f996ceeRazvan A Lupusoru      // until codegen to handle intrinsic).
1963e90a96f403cbc353731e6687fe12a088f996ceeRazvan A Lupusoru      return Intrinsics::kNone;
19771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicIndexOf:
19871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
19971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
200848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao    case kIntrinsicNewStringFromBytes:
201848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao      return Intrinsics::kStringNewStringFromBytes;
202848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao    case kIntrinsicNewStringFromChars:
203848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao      return Intrinsics::kStringNewStringFromChars;
204848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao    case kIntrinsicNewStringFromString:
205848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao      return Intrinsics::kStringNewStringFromString;
20671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
20771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicCas:
20871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      switch (GetType(method.d.data, false)) {
209878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimNot:
21071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kUnsafeCASObject;
211878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimInt:
21271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kUnsafeCASInt;
213878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimLong:
21471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return Intrinsics::kUnsafeCASLong;
21571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        default:
21671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
21771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          UNREACHABLE();
21871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      }
21971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicUnsafeGet: {
22071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
22171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      switch (GetType(method.d.data, false)) {
222878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimInt:
22371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
224878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimLong:
22571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
226878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimNot:
227878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe          return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
22871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        default:
22971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
23071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          UNREACHABLE();
23171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      }
23271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    }
23371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicUnsafePut: {
23471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      enum Sync { kNoSync, kVolatile, kOrdered };
23571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      const Sync sync =
23671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
23771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          ((method.d.data & kIntrinsicFlagIsOrdered) != 0)  ? kOrdered :
23871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe                                                              kNoSync;
23971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      switch (GetType(method.d.data, false)) {
240878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimInt:
24171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          switch (sync) {
24271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kNoSync:
24371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePut;
24471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kVolatile:
24571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePutVolatile;
24671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kOrdered:
24771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePutOrdered;
24871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          }
24971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          break;
250878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimLong:
25171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          switch (sync) {
25271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kNoSync:
25371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePutLong;
25471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kVolatile:
25571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePutLongVolatile;
25671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kOrdered:
25771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePutLongOrdered;
25871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          }
25971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          break;
260878d58cbaf6b17a9e3dcab790754527f3ebc69e5Andreas Gampe        case Primitive::kPrimNot:
26171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          switch (sync) {
26271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kNoSync:
26371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePutObject;
26471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kVolatile:
26571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePutObjectVolatile;
26671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            case kOrdered:
26771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              return Intrinsics::kUnsafePutObjectOrdered;
26871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          }
26971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          break;
27071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        default:
27171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
27271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          UNREACHABLE();
27371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      }
27471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      break;
27571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    }
27671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
27771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Virtual cases.
27871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
27971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kIntrinsicReferenceGetReferent:
28071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kReferenceGetReferent;
28171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
28271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // Quick inliner cases. Remove after refactoring. They are here so that we can use the
28371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // compiler to warn on missing cases.
28471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
28571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kInlineOpNop:
28671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kInlineOpReturnArg:
28771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kInlineOpNonWideConst:
28871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kInlineOpIGet:
28971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kInlineOpIPut:
29071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return Intrinsics::kNone;
29171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
292848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao    // String init cases, not intrinsics.
293848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
294848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao    case kInlineStringInit:
295848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao      return Intrinsics::kNone;
296848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
29771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    // No default case to make the compiler warn on missing cases.
29871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  }
29971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  return Intrinsics::kNone;
30071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe}
30171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
30271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampestatic bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
30371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  // The DexFileMethodInliner should have checked whether the methods are agreeing with
30471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  // what we expect, i.e., static methods are called as such. Add another check here for
30571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  // our expectations:
30671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
30771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
30871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  // functions that will perform a check inline. If the precise type is known, however,
30971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  // the instruction will be sharpened to an InvokeStaticOrDirect.
31071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
31171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
31271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
31371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      invoke->IsInvokeVirtual() ? kVirtual : kSuper;
31471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  switch (intrinsic_type) {
31571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kStatic:
31671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return (invoke_type == kStatic);
31771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kDirect:
31871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return (invoke_type == kDirect);
31971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case kVirtual:
32071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      // Call might be devirtualized.
32171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return (invoke_type == kVirtual || invoke_type == kDirect);
32271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
32371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    default:
32471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      return false;
32571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  }
32671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe}
32771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
32871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
32971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampevoid IntrinsicsRecognizer::Run() {
33071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(dex_file_);
33171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  DCHECK(inliner != nullptr);
33271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
33371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
33471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    HBasicBlock* block = it.Current();
33571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
33671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe         inst_it.Advance()) {
33771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      HInstruction* inst = inst_it.Current();
33871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      if (inst->IsInvoke()) {
33971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        HInvoke* invoke = inst->AsInvoke();
34071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        InlineMethod method;
34171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
34271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          Intrinsics intrinsic = GetIntrinsic(method);
34371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
34471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          if (intrinsic != Intrinsics::kNone) {
34571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            if (!CheckInvokeType(intrinsic, invoke)) {
34671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
34771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe                           << intrinsic << " for "
34871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe                           << PrettyMethod(invoke->GetDexMethodIndex(), *dex_file_);
34971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            } else {
35071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe              invoke->SetIntrinsic(intrinsic);
35171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe            }
35271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe          }
35371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe        }
35471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      }
35571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    }
35671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  }
35771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe}
35871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
35971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampestd::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
36071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  switch (intrinsic) {
36171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case Intrinsics::kNone:
36271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      os << "No intrinsic.";
36371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      break;
36471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#define OPTIMIZING_INTRINSICS(Name, IsStatic) \
36571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe    case Intrinsics::k ## Name: \
36671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      os << # Name; \
36771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe      break;
36871fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#include "intrinsics_list.h"
36971fb52fee246b7d511f520febbd73dc7a9bbca79Andreas GampeINTRINSICS_LIST(OPTIMIZING_INTRINSICS)
37071fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#undef STATIC_INTRINSICS_LIST
37171fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#undef VIRTUAL_INTRINSICS_LIST
37271fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe#undef OPTIMIZING_INTRINSICS
37371fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  }
37471fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe  return os;
37571fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe}
37671fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe
37771fb52fee246b7d511f520febbd73dc7a9bbca79Andreas Gampe}  // namespace art
378