blob: 951b07585c7ed2ec242aa7c8a177d1ed60e66011 [file] [log] [blame]
/*
* 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 <algorithm>
#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
"<init>", // 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<uint16_t>(return_index);
DCHECK_EQ(static_cast<uint32_t>(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<uint16_t>(param_index);
DCHECK_EQ(static_cast<uint32_t>(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