dex_file_method_inliner.h revision 5c96e6b4dc354a7439b211b93462fbe8edea5e57
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ 18#define ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ 19 20#include <stdint.h> 21#include <map> 22 23namespace art { 24 25class CallInfo; 26class DexFile; 27class Mir2Lir; 28 29enum IntrinsicOpcode { 30 kIntrinsicDoubleCvt, 31 kIntrinsicFloatCvt, 32 kIntrinsicReverseBytes, 33 kIntrinsicAbsInt, 34 kIntrinsicAbsLong, 35 kIntrinsicMinMaxInt, 36 kIntrinsicSqrt, 37 kIntrinsicCharAt, 38 kIntrinsicCompareTo, 39 kIntrinsicIsEmptyOrLength, 40 kIntrinsicIndexOf, 41 kIntrinsicCurrentThread, 42 kIntrinsicPeek, 43 kIntrinsicPoke, 44 kIntrinsicCas32, 45 kIntrinsicUnsafeGet, 46 kIntrinsicUnsafePut, 47}; 48 49enum IntrinsicFlags { 50 kIntrinsicFlagNone = 0, 51 52 // kIntrinsicMinMaxInt 53 kIntrinsicFlagMax = kIntrinsicFlagNone, 54 kIntrinsicFlagMin = 1, 55 56 // kIntrinsicIsEmptyOrLength 57 kIntrinsicFlagLength = kIntrinsicFlagNone, 58 kIntrinsicFlagIsEmpty = 1, 59 60 // kIntrinsicIndexOf 61 kIntrinsicFlagBase0 = 1, 62 63 // kIntrinsicUnsafeCas32 64 kIntrinsicFlagDontNeedWriteBarrier = 0, 65 kIntrinsicFlagNeedWriteBarrier = 1, 66 67 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut 68 kIntrinsicFlagIsLong = 1, 69 kIntrinsicFlagIsVolatile = 2, 70 // kIntrinsicUnsafePut 71 kIntrinsicFlagIsObject = 4, 72 kIntrinsicFlagIsOrdered = 8, 73}; 74 75struct Intrinsic { 76 IntrinsicOpcode opcode; 77 uint32_t data; 78}; 79 80/** 81 * Handles inlining of methods from a particular DexFile. 82 * 83 * Intrinsics are a special case of inline methods. The DexFile indices for 84 * all the supported intrinsic methods are looked up once by the FindIntrinsics 85 * function and cached by this class for quick lookup by the method index. 86 * 87 * TODO: Detect short methods (at least getters, setters and empty functions) 88 * from the verifier and mark them for inlining. Inline these methods early 89 * during compilation to allow further optimizations. Similarly, provide 90 * additional information about intrinsics to the early phases of compilation. 91 */ 92class DexFileMethodInliner { 93 public: 94 virtual ~DexFileMethodInliner(); 95 96 /** 97 * Find all known intrinsic methods in the dex_file and cache their indices. 98 */ 99 virtual void FindIntrinsics(const DexFile* dex_file) = 0; 100 101 /** 102 * Check whether a particular method index corresponds to an intrinsic function. 103 */ 104 bool IsIntrinsic(uint32_t method_index) const; 105 106 /** 107 * Generate code for an intrinsic function invocation. 108 * 109 * TODO: This should be target-specific. For the time being, 110 * it's shared since it dispatches everything to backend. 111 */ 112 bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const; 113 114 protected: 115 DexFileMethodInliner(); 116 117 /** 118 * To avoid multiple lookups of a class by its descriptor, we cache its 119 * type index in the IndexCache. These are the indexes into the IndexCache 120 * class_indexes array. 121 */ 122 enum ClassCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 123 kClassCacheFirst = 0, 124 kClassCacheBoolean = kClassCacheFirst, 125 kClassCacheByte, 126 kClassCacheChar, 127 kClassCacheShort, 128 kClassCacheInt, 129 kClassCacheLong, 130 kClassCacheFloat, 131 kClassCacheDouble, 132 kClassCacheVoid, 133 kClassCacheJavaLangObject, 134 kClassCacheJavaLangString, 135 kClassCacheJavaLangDouble, 136 kClassCacheJavaLangFloat, 137 kClassCacheJavaLangInteger, 138 kClassCacheJavaLangLong, 139 kClassCacheJavaLangShort, 140 kClassCacheJavaLangMath, 141 kClassCacheJavaLangStrictMath, 142 kClassCacheJavaLangThread, 143 kClassCacheLibcoreIoMemory, 144 kClassCacheSunMiscUnsafe, 145 kClassCacheLast 146 }; 147 148 /** 149 * To avoid multiple lookups of a method name string, we cache its string 150 * index in the IndexCache. These are the indexes into the IndexCache 151 * name_indexes array. 152 */ 153 enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 154 kNameCacheFirst = 0, 155 kNameCacheReverseBytes = kNameCacheFirst, 156 kNameCacheDoubleToRawLongBits, 157 kNameCacheLongBitsToDouble, 158 kNameCacheFloatToRawIntBits, 159 kNameCacheIntBitsToFloat, 160 kNameCacheAbs, 161 kNameCacheMax, 162 kNameCacheMin, 163 kNameCacheSqrt, 164 kNameCacheCharAt, 165 kNameCacheCompareTo, 166 kNameCacheIsEmpty, 167 kNameCacheIndexOf, 168 kNameCacheLength, 169 kNameCacheCurrentThread, 170 kNameCachePeekByte, 171 kNameCachePeekIntNative, 172 kNameCachePeekLongNative, 173 kNameCachePeekShortNative, 174 kNameCachePokeByte, 175 kNameCachePokeIntNative, 176 kNameCachePokeLongNative, 177 kNameCachePokeShortNative, 178 kNameCacheCompareAndSwapInt, 179 kNameCacheCompareAndSwapObject, 180 kNameCacheGetInt, 181 kNameCacheGetIntVolatile, 182 kNameCachePutInt, 183 kNameCachePutIntVolatile, 184 kNameCachePutOrderedInt, 185 kNameCacheGetLong, 186 kNameCacheGetLongVolatile, 187 kNameCachePutLong, 188 kNameCachePutLongVolatile, 189 kNameCachePutOrderedLong, 190 kNameCacheGetObject, 191 kNameCacheGetObjectVolatile, 192 kNameCachePutObject, 193 kNameCachePutObjectVolatile, 194 kNameCachePutOrderedObject, 195 kNameCacheLast 196 }; 197 198 /** 199 * To avoid multiple lookups of a method signature, we cache its proto 200 * index in the IndexCache. These are the indexes into the IndexCache 201 * proto_indexes array. 202 */ 203 enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 204 kProtoCacheFirst = 0, 205 kProtoCacheI_I = kProtoCacheFirst, 206 kProtoCacheJ_J, 207 kProtoCacheS_S, 208 kProtoCacheD_D, 209 kProtoCacheD_J, 210 kProtoCacheJ_D, 211 kProtoCacheF_I, 212 kProtoCacheI_F, 213 kProtoCacheII_I, 214 kProtoCacheI_C, 215 kProtoCacheString_I, 216 kProtoCache_Z, 217 kProtoCache_I, 218 kProtoCache_Thread, 219 kProtoCacheJ_B, 220 kProtoCacheJ_I, 221 kProtoCacheJ_S, 222 kProtoCacheJB_V, 223 kProtoCacheJI_V, 224 kProtoCacheJJ_V, 225 kProtoCacheJS_V, 226 kProtoCacheObjectJII_Z, 227 kProtoCacheObjectJObjectObject_Z, 228 kProtoCacheObjectJ_I, 229 kProtoCacheObjectJI_V, 230 kProtoCacheObjectJ_J, 231 kProtoCacheObjectJJ_V, 232 kProtoCacheObjectJ_Object, 233 kProtoCacheObjectJObject_V, 234 kProtoCacheLast 235 }; 236 237 /** 238 * The maximum number of method parameters we support in the ProtoDef. 239 */ 240 static constexpr uint32_t kProtoMaxParams = 6; 241 242 /** 243 * The method signature (proto) definition using cached class indexes. 244 * The return_type and params are used with the IndexCache to look up 245 * appropriate class indexes to be passed to DexFile::FindProtoId(). 246 */ 247 struct ProtoDef { 248 ClassCacheIndex return_type; 249 uint8_t param_count; 250 ClassCacheIndex params[kProtoMaxParams]; 251 }; 252 253 /** 254 * The method definition using cached class, name and proto indexes. 255 * The class index, method name index and proto index are used with 256 * IndexCache to look up appropriate parameters for DexFile::FindMethodId(). 257 */ 258 struct MethodDef { 259 ClassCacheIndex declaring_class; 260 NameCacheIndex name; 261 ProtoCacheIndex proto; 262 }; 263 264 /** 265 * The definition of an intrinsic function binds the method definition 266 * to an Intrinsic. 267 */ 268 struct IntrinsicDef { 269 MethodDef method_def; 270 Intrinsic intrinsic; 271 }; 272 273 /** 274 * Cache for class, method name and method signature indexes used during 275 * intrinsic function lookup to avoid multiple lookups of the same items. 276 * 277 * Many classes have multiple intrinsics and/or they are used in multiple 278 * method signatures and we want to avoid repeated lookups since they are 279 * not exactly cheap. The method names and method signatures are sometimes 280 * reused and therefore cached as well. 281 */ 282 struct IndexCache { 283 IndexCache(); 284 285 uint32_t class_indexes[kClassCacheLast - kClassCacheFirst]; 286 uint32_t name_indexes[kNameCacheLast - kNameCacheFirst]; 287 uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst]; 288 }; 289 290 static const char* kClassCacheNames[]; 291 static const char* kNameCacheNames[]; 292 static const ProtoDef kProtoCacheDefs[]; 293 294 static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1); 295 static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2); 296 297 static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache, 298 ClassCacheIndex index); 299 static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache, 300 NameCacheIndex index); 301 static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache, 302 ProtoCacheIndex index); 303 static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache, 304 const MethodDef& method_def); 305 306 void DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache, 307 const IntrinsicDef* defs, uint32_t def_count); 308 309 /* 310 * Maps method indexes (for the particular DexFile) to Intrinsic defintions. 311 */ 312 std::map<uint32_t, Intrinsic> intrinsics_; 313 const DexFile* dex_file_; 314}; 315 316} // namespace art 317 318#endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ 319