diff options
Diffstat (limited to 'compiler/dex/quick/dex_file_method_inliner.h')
-rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.h | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h new file mode 100644 index 0000000000..95b8dd3adf --- /dev/null +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -0,0 +1,318 @@ +/* + * 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. + */ + +#ifndef ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ +#define ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ + +#include <stdint.h> +#include <map> + +namespace art { + +class CallInfo; +class DexFile; +class Mir2Lir; + +enum IntrinsicOpcode { + kIntrinsicDoubleCvt, + kIntrinsicFloatCvt, + kIntrinsicReverseBytes, + kIntrinsicAbsInt, + kIntrinsicAbsLong, + kIntrinsicMinMaxInt, + kIntrinsicSqrt, + kIntrinsicCharAt, + kIntrinsicCompareTo, + kIntrinsicIsEmptyOrLength, + kIntrinsicIndexOf, + kIntrinsicCurrentThread, + kIntrinsicPeek, + kIntrinsicPoke, + kIntrinsicCas32, + kIntrinsicUnsafeGet, + kIntrinsicUnsafePut, +}; + +enum IntrinsicFlags { + kIntrinsicFlagNone = 0, + + // kIntrinsicMinMaxInt + kIntrinsicFlagMax = kIntrinsicFlagNone, + kIntrinsicFlagMin = 1, + + // kIntrinsicIsEmptyOrLength + kIntrinsicFlagLength = kIntrinsicFlagNone, + kIntrinsicFlagIsEmpty = 1, + + // kIntrinsicIndexOf + kIntrinsicFlagBase0 = 1, + + // kIntrinsicUnsafeCas32 + kIntrinsicFlagDontNeedWriteBarrier = 0, + kIntrinsicFlagNeedWriteBarrier = 1, + + // kIntrinsicUnsafeGet, kIntrinsicUnsafePut + kIntrinsicFlagIsLong = 1, + kIntrinsicFlagIsVolatile = 2, + // kIntrinsicUnsafePut + kIntrinsicFlagIsObject = 4, + kIntrinsicFlagIsOrdered = 8, +}; + +struct Intrinsic { + IntrinsicOpcode opcode; + uint32_t data; +}; + +/** + * Handles inlining of methods from a particular DexFile. + * + * Intrinsics are a special case of inline methods. The DexFile indices for + * all the supported intrinsic methods are looked up once by the FindIntrinsics + * function and cached by this class for quick lookup by the method index. + * + * TODO: Detect short methods (at least getters, setters and empty functions) + * from the verifier and mark them for inlining. Inline these methods early + * during compilation to allow further optimizations. Similarly, provide + * additional information about intrinsics to the early phases of compilation. + */ +class DexFileMethodInliner { + public: + virtual ~DexFileMethodInliner(); + + /** + * Find all known intrinsic methods in the dex_file and cache their indices. + */ + virtual void FindIntrinsics(const DexFile* dex_file) = 0; + + /** + * Check whether a particular method index corresponds to an intrinsic function. + */ + bool IsIntrinsic(uint32_t method_index) const; + + /** + * Generate code for an intrinsic function invocation. + * + * TODO: This should be target-specific. For the time being, + * it's shared since it dispatches everything to backend. + */ + bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const; + + protected: + DexFileMethodInliner(); + + /** + * To avoid multiple lookups of a class by its descriptor, we cache its + * type index in the IndexCache. These are the indexes into the IndexCache + * class_indexes array. + */ + enum ClassCacheIndex : uint8_t { // unit8_t to save space, make larger if needed + kClassCacheFirst = 0, + kClassCacheBoolean = kClassCacheFirst, + kClassCacheByte, + kClassCacheChar, + kClassCacheShort, + kClassCacheInt, + kClassCacheLong, + kClassCacheFloat, + kClassCacheDouble, + kClassCacheVoid, + kClassCacheJavaLangObject, + kClassCacheJavaLangString, + kClassCacheJavaLangDouble, + kClassCacheJavaLangFloat, + kClassCacheJavaLangInteger, + kClassCacheJavaLangLong, + kClassCacheJavaLangShort, + kClassCacheJavaLangMath, + kClassCacheJavaLangStrictMath, + kClassCacheJavaLangThread, + kClassCacheLibcoreIoMemory, + kClassCacheSunMiscUnsafe, + kClassCacheLast + }; + + /** + * To avoid multiple lookups of a method name string, we cache its string + * index in the IndexCache. These are the indexes into the IndexCache + * name_indexes array. + */ + enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed + kNameCacheFirst = 0, + kNameCacheReverseBytes = kNameCacheFirst, + kNameCacheDoubleToRawLongBits, + kNameCacheLongBitsToDouble, + kNameCacheFloatToRawIntBits, + kNameCacheIntBitsToFloat, + kNameCacheAbs, + kNameCacheMax, + kNameCacheMin, + kNameCacheSqrt, + kNameCacheCharAt, + kNameCacheCompareTo, + kNameCacheIsEmpty, + kNameCacheIndexOf, + kNameCacheLength, + kNameCacheCurrentThread, + kNameCachePeekByte, + kNameCachePeekIntNative, + kNameCachePeekLongNative, + kNameCachePeekShortNative, + kNameCachePokeByte, + kNameCachePokeIntNative, + kNameCachePokeLongNative, + kNameCachePokeShortNative, + kNameCacheCompareAndSwapInt, + kNameCacheCompareAndSwapObject, + kNameCacheGetInt, + kNameCacheGetIntVolatile, + kNameCachePutInt, + kNameCachePutIntVolatile, + kNameCachePutOrderedInt, + kNameCacheGetLong, + kNameCacheGetLongVolatile, + kNameCachePutLong, + kNameCachePutLongVolatile, + kNameCachePutOrderedLong, + kNameCacheGetObject, + kNameCacheGetObjectVolatile, + kNameCachePutObject, + kNameCachePutObjectVolatile, + kNameCachePutOrderedObject, + kNameCacheLast + }; + + /** + * To avoid multiple lookups of a method signature, we cache its proto + * index in the IndexCache. These are the indexes into the IndexCache + * proto_indexes array. + */ + enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed + kProtoCacheFirst = 0, + kProtoCacheI_I = kProtoCacheFirst, + kProtoCacheJ_J, + kProtoCacheS_S, + kProtoCacheD_D, + kProtoCacheD_J, + kProtoCacheJ_D, + kProtoCacheF_I, + kProtoCacheI_F, + kProtoCacheII_I, + kProtoCacheI_C, + kProtoCacheString_I, + kProtoCache_Z, + kProtoCache_I, + kProtoCache_Thread, + kProtoCacheJ_B, + kProtoCacheJ_I, + kProtoCacheJ_S, + kProtoCacheJB_V, + kProtoCacheJI_V, + kProtoCacheJJ_V, + kProtoCacheJS_V, + kProtoCacheObjectJII_Z, + kProtoCacheObjectJObjectObject_Z, + kProtoCacheObjectJ_I, + kProtoCacheObjectJI_V, + kProtoCacheObjectJ_J, + kProtoCacheObjectJJ_V, + kProtoCacheObjectJ_Object, + kProtoCacheObjectJObject_V, + kProtoCacheLast + }; + + /** + * The maximum number of method parameters we support in the ProtoDef. + */ + static constexpr uint32_t kProtoMaxParams = 6; + + /** + * The method signature (proto) definition using cached class indexes. + * The return_type and params are used with the IndexCache to look up + * appropriate class indexes to be passed to DexFile::FindProtoId(). + */ + struct ProtoDef { + ClassCacheIndex return_type; + uint8_t param_count; + ClassCacheIndex params[kProtoMaxParams]; + }; + + /** + * The method definition using cached class, name and proto indexes. + * The class index, method name index and proto index are used with + * IndexCache to look up appropriate parameters for DexFile::FindMethodId(). + */ + struct MethodDef { + ClassCacheIndex declaring_class; + NameCacheIndex name; + ProtoCacheIndex proto; + }; + + /** + * The definition of an intrinsic function binds the method definition + * to an Intrinsic. + */ + struct IntrinsicDef { + MethodDef method_def; + Intrinsic intrinsic; + }; + + /** + * Cache for class, method name and method signature indexes used during + * intrinsic function lookup to avoid multiple lookups of the same items. + * + * Many classes have multiple intrinsics and/or they are used in multiple + * method signatures and we want to avoid repeated lookups since they are + * not exactly cheap. The method names and method signatures are sometimes + * reused and therefore cached as well. + */ + struct IndexCache { + IndexCache(); + + uint32_t class_indexes[kClassCacheLast - kClassCacheFirst]; + uint32_t name_indexes[kNameCacheLast - kNameCacheFirst]; + uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst]; + }; + + static const char* kClassCacheNames[]; + static const char* kNameCacheNames[]; + static const ProtoDef kProtoCacheDefs[]; + + static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1); + static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2); + + static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache, + ClassCacheIndex index); + static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache, + NameCacheIndex index); + static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache, + ProtoCacheIndex index); + static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache, + const MethodDef& method_def); + + void DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache, + const IntrinsicDef* defs, uint32_t def_count); + + /* + * Maps method indexes (for the particular DexFile) to Intrinsic defintions. + */ + std::map<uint32_t, Intrinsic> intrinsics_; + const DexFile* dex_file_; +}; + +} // namespace art + +#endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ |