dex_file_method_inliner.h revision 1c282e2b9a9b432e132b2c332f861cad9feb4a73
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 kIntrinsicCas, 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 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas 64 kIntrinsicFlagIsLong = 1, 65 // kIntrinsicUnsafeGet, kIntrinsicUnsafePut 66 kIntrinsicFlagIsVolatile = 2, 67 // kIntrinsicUnsafePut, kIntrinsicUnsafeCas 68 kIntrinsicFlagIsObject = 4, 69 // kIntrinsicUnsafePut 70 kIntrinsicFlagIsOrdered = 8, 71}; 72 73struct Intrinsic { 74 IntrinsicOpcode opcode; 75 uint32_t data; 76}; 77 78/** 79 * Handles inlining of methods from a particular DexFile. 80 * 81 * Intrinsics are a special case of inline methods. The DexFile indices for 82 * all the supported intrinsic methods are looked up once by the FindIntrinsics 83 * function and cached by this class for quick lookup by the method index. 84 * 85 * TODO: Detect short methods (at least getters, setters and empty functions) 86 * from the verifier and mark them for inlining. Inline these methods early 87 * during compilation to allow further optimizations. Similarly, provide 88 * additional information about intrinsics to the early phases of compilation. 89 */ 90class DexFileMethodInliner { 91 public: 92 virtual ~DexFileMethodInliner(); 93 94 /** 95 * Find all known intrinsic methods in the dex_file and cache their indices. 96 */ 97 virtual void FindIntrinsics(const DexFile* dex_file) = 0; 98 99 /** 100 * Check whether a particular method index corresponds to an intrinsic function. 101 */ 102 bool IsIntrinsic(uint32_t method_index) const; 103 104 /** 105 * Generate code for an intrinsic function invocation. 106 * 107 * TODO: This should be target-specific. For the time being, 108 * it's shared since it dispatches everything to backend. 109 */ 110 bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const; 111 112 protected: 113 DexFileMethodInliner(); 114 115 /** 116 * To avoid multiple lookups of a class by its descriptor, we cache its 117 * type index in the IndexCache. These are the indexes into the IndexCache 118 * class_indexes array. 119 */ 120 enum ClassCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 121 kClassCacheFirst = 0, 122 kClassCacheBoolean = kClassCacheFirst, 123 kClassCacheByte, 124 kClassCacheChar, 125 kClassCacheShort, 126 kClassCacheInt, 127 kClassCacheLong, 128 kClassCacheFloat, 129 kClassCacheDouble, 130 kClassCacheVoid, 131 kClassCacheJavaLangObject, 132 kClassCacheJavaLangString, 133 kClassCacheJavaLangDouble, 134 kClassCacheJavaLangFloat, 135 kClassCacheJavaLangInteger, 136 kClassCacheJavaLangLong, 137 kClassCacheJavaLangShort, 138 kClassCacheJavaLangMath, 139 kClassCacheJavaLangStrictMath, 140 kClassCacheJavaLangThread, 141 kClassCacheLibcoreIoMemory, 142 kClassCacheSunMiscUnsafe, 143 kClassCacheLast 144 }; 145 146 /** 147 * To avoid multiple lookups of a method name string, we cache its string 148 * index in the IndexCache. These are the indexes into the IndexCache 149 * name_indexes array. 150 */ 151 enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 152 kNameCacheFirst = 0, 153 kNameCacheReverseBytes = kNameCacheFirst, 154 kNameCacheDoubleToRawLongBits, 155 kNameCacheLongBitsToDouble, 156 kNameCacheFloatToRawIntBits, 157 kNameCacheIntBitsToFloat, 158 kNameCacheAbs, 159 kNameCacheMax, 160 kNameCacheMin, 161 kNameCacheSqrt, 162 kNameCacheCharAt, 163 kNameCacheCompareTo, 164 kNameCacheIsEmpty, 165 kNameCacheIndexOf, 166 kNameCacheLength, 167 kNameCacheCurrentThread, 168 kNameCachePeekByte, 169 kNameCachePeekIntNative, 170 kNameCachePeekLongNative, 171 kNameCachePeekShortNative, 172 kNameCachePokeByte, 173 kNameCachePokeIntNative, 174 kNameCachePokeLongNative, 175 kNameCachePokeShortNative, 176 kNameCacheCompareAndSwapInt, 177 kNameCacheCompareAndSwapLong, 178 kNameCacheCompareAndSwapObject, 179 kNameCacheGetInt, 180 kNameCacheGetIntVolatile, 181 kNameCachePutInt, 182 kNameCachePutIntVolatile, 183 kNameCachePutOrderedInt, 184 kNameCacheGetLong, 185 kNameCacheGetLongVolatile, 186 kNameCachePutLong, 187 kNameCachePutLongVolatile, 188 kNameCachePutOrderedLong, 189 kNameCacheGetObject, 190 kNameCacheGetObjectVolatile, 191 kNameCachePutObject, 192 kNameCachePutObjectVolatile, 193 kNameCachePutOrderedObject, 194 kNameCacheLast 195 }; 196 197 /** 198 * To avoid multiple lookups of a method signature, we cache its proto 199 * index in the IndexCache. These are the indexes into the IndexCache 200 * proto_indexes array. 201 */ 202 enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed 203 kProtoCacheFirst = 0, 204 kProtoCacheI_I = kProtoCacheFirst, 205 kProtoCacheJ_J, 206 kProtoCacheS_S, 207 kProtoCacheD_D, 208 kProtoCacheD_J, 209 kProtoCacheJ_D, 210 kProtoCacheF_I, 211 kProtoCacheI_F, 212 kProtoCacheII_I, 213 kProtoCacheI_C, 214 kProtoCacheString_I, 215 kProtoCache_Z, 216 kProtoCache_I, 217 kProtoCache_Thread, 218 kProtoCacheJ_B, 219 kProtoCacheJ_I, 220 kProtoCacheJ_S, 221 kProtoCacheJB_V, 222 kProtoCacheJI_V, 223 kProtoCacheJJ_V, 224 kProtoCacheJS_V, 225 kProtoCacheObjectJII_Z, 226 kProtoCacheObjectJJJ_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