/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "dex_file_method_inliner.h" #include #include "base/logging.h" #include "base/macros.h" #include "base/mutex-inl.h" #include "driver/compiler_driver.h" #include "thread-inl.h" #include "dex_instruction-inl.h" #include "driver/dex_compilation_unit.h" #include "verifier/method_verifier-inl.h" namespace art { namespace { // anonymous namespace static constexpr bool kIntrinsicIsStatic[] = { true, // kIntrinsicDoubleCvt true, // kIntrinsicFloatCvt true, // kIntrinsicFloat2Int true, // kIntrinsicDouble2Long true, // kIntrinsicFloatIsInfinite true, // kIntrinsicDoubleIsInfinite true, // kIntrinsicFloatIsNaN true, // kIntrinsicDoubleIsNaN true, // kIntrinsicReverseBits true, // kIntrinsicReverseBytes true, // kIntrinsicBitCount true, // kIntrinsicCompare, true, // kIntrinsicHighestOneBit true, // kIntrinsicLowestOneBit true, // kIntrinsicNumberOfLeadingZeros true, // kIntrinsicNumberOfTrailingZeros true, // kIntrinsicRotateRight true, // kIntrinsicRotateLeft true, // kIntrinsicSignum true, // kIntrinsicAbsInt true, // kIntrinsicAbsLong true, // kIntrinsicAbsFloat true, // kIntrinsicAbsDouble true, // kIntrinsicMinMaxInt true, // kIntrinsicMinMaxLong true, // kIntrinsicMinMaxFloat true, // kIntrinsicMinMaxDouble true, // kIntrinsicCos true, // kIntrinsicSin true, // kIntrinsicAcos true, // kIntrinsicAsin true, // kIntrinsicAtan true, // kIntrinsicAtan2 true, // kIntrinsicCbrt true, // kIntrinsicCosh true, // kIntrinsicExp true, // kIntrinsicExpm1 true, // kIntrinsicHypot true, // kIntrinsicLog true, // kIntrinsicLog10 true, // kIntrinsicNextAfter true, // kIntrinsicSinh true, // kIntrinsicTan true, // kIntrinsicTanh true, // kIntrinsicSqrt true, // kIntrinsicCeil true, // kIntrinsicFloor true, // kIntrinsicRint true, // kIntrinsicRoundFloat true, // kIntrinsicRoundDouble false, // kIntrinsicReferenceGetReferent false, // kIntrinsicCharAt false, // kIntrinsicCompareTo false, // kIntrinsicEquals false, // kIntrinsicGetCharsNoCheck false, // kIntrinsicIsEmptyOrLength false, // kIntrinsicIndexOf true, // kIntrinsicNewStringFromBytes true, // kIntrinsicNewStringFromChars true, // kIntrinsicNewStringFromString true, // kIntrinsicCurrentThread true, // kIntrinsicPeek true, // kIntrinsicPoke false, // kIntrinsicCas false, // kIntrinsicUnsafeGet false, // kIntrinsicUnsafePut false, // kIntrinsicUnsafeGetAndAddInt, false, // kIntrinsicUnsafeGetAndAddLong, false, // kIntrinsicUnsafeGetAndSetInt, false, // kIntrinsicUnsafeGetAndSetLong, false, // kIntrinsicUnsafeGetAndSetObject, false, // kIntrinsicUnsafeLoadFence, false, // kIntrinsicUnsafeStoreFence, false, // kIntrinsicUnsafeFullFence, true, // kIntrinsicSystemArrayCopyCharArray true, // kIntrinsicSystemArrayCopy }; static_assert(arraysize(kIntrinsicIsStatic) == kInlineOpNop, "arraysize of kIntrinsicIsStatic unexpected"); static_assert(kIntrinsicIsStatic[kIntrinsicDoubleCvt], "DoubleCvt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicFloat2Int], "Float2Int must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicDouble2Long], "Double2Long must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsInfinite], "FloatIsInfinite must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsInfinite], "DoubleIsInfinite must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsNaN], "FloatIsNaN must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsNaN], "DoubleIsNaN must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicBitCount], "BitCount must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicCompare], "Compare must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicHighestOneBit], "HighestOneBit must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicLowestOneBit], "LowestOneBit must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfLeadingZeros], "NumberOfLeadingZeros must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfTrailingZeros], "NumberOfTrailingZeros must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicRotateRight], "RotateRight must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicRotateLeft], "RotateLeft must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSignum], "Signum must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsDouble], "AbsDouble must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxInt], "MinMaxInt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxLong], "MinMaxLong must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], "MinMaxFloat must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], "MinMaxDouble must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicCos], "Cos must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSin], "Sin must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAcos], "Acos must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAsin], "Asin must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAtan], "Atan must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAtan2], "Atan2 must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicCbrt], "Cbrt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicCosh], "Cosh must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicExp], "Exp must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicExpm1], "Expm1 must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicHypot], "Hypot must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicLog], "Log must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicLog10], "Log10 must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNextAfter], "NextAfter must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSinh], "Sinh must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicTan], "Tan must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicTanh], "Tanh must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSqrt], "Sqrt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicCeil], "Ceil must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicFloor], "Floor must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicRint], "Rint must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicRoundFloat], "RoundFloat must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicRoundDouble], "RoundDouble must be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], "Get must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicCharAt], "CharAt must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicCompareTo], "CompareTo must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicEquals], "String equals must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicGetCharsNoCheck], "GetCharsNoCheck must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], "IsEmptyOrLength must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicIndexOf], "IndexOf must not be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromBytes], "NewStringFromBytes must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromChars], "NewStringFromChars must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromString], "NewStringFromString must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicCurrentThread], "CurrentThread must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicPeek], "Peek must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicPoke], "Poke must be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicCas], "Cas must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], "UnsafeGet must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafePut], "UnsafePut must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndAddInt], "UnsafeGetAndAddInt must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndAddLong], "UnsafeGetAndAddLong must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetInt], "UnsafeGetAndSetInt must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetLong], "UnsafeGetAndSetLong must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetObject], "UnsafeGetAndSetObject must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeLoadFence], "UnsafeLoadFence must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeStoreFence], "UnsafeStoreFence must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeFullFence], "UnsafeFullFence must not be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray], "SystemArrayCopyCharArray must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopy], "SystemArrayCopy must be static"); } // anonymous namespace const uint32_t DexFileMethodInliner::kIndexUnresolved; const char* const DexFileMethodInliner::kClassCacheNames[] = { "Z", // kClassCacheBoolean "B", // kClassCacheByte "C", // kClassCacheChar "S", // kClassCacheShort "I", // kClassCacheInt "J", // kClassCacheLong "F", // kClassCacheFloat "D", // kClassCacheDouble "V", // kClassCacheVoid "[B", // kClassCacheJavaLangByteArray "[C", // kClassCacheJavaLangCharArray "[I", // kClassCacheJavaLangIntArray "Ljava/lang/Object;", // kClassCacheJavaLangObject "Ljava/lang/ref/Reference;", // kClassCacheJavaLangRefReference "Ljava/lang/String;", // kClassCacheJavaLangString "Ljava/lang/StringBuffer;", // kClassCacheJavaLangStringBuffer "Ljava/lang/StringBuilder;", // kClassCacheJavaLangStringBuilder "Ljava/lang/StringFactory;", // kClassCacheJavaLangStringFactory "Ljava/lang/Double;", // kClassCacheJavaLangDouble "Ljava/lang/Float;", // kClassCacheJavaLangFloat "Ljava/lang/Integer;", // kClassCacheJavaLangInteger "Ljava/lang/Long;", // kClassCacheJavaLangLong "Ljava/lang/Short;", // kClassCacheJavaLangShort "Ljava/lang/Math;", // kClassCacheJavaLangMath "Ljava/lang/StrictMath;", // kClassCacheJavaLangStrictMath "Ljava/lang/Thread;", // kClassCacheJavaLangThread "Ljava/nio/charset/Charset;", // kClassCacheJavaNioCharsetCharset "Llibcore/io/Memory;", // kClassCacheLibcoreIoMemory "Lsun/misc/Unsafe;", // kClassCacheSunMiscUnsafe "Ljava/lang/System;", // kClassCacheJavaLangSystem }; const char* const DexFileMethodInliner::kNameCacheNames[] = { "reverse", // kNameCacheReverse "reverseBytes", // kNameCacheReverseBytes "doubleToRawLongBits", // kNameCacheDoubleToRawLongBits "longBitsToDouble", // kNameCacheLongBitsToDouble "floatToRawIntBits", // kNameCacheFloatToRawIntBits "intBitsToFloat", // kNameCacheIntBitsToFloat "abs", // kNameCacheAbs "max", // kNameCacheMax "min", // kNameCacheMin "cos", // kNameCacheCos "sin", // kNameCacheSin "acos", // kNameCacheAcos "asin", // kNameCacheAsin "atan", // kNameCacheAtan "atan2", // kNameCacheAtan2 "cbrt", // kNameCacheCbrt "cosh", // kNameCacheCosh "exp", // kNameCacheExp "expm1", // kNameCacheExpm1 "hypot", // kNameCacheHypot "log", // kNameCacheLog "log10", // kNameCacheLog10 "nextAfter", // kNameCacheNextAfter "sinh", // kNameCacheSinh "tan", // kNameCacheTan "tanh", // kNameCacheTanh "sqrt", // kNameCacheSqrt "ceil", // kNameCacheCeil "floor", // kNameCacheFloor "rint", // kNameCacheRint "round", // kNameCacheRound "getReferent", // kNameCacheReferenceGet "charAt", // kNameCacheCharAt "compareTo", // kNameCacheCompareTo "equals", // kNameCacheEquals "getCharsNoCheck", // kNameCacheGetCharsNoCheck "isEmpty", // kNameCacheIsEmpty "floatToIntBits", // kNameCacheFloatToIntBits "doubleToLongBits", // kNameCacheDoubleToLongBits "isInfinite", // kNameCacheIsInfinite "isNaN", // kNameCacheIsNaN "indexOf", // kNameCacheIndexOf "length", // kNameCacheLength "", // kNameCacheInit "newStringFromBytes", // kNameCacheNewStringFromBytes "newStringFromChars", // kNameCacheNewStringFromChars "newStringFromString", // kNameCacheNewStringFromString "currentThread", // kNameCacheCurrentThread "peekByte", // kNameCachePeekByte "peekIntNative", // kNameCachePeekIntNative "peekLongNative", // kNameCachePeekLongNative "peekShortNative", // kNameCachePeekShortNative "pokeByte", // kNameCachePokeByte "pokeIntNative", // kNameCachePokeIntNative "pokeLongNative", // kNameCachePokeLongNative "pokeShortNative", // kNameCachePokeShortNative "compareAndSwapInt", // kNameCacheCompareAndSwapInt "compareAndSwapLong", // kNameCacheCompareAndSwapLong "compareAndSwapObject", // kNameCacheCompareAndSwapObject "getInt", // kNameCacheGetInt "getIntVolatile", // kNameCacheGetIntVolatile "putInt", // kNameCachePutInt "putIntVolatile", // kNameCachePutIntVolatile "putOrderedInt", // kNameCachePutOrderedInt "getLong", // kNameCacheGetLong "getLongVolatile", // kNameCacheGetLongVolatile "putLong", // kNameCachePutLong "putLongVolatile", // kNameCachePutLongVolatile "putOrderedLong", // kNameCachePutOrderedLong "getObject", // kNameCacheGetObject "getObjectVolatile", // kNameCacheGetObjectVolatile "putObject", // kNameCachePutObject "putObjectVolatile", // kNameCachePutObjectVolatile "putOrderedObject", // kNameCachePutOrderedObject "getAndAddInt", // kNameCacheGetAndAddInt, "getAndAddLong", // kNameCacheGetAndAddLong, "getAndSetInt", // kNameCacheGetAndSetInt, "getAndSetLong", // kNameCacheGetAndSetLong, "getAndSetObject", // kNameCacheGetAndSetObject, "loadFence", // kNameCacheLoadFence, "storeFence", // kNameCacheStoreFence, "fullFence", // kNameCacheFullFence, "arraycopy", // kNameCacheArrayCopy "bitCount", // kNameCacheBitCount "compare", // kNameCacheCompare "highestOneBit", // kNameCacheHighestOneBit "lowestOneBit", // kNameCacheLowestOneBit "numberOfLeadingZeros", // kNameCacheNumberOfLeadingZeros "numberOfTrailingZeros", // kNameCacheNumberOfTrailingZeros "rotateRight", // kNameCacheRotateRight "rotateLeft", // kNameCacheRotateLeft "signum", // kNameCacheSignum }; const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { // kProtoCacheI_I { kClassCacheInt, 1, { kClassCacheInt } }, // kProtoCacheJ_J { kClassCacheLong, 1, { kClassCacheLong } }, // kProtoCacheS_S { kClassCacheShort, 1, { kClassCacheShort } }, // kProtoCacheD_D { kClassCacheDouble, 1, { kClassCacheDouble } }, // kProtoCacheDD_D { kClassCacheDouble, 2, { kClassCacheDouble, kClassCacheDouble } }, // kProtoCacheF_F { kClassCacheFloat, 1, { kClassCacheFloat } }, // kProtoCacheFF_F { kClassCacheFloat, 2, { kClassCacheFloat, kClassCacheFloat } }, // kProtoCacheD_J { kClassCacheLong, 1, { kClassCacheDouble } }, // kProtoCacheD_Z { kClassCacheBoolean, 1, { kClassCacheDouble } }, // kProtoCacheJ_D { kClassCacheDouble, 1, { kClassCacheLong } }, // kProtoCacheF_I { kClassCacheInt, 1, { kClassCacheFloat } }, // kProtoCacheF_Z { kClassCacheBoolean, 1, { kClassCacheFloat } }, // kProtoCacheI_F { kClassCacheFloat, 1, { kClassCacheInt } }, // kProtoCacheII_I { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } }, // kProtoCacheI_C { kClassCacheChar, 1, { kClassCacheInt } }, // kProtoCacheString_I { kClassCacheInt, 1, { kClassCacheJavaLangString } }, // kProtoCache_Z { kClassCacheBoolean, 0, { } }, // kProtoCache_I { kClassCacheInt, 0, { } }, // kProtoCache_Object { kClassCacheJavaLangObject, 0, { } }, // kProtoCache_Thread { kClassCacheJavaLangThread, 0, { } }, // kProtoCacheJ_B { kClassCacheByte, 1, { kClassCacheLong } }, // kProtoCacheJ_I { kClassCacheInt, 1, { kClassCacheLong } }, // kProtoCacheJ_S { kClassCacheShort, 1, { kClassCacheLong } }, // kProtoCacheJB_V { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } }, // kProtoCacheJI_V { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } }, // kProtoCacheJJ_J { kClassCacheLong, 2, { kClassCacheLong, kClassCacheLong } }, // kProtoCacheJJ_I { kClassCacheInt, 2, { kClassCacheLong, kClassCacheLong } }, // kProtoCacheJJ_V { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } }, // kProtoCacheJS_V { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } }, // kProtoCacheObject_Z { kClassCacheBoolean, 1, { kClassCacheJavaLangObject } }, // kProtoCacheJI_J { kClassCacheLong, 2, { kClassCacheLong, kClassCacheInt } }, // kProtoCacheObjectJII_Z { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt, kClassCacheInt } }, // kProtoCacheObjectJJJ_Z { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong, kClassCacheLong } }, // kProtoCacheObjectJObjectObject_Z { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheJavaLangObject, kClassCacheJavaLangObject } }, // kProtoCacheObjectJ_I { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, // kProtoCacheObjectJI_I { kClassCacheInt, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } }, // kProtoCacheObjectJI_V { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } }, // kProtoCacheObjectJ_J { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, // kProtoCacheObjectJJ_J { kClassCacheLong, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } }, // kProtoCacheObjectJJ_V { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } }, // kProtoCacheObjectJ_Object { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } }, // kProtoCacheObjectJObject_V { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheJavaLangObject } }, // kProtoCacheObjectJObject_Object { kClassCacheJavaLangObject, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheJavaLangObject } }, // kProtoCacheCharArrayICharArrayII_V { kClassCacheVoid, 5, {kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt} }, // kProtoCacheObjectIObjectII_V { kClassCacheVoid, 5, {kClassCacheJavaLangObject, kClassCacheInt, kClassCacheJavaLangObject, kClassCacheInt, kClassCacheInt} }, // kProtoCacheIICharArrayI_V { kClassCacheVoid, 4, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray, kClassCacheInt } }, // kProtoCacheByteArrayIII_String { kClassCacheJavaLangString, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt, kClassCacheInt } }, // kProtoCacheIICharArray_String { kClassCacheJavaLangString, 3, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray } }, // kProtoCacheString_String { kClassCacheJavaLangString, 1, { kClassCacheJavaLangString } }, // kProtoCache_V { kClassCacheVoid, 0, { } }, // kProtoCacheByteArray_V { kClassCacheVoid, 1, { kClassCacheJavaLangByteArray } }, // kProtoCacheByteArrayI_V { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheInt } }, // kProtoCacheByteArrayII_V { kClassCacheVoid, 3, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt } }, // kProtoCacheByteArrayIII_V { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt, kClassCacheInt } }, // kProtoCacheByteArrayIIString_V { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt, kClassCacheJavaLangString } }, // kProtoCacheByteArrayString_V { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaLangString } }, // kProtoCacheByteArrayIICharset_V { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt, kClassCacheJavaNioCharsetCharset } }, // kProtoCacheByteArrayCharset_V { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaNioCharsetCharset } }, // kProtoCacheCharArray_V { kClassCacheVoid, 1, { kClassCacheJavaLangCharArray } }, // kProtoCacheCharArrayII_V { kClassCacheVoid, 3, { kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt } }, // kProtoCacheIICharArray_V { kClassCacheVoid, 3, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray } }, // kProtoCacheIntArrayII_V { kClassCacheVoid, 3, { kClassCacheJavaLangIntArray, kClassCacheInt, kClassCacheInt } }, // kProtoCacheString_V { kClassCacheVoid, 1, { kClassCacheJavaLangString } }, // kProtoCacheStringBuffer_V { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuffer } }, // kProtoCacheStringBuilder_V { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuilder } }, }; const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = { #define INTRINSIC(c, n, p, o, d) \ { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } } INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0), INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, kIntrinsicFlagToFloatingPoint), INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, kIntrinsicFlagToFloatingPoint), INTRINSIC(JavaLangFloat, FloatToIntBits, F_I, kIntrinsicFloat2Int, 0), INTRINSIC(JavaLangDouble, DoubleToLongBits, D_J, kIntrinsicDouble2Long, 0), INTRINSIC(JavaLangFloat, IsInfinite, F_Z, kIntrinsicFloatIsInfinite, 0), INTRINSIC(JavaLangDouble, IsInfinite, D_Z, kIntrinsicDoubleIsInfinite, 0), INTRINSIC(JavaLangFloat, IsNaN, F_Z, kIntrinsicFloatIsNaN, 0), INTRINSIC(JavaLangDouble, IsNaN, D_Z, kIntrinsicDoubleIsNaN, 0), INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32), INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64), INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf), INTRINSIC(JavaLangInteger, Reverse, I_I, kIntrinsicReverseBits, k32), INTRINSIC(JavaLangLong, Reverse, J_J, kIntrinsicReverseBits, k64), INTRINSIC(JavaLangInteger, BitCount, I_I, kIntrinsicBitCount, k32), INTRINSIC(JavaLangLong, BitCount, J_I, kIntrinsicBitCount, k64), INTRINSIC(JavaLangInteger, Compare, II_I, kIntrinsicCompare, k32), INTRINSIC(JavaLangLong, Compare, JJ_I, kIntrinsicCompare, k64), INTRINSIC(JavaLangInteger, HighestOneBit, I_I, kIntrinsicHighestOneBit, k32), INTRINSIC(JavaLangLong, HighestOneBit, J_J, kIntrinsicHighestOneBit, k64), INTRINSIC(JavaLangInteger, LowestOneBit, I_I, kIntrinsicLowestOneBit, k32), INTRINSIC(JavaLangLong, LowestOneBit, J_J, kIntrinsicLowestOneBit, k64), INTRINSIC(JavaLangInteger, NumberOfLeadingZeros, I_I, kIntrinsicNumberOfLeadingZeros, k32), INTRINSIC(JavaLangLong, NumberOfLeadingZeros, J_I, kIntrinsicNumberOfLeadingZeros, k64), INTRINSIC(JavaLangInteger, NumberOfTrailingZeros, I_I, kIntrinsicNumberOfTrailingZeros, k32), INTRINSIC(JavaLangLong, NumberOfTrailingZeros, J_I, kIntrinsicNumberOfTrailingZeros, k64), INTRINSIC(JavaLangInteger, Signum, I_I, kIntrinsicSignum, k32), INTRINSIC(JavaLangLong, Signum, J_I, kIntrinsicSignum, k64), INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0), INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0), INTRINSIC(JavaLangMath, Abs, F_F, kIntrinsicAbsFloat, 0), INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0), INTRINSIC(JavaLangMath, Abs, D_D, kIntrinsicAbsDouble, 0), INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0), INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), INTRINSIC(JavaLangMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin), INTRINSIC(JavaLangStrictMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin), INTRINSIC(JavaLangMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax), INTRINSIC(JavaLangStrictMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax), INTRINSIC(JavaLangMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin), INTRINSIC(JavaLangStrictMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin), INTRINSIC(JavaLangMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax), INTRINSIC(JavaLangStrictMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax), INTRINSIC(JavaLangMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin), INTRINSIC(JavaLangStrictMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin), INTRINSIC(JavaLangMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax), INTRINSIC(JavaLangStrictMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax), INTRINSIC(JavaLangMath, Cos, D_D, kIntrinsicCos, 0), INTRINSIC(JavaLangMath, Sin, D_D, kIntrinsicSin, 0), INTRINSIC(JavaLangMath, Acos, D_D, kIntrinsicAcos, 0), INTRINSIC(JavaLangMath, Asin, D_D, kIntrinsicAsin, 0), INTRINSIC(JavaLangMath, Atan, D_D, kIntrinsicAtan, 0), INTRINSIC(JavaLangMath, Atan2, DD_D, kIntrinsicAtan2, 0), INTRINSIC(JavaLangMath, Cbrt, D_D, kIntrinsicCbrt, 0), INTRINSIC(JavaLangMath, Cosh, D_D, kIntrinsicCosh, 0), INTRINSIC(JavaLangMath, Exp, D_D, kIntrinsicExp, 0), INTRINSIC(JavaLangMath, Expm1, D_D, kIntrinsicExpm1, 0), INTRINSIC(JavaLangMath, Hypot, DD_D, kIntrinsicHypot, 0), INTRINSIC(JavaLangMath, Log, D_D, kIntrinsicLog, 0), INTRINSIC(JavaLangMath, Log10, D_D, kIntrinsicLog10, 0), INTRINSIC(JavaLangMath, NextAfter, DD_D, kIntrinsicNextAfter, 0), INTRINSIC(JavaLangMath, Sinh, D_D, kIntrinsicSinh, 0), INTRINSIC(JavaLangMath, Tan, D_D, kIntrinsicTan, 0), INTRINSIC(JavaLangMath, Tanh, D_D, kIntrinsicTanh, 0), INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), INTRINSIC(JavaLangMath, Ceil, D_D, kIntrinsicCeil, 0), INTRINSIC(JavaLangStrictMath, Ceil, D_D, kIntrinsicCeil, 0), INTRINSIC(JavaLangMath, Floor, D_D, kIntrinsicFloor, 0), INTRINSIC(JavaLangStrictMath, Floor, D_D, kIntrinsicFloor, 0), INTRINSIC(JavaLangMath, Rint, D_D, kIntrinsicRint, 0), INTRINSIC(JavaLangStrictMath, Rint, D_D, kIntrinsicRint, 0), INTRINSIC(JavaLangMath, Round, F_I, kIntrinsicRoundFloat, 0), INTRINSIC(JavaLangStrictMath, Round, F_I, kIntrinsicRoundFloat, 0), INTRINSIC(JavaLangMath, Round, D_J, kIntrinsicRoundDouble, 0), INTRINSIC(JavaLangStrictMath, Round, D_J, kIntrinsicRoundDouble, 0), INTRINSIC(JavaLangRefReference, ReferenceGetReferent, _Object, kIntrinsicReferenceGetReferent, 0), INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), INTRINSIC(JavaLangString, Equals, Object_Z, kIntrinsicEquals, 0), INTRINSIC(JavaLangString, GetCharsNoCheck, IICharArrayI_V, kIntrinsicGetCharsNoCheck, 0), INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone), INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0), INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength), INTRINSIC(JavaLangStringFactory, NewStringFromBytes, ByteArrayIII_String, kIntrinsicNewStringFromBytes, kIntrinsicFlagNone), INTRINSIC(JavaLangStringFactory, NewStringFromChars, IICharArray_String, kIntrinsicNewStringFromChars, kIntrinsicFlagNone), INTRINSIC(JavaLangStringFactory, NewStringFromString, String_String, kIntrinsicNewStringFromString, kIntrinsicFlagNone), INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0), INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte), INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, k32), INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, k64), INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf), INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte), INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, k32), INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, k64), INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf), INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas, kIntrinsicFlagNone), INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas, kIntrinsicFlagIsLong), INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas, kIntrinsicFlagIsObject), #define UNSAFE_GET_PUT(type, code, type_flags) \ INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ type_flags), \ INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ type_flags | kIntrinsicFlagIsVolatile), \ INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ type_flags), \ INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ type_flags | kIntrinsicFlagIsVolatile), \ INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ type_flags | kIntrinsicFlagIsOrdered) UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone), UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong), UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject), #undef UNSAFE_GET_PUT // 1.8 INTRINSIC(SunMiscUnsafe, GetAndAddInt, ObjectJI_I, kIntrinsicUnsafeGetAndAddInt, 0), INTRINSIC(SunMiscUnsafe, GetAndAddLong, ObjectJJ_J, kIntrinsicUnsafeGetAndAddLong, 0), INTRINSIC(SunMiscUnsafe, GetAndSetInt, ObjectJI_I, kIntrinsicUnsafeGetAndSetInt, 0), INTRINSIC(SunMiscUnsafe, GetAndSetLong, ObjectJJ_J, kIntrinsicUnsafeGetAndSetLong, 0), INTRINSIC(SunMiscUnsafe, GetAndSetObject, ObjectJObject_Object, kIntrinsicUnsafeGetAndSetObject, 0), INTRINSIC(SunMiscUnsafe, LoadFence, _V, kIntrinsicUnsafeLoadFence, 0), INTRINSIC(SunMiscUnsafe, StoreFence, _V, kIntrinsicUnsafeStoreFence, 0), INTRINSIC(SunMiscUnsafe, FullFence, _V, kIntrinsicUnsafeFullFence, 0), INTRINSIC(JavaLangSystem, ArrayCopy, CharArrayICharArrayII_V , kIntrinsicSystemArrayCopyCharArray, 0), INTRINSIC(JavaLangSystem, ArrayCopy, ObjectIObjectII_V , kIntrinsicSystemArrayCopy, 0), INTRINSIC(JavaLangInteger, RotateRight, II_I, kIntrinsicRotateRight, k32), INTRINSIC(JavaLangLong, RotateRight, JI_J, kIntrinsicRotateRight, k64), INTRINSIC(JavaLangInteger, RotateLeft, II_I, kIntrinsicRotateLeft, k32), INTRINSIC(JavaLangLong, RotateLeft, JI_J, kIntrinsicRotateLeft, k64), #undef INTRINSIC #define SPECIAL(c, n, p, o, d) \ { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineSpecial, { d } } } SPECIAL(JavaLangString, Init, _V, kInlineStringInit, 0), SPECIAL(JavaLangString, Init, ByteArray_V, kInlineStringInit, 1), SPECIAL(JavaLangString, Init, ByteArrayI_V, kInlineStringInit, 2), SPECIAL(JavaLangString, Init, ByteArrayII_V, kInlineStringInit, 3), SPECIAL(JavaLangString, Init, ByteArrayIII_V, kInlineStringInit, 4), SPECIAL(JavaLangString, Init, ByteArrayIIString_V, kInlineStringInit, 5), SPECIAL(JavaLangString, Init, ByteArrayString_V, kInlineStringInit, 6), SPECIAL(JavaLangString, Init, ByteArrayIICharset_V, kInlineStringInit, 7), SPECIAL(JavaLangString, Init, ByteArrayCharset_V, kInlineStringInit, 8), SPECIAL(JavaLangString, Init, CharArray_V, kInlineStringInit, 9), SPECIAL(JavaLangString, Init, CharArrayII_V, kInlineStringInit, 10), SPECIAL(JavaLangString, Init, IICharArray_V, kInlineStringInit, 11), SPECIAL(JavaLangString, Init, IntArrayII_V, kInlineStringInit, 12), SPECIAL(JavaLangString, Init, String_V, kInlineStringInit, 13), SPECIAL(JavaLangString, Init, StringBuffer_V, kInlineStringInit, 14), SPECIAL(JavaLangString, Init, StringBuilder_V, kInlineStringInit, 15), #undef SPECIAL }; DexFileMethodInliner::DexFileMethodInliner() : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock), dex_file_(nullptr) { static_assert(kClassCacheFirst == 0, "kClassCacheFirst not 0"); static_assert(arraysize(kClassCacheNames) == kClassCacheLast, "bad arraysize for kClassCacheNames"); static_assert(kNameCacheFirst == 0, "kNameCacheFirst not 0"); static_assert(arraysize(kNameCacheNames) == kNameCacheLast, "bad arraysize for kNameCacheNames"); static_assert(kProtoCacheFirst == 0, "kProtoCacheFirst not 0"); static_assert(arraysize(kProtoCacheDefs) == kProtoCacheLast, "bad arraysize kProtoCacheNames"); } DexFileMethodInliner::~DexFileMethodInliner() { } bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) { InlineMethod method; bool success = InlineMethodAnalyser::AnalyseMethodCode(verifier, &method); return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method); } InlineMethodFlags DexFileMethodInliner::IsIntrinsicOrSpecial(uint32_t method_index) { ReaderMutexLock mu(Thread::Current(), lock_); auto it = inline_methods_.find(method_index); if (it != inline_methods_.end()) { DCHECK_NE(it->second.flags & (kInlineIntrinsic | kInlineSpecial), 0); return it->second.flags; } else { return kNoInlineMethodFlags; } } bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) { ReaderMutexLock mu(Thread::Current(), lock_); auto it = inline_methods_.find(method_index); bool res = (it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0); if (res && intrinsic != nullptr) { *intrinsic = it->second; } return res; } bool DexFileMethodInliner::IsSpecial(uint32_t method_index) { ReaderMutexLock mu(Thread::Current(), lock_); auto it = inline_methods_.find(method_index); return it != inline_methods_.end() && (it->second.flags & kInlineSpecial) != 0; } uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache, ClassCacheIndex index) { uint32_t* class_index = &cache->class_indexes[index]; if (*class_index != kIndexUnresolved) { return *class_index; } const DexFile::TypeId* type_id = dex_file->FindTypeId(kClassCacheNames[index]); if (type_id == nullptr) { *class_index = kIndexNotFound; return *class_index; } *class_index = dex_file->GetIndexForTypeId(*type_id); return *class_index; } uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache, NameCacheIndex index) { uint32_t* name_index = &cache->name_indexes[index]; if (*name_index != kIndexUnresolved) { return *name_index; } const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]); if (string_id == nullptr) { *name_index = kIndexNotFound; return *name_index; } *name_index = dex_file->GetIndexForStringId(*string_id); return *name_index; } uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache, ProtoCacheIndex index) { uint32_t* proto_index = &cache->proto_indexes[index]; if (*proto_index != kIndexUnresolved) { return *proto_index; } const ProtoDef& proto_def = kProtoCacheDefs[index]; uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type); if (return_index == kIndexNotFound) { *proto_index = kIndexNotFound; return *proto_index; } uint16_t return_type = static_cast(return_index); DCHECK_EQ(static_cast(return_type), return_index); uint32_t signature_length = proto_def.param_count; uint16_t signature_type_idxs[kProtoMaxParams]; for (uint32_t i = 0; i != signature_length; ++i) { uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]); if (param_index == kIndexNotFound) { *proto_index = kIndexNotFound; return *proto_index; } signature_type_idxs[i] = static_cast(param_index); DCHECK_EQ(static_cast(signature_type_idxs[i]), param_index); } const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs, signature_length); if (proto_id == nullptr) { *proto_index = kIndexNotFound; return *proto_index; } *proto_index = dex_file->GetIndexForProtoId(*proto_id); return *proto_index; } uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache, const MethodDef& method_def) { uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class); if (declaring_class_index == kIndexNotFound) { return kIndexNotFound; } uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name); if (name_index == kIndexNotFound) { return kIndexNotFound; } uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto); if (proto_index == kIndexNotFound) { return kIndexNotFound; } const DexFile::MethodId* method_id = dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index), dex_file->GetStringId(name_index), dex_file->GetProtoId(proto_index)); if (method_id == nullptr) { return kIndexNotFound; } return dex_file->GetIndexForMethodId(*method_id); } DexFileMethodInliner::IndexCache::IndexCache() { std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved); std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved); std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved); } void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { DCHECK(dex_file != nullptr); DCHECK(dex_file_ == nullptr); IndexCache cache; for (const IntrinsicDef& def : kIntrinsicMethods) { uint32_t method_idx = FindMethodIndex(dex_file, &cache, def.method_def); if (method_idx != kIndexNotFound) { DCHECK(inline_methods_.find(method_idx) == inline_methods_.end()); inline_methods_.Put(method_idx, def.intrinsic); } } dex_file_ = dex_file; } bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) { WriterMutexLock mu(Thread::Current(), lock_); if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) { inline_methods_.Put(method_idx, method); return true; } else { if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") { // TODO: String.length is both kIntrinsicIsEmptyOrLength and kInlineOpIGet. } else { LOG(WARNING) << "Inliner: " << PrettyMethod(method_idx, *dex_file_) << " already inline"; } return false; } } uint32_t DexFileMethodInliner::GetOffsetForStringInit(uint32_t method_index, size_t pointer_size) { ReaderMutexLock mu(Thread::Current(), lock_); auto it = inline_methods_.find(method_index); if (it != inline_methods_.end() && (it->second.opcode == kInlineStringInit)) { uint32_t string_init_base_offset = Thread::QuickEntryPointOffsetWithSize( OFFSETOF_MEMBER(QuickEntryPoints, pNewEmptyString), pointer_size); return string_init_base_offset + it->second.d.data * pointer_size; } return 0; } bool DexFileMethodInliner::IsStringInitMethodIndex(uint32_t method_index) { ReaderMutexLock mu(Thread::Current(), lock_); auto it = inline_methods_.find(method_index); return (it != inline_methods_.end()) && (it->second.opcode == kInlineStringInit); } } // namespace art