Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 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> |
Vladimir Marko | e13717e | 2013-11-20 12:44:55 +0000 | [diff] [blame] | 21 | #include "base/mutex.h" |
| 22 | #include "base/macros.h" |
Ian Rogers | dce164a | 2014-01-02 17:00:38 -0800 | [diff] [blame] | 23 | #include "safe_map.h" |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 24 | #include "dex/compiler_enums.h" |
| 25 | #include "dex_file.h" |
Vladimir Marko | e3e0260 | 2014-03-12 15:42:41 +0000 | [diff] [blame] | 26 | #include "quick/inline_method_analyser.h" |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 27 | |
| 28 | namespace art { |
| 29 | |
Vladimir Marko | 2bc4780 | 2014-02-10 09:43:07 +0000 | [diff] [blame] | 30 | namespace verifier { |
| 31 | class MethodVerifier; |
| 32 | } // namespace verifier |
| 33 | |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 34 | struct BasicBlock; |
Ian Rogers | b48b9eb | 2014-02-28 16:20:21 -0800 | [diff] [blame] | 35 | struct CallInfo; |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 36 | struct MIR; |
| 37 | class MIRGraph; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 38 | class Mir2Lir; |
| 39 | |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 40 | /** |
| 41 | * Handles inlining of methods from a particular DexFile. |
| 42 | * |
| 43 | * Intrinsics are a special case of inline methods. The DexFile indices for |
| 44 | * all the supported intrinsic methods are looked up once by the FindIntrinsics |
| 45 | * function and cached by this class for quick lookup by the method index. |
| 46 | * |
| 47 | * TODO: Detect short methods (at least getters, setters and empty functions) |
| 48 | * from the verifier and mark them for inlining. Inline these methods early |
| 49 | * during compilation to allow further optimizations. Similarly, provide |
| 50 | * additional information about intrinsics to the early phases of compilation. |
| 51 | */ |
| 52 | class DexFileMethodInliner { |
| 53 | public: |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 54 | DexFileMethodInliner(); |
| 55 | ~DexFileMethodInliner(); |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 56 | |
| 57 | /** |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 58 | * Analyse method code to determine if the method is a candidate for inlining. |
| 59 | * If it is, record its data for later. |
| 60 | * |
Vladimir Marko | 84c072c | 2014-02-17 15:07:04 +0000 | [diff] [blame] | 61 | * @param verifier the method verifier holding data about the method to analyse. |
| 62 | * @return true if the method is a candidate for inlining, false otherwise. |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 63 | */ |
Vladimir Marko | 2bc4780 | 2014-02-10 09:43:07 +0000 | [diff] [blame] | 64 | bool AnalyseMethodCode(verifier::MethodVerifier* verifier) |
| 65 | SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_); |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 66 | |
| 67 | /** |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 68 | * Check whether a particular method index corresponds to an intrinsic function. |
| 69 | */ |
Yixin Shou | 7071c8d | 2014-03-05 06:07:48 -0500 | [diff] [blame^] | 70 | bool IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) LOCKS_EXCLUDED(lock_); |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 71 | |
| 72 | /** |
| 73 | * Generate code for an intrinsic function invocation. |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 74 | */ |
Vladimir Marko | e13717e | 2013-11-20 12:44:55 +0000 | [diff] [blame] | 75 | bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) LOCKS_EXCLUDED(lock_); |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 76 | |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 77 | /** |
| 78 | * Check whether a particular method index corresponds to a special function. |
| 79 | */ |
| 80 | bool IsSpecial(uint32_t method_index) LOCKS_EXCLUDED(lock_); |
| 81 | |
| 82 | /** |
| 83 | * Generate code for a special function. |
| 84 | */ |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 85 | bool GenSpecial(Mir2Lir* backend, uint32_t method_idx) LOCKS_EXCLUDED(lock_); |
| 86 | |
| 87 | /** |
| 88 | * Try to inline an invoke. |
| 89 | */ |
| 90 | bool GenInline(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, uint32_t method_idx) |
| 91 | LOCKS_EXCLUDED(lock_); |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 92 | |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 93 | /** |
| 94 | * To avoid multiple lookups of a class by its descriptor, we cache its |
| 95 | * type index in the IndexCache. These are the indexes into the IndexCache |
| 96 | * class_indexes array. |
| 97 | */ |
| 98 | enum ClassCacheIndex : uint8_t { // unit8_t to save space, make larger if needed |
| 99 | kClassCacheFirst = 0, |
| 100 | kClassCacheBoolean = kClassCacheFirst, |
| 101 | kClassCacheByte, |
| 102 | kClassCacheChar, |
| 103 | kClassCacheShort, |
| 104 | kClassCacheInt, |
| 105 | kClassCacheLong, |
| 106 | kClassCacheFloat, |
| 107 | kClassCacheDouble, |
| 108 | kClassCacheVoid, |
| 109 | kClassCacheJavaLangObject, |
| 110 | kClassCacheJavaLangString, |
| 111 | kClassCacheJavaLangDouble, |
| 112 | kClassCacheJavaLangFloat, |
| 113 | kClassCacheJavaLangInteger, |
| 114 | kClassCacheJavaLangLong, |
| 115 | kClassCacheJavaLangShort, |
| 116 | kClassCacheJavaLangMath, |
| 117 | kClassCacheJavaLangStrictMath, |
| 118 | kClassCacheJavaLangThread, |
| 119 | kClassCacheLibcoreIoMemory, |
| 120 | kClassCacheSunMiscUnsafe, |
| 121 | kClassCacheLast |
| 122 | }; |
| 123 | |
| 124 | /** |
| 125 | * To avoid multiple lookups of a method name string, we cache its string |
| 126 | * index in the IndexCache. These are the indexes into the IndexCache |
| 127 | * name_indexes array. |
| 128 | */ |
| 129 | enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed |
| 130 | kNameCacheFirst = 0, |
| 131 | kNameCacheReverseBytes = kNameCacheFirst, |
| 132 | kNameCacheDoubleToRawLongBits, |
| 133 | kNameCacheLongBitsToDouble, |
| 134 | kNameCacheFloatToRawIntBits, |
| 135 | kNameCacheIntBitsToFloat, |
| 136 | kNameCacheAbs, |
| 137 | kNameCacheMax, |
| 138 | kNameCacheMin, |
| 139 | kNameCacheSqrt, |
| 140 | kNameCacheCharAt, |
| 141 | kNameCacheCompareTo, |
| 142 | kNameCacheIsEmpty, |
| 143 | kNameCacheIndexOf, |
| 144 | kNameCacheLength, |
| 145 | kNameCacheCurrentThread, |
| 146 | kNameCachePeekByte, |
| 147 | kNameCachePeekIntNative, |
| 148 | kNameCachePeekLongNative, |
| 149 | kNameCachePeekShortNative, |
| 150 | kNameCachePokeByte, |
| 151 | kNameCachePokeIntNative, |
| 152 | kNameCachePokeLongNative, |
| 153 | kNameCachePokeShortNative, |
| 154 | kNameCacheCompareAndSwapInt, |
Vladimir Marko | 1c282e2 | 2013-11-21 14:49:47 +0000 | [diff] [blame] | 155 | kNameCacheCompareAndSwapLong, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 156 | kNameCacheCompareAndSwapObject, |
| 157 | kNameCacheGetInt, |
| 158 | kNameCacheGetIntVolatile, |
| 159 | kNameCachePutInt, |
| 160 | kNameCachePutIntVolatile, |
| 161 | kNameCachePutOrderedInt, |
| 162 | kNameCacheGetLong, |
| 163 | kNameCacheGetLongVolatile, |
| 164 | kNameCachePutLong, |
| 165 | kNameCachePutLongVolatile, |
| 166 | kNameCachePutOrderedLong, |
| 167 | kNameCacheGetObject, |
| 168 | kNameCacheGetObjectVolatile, |
| 169 | kNameCachePutObject, |
| 170 | kNameCachePutObjectVolatile, |
| 171 | kNameCachePutOrderedObject, |
| 172 | kNameCacheLast |
| 173 | }; |
| 174 | |
| 175 | /** |
| 176 | * To avoid multiple lookups of a method signature, we cache its proto |
| 177 | * index in the IndexCache. These are the indexes into the IndexCache |
| 178 | * proto_indexes array. |
| 179 | */ |
| 180 | enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed |
| 181 | kProtoCacheFirst = 0, |
| 182 | kProtoCacheI_I = kProtoCacheFirst, |
| 183 | kProtoCacheJ_J, |
| 184 | kProtoCacheS_S, |
| 185 | kProtoCacheD_D, |
Yixin Shou | dbb17e3 | 2014-02-07 05:09:30 -0800 | [diff] [blame] | 186 | kProtoCacheF_F, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 187 | kProtoCacheD_J, |
| 188 | kProtoCacheJ_D, |
| 189 | kProtoCacheF_I, |
| 190 | kProtoCacheI_F, |
| 191 | kProtoCacheII_I, |
| 192 | kProtoCacheI_C, |
| 193 | kProtoCacheString_I, |
| 194 | kProtoCache_Z, |
| 195 | kProtoCache_I, |
| 196 | kProtoCache_Thread, |
| 197 | kProtoCacheJ_B, |
| 198 | kProtoCacheJ_I, |
| 199 | kProtoCacheJ_S, |
| 200 | kProtoCacheJB_V, |
| 201 | kProtoCacheJI_V, |
| 202 | kProtoCacheJJ_V, |
| 203 | kProtoCacheJS_V, |
| 204 | kProtoCacheObjectJII_Z, |
Vladimir Marko | 1c282e2 | 2013-11-21 14:49:47 +0000 | [diff] [blame] | 205 | kProtoCacheObjectJJJ_Z, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 206 | kProtoCacheObjectJObjectObject_Z, |
| 207 | kProtoCacheObjectJ_I, |
| 208 | kProtoCacheObjectJI_V, |
| 209 | kProtoCacheObjectJ_J, |
| 210 | kProtoCacheObjectJJ_V, |
| 211 | kProtoCacheObjectJ_Object, |
| 212 | kProtoCacheObjectJObject_V, |
| 213 | kProtoCacheLast |
| 214 | }; |
| 215 | |
Ian Rogers | b48b9eb | 2014-02-28 16:20:21 -0800 | [diff] [blame] | 216 | private: |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 217 | /** |
| 218 | * The maximum number of method parameters we support in the ProtoDef. |
| 219 | */ |
| 220 | static constexpr uint32_t kProtoMaxParams = 6; |
| 221 | |
| 222 | /** |
| 223 | * The method signature (proto) definition using cached class indexes. |
| 224 | * The return_type and params are used with the IndexCache to look up |
| 225 | * appropriate class indexes to be passed to DexFile::FindProtoId(). |
| 226 | */ |
| 227 | struct ProtoDef { |
| 228 | ClassCacheIndex return_type; |
| 229 | uint8_t param_count; |
| 230 | ClassCacheIndex params[kProtoMaxParams]; |
| 231 | }; |
| 232 | |
| 233 | /** |
| 234 | * The method definition using cached class, name and proto indexes. |
| 235 | * The class index, method name index and proto index are used with |
| 236 | * IndexCache to look up appropriate parameters for DexFile::FindMethodId(). |
| 237 | */ |
| 238 | struct MethodDef { |
| 239 | ClassCacheIndex declaring_class; |
| 240 | NameCacheIndex name; |
| 241 | ProtoCacheIndex proto; |
| 242 | }; |
| 243 | |
| 244 | /** |
| 245 | * The definition of an intrinsic function binds the method definition |
| 246 | * to an Intrinsic. |
| 247 | */ |
| 248 | struct IntrinsicDef { |
| 249 | MethodDef method_def; |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 250 | InlineMethod intrinsic; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 251 | }; |
| 252 | |
| 253 | /** |
| 254 | * Cache for class, method name and method signature indexes used during |
| 255 | * intrinsic function lookup to avoid multiple lookups of the same items. |
| 256 | * |
| 257 | * Many classes have multiple intrinsics and/or they are used in multiple |
| 258 | * method signatures and we want to avoid repeated lookups since they are |
| 259 | * not exactly cheap. The method names and method signatures are sometimes |
| 260 | * reused and therefore cached as well. |
| 261 | */ |
| 262 | struct IndexCache { |
| 263 | IndexCache(); |
| 264 | |
| 265 | uint32_t class_indexes[kClassCacheLast - kClassCacheFirst]; |
| 266 | uint32_t name_indexes[kNameCacheLast - kNameCacheFirst]; |
| 267 | uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst]; |
| 268 | }; |
| 269 | |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 270 | static const char* const kClassCacheNames[]; |
| 271 | static const char* const kNameCacheNames[]; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 272 | static const ProtoDef kProtoCacheDefs[]; |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 273 | static const IntrinsicDef kIntrinsicMethods[]; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 274 | |
| 275 | static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1); |
| 276 | static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2); |
| 277 | |
| 278 | static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache, |
| 279 | ClassCacheIndex index); |
| 280 | static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache, |
| 281 | NameCacheIndex index); |
| 282 | static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache, |
| 283 | ProtoCacheIndex index); |
| 284 | static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache, |
| 285 | const MethodDef& method_def); |
| 286 | |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 287 | /** |
| 288 | * Find all known intrinsic methods in the dex_file and cache their indices. |
| 289 | * |
| 290 | * Only DexFileToMethodInlinerMap may call this function to initialize the inliner. |
| 291 | */ |
Vladimir Marko | e13717e | 2013-11-20 12:44:55 +0000 | [diff] [blame] | 292 | void FindIntrinsics(const DexFile* dex_file) EXCLUSIVE_LOCKS_REQUIRED(lock_); |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 293 | |
| 294 | friend class DexFileToMethodInlinerMap; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 295 | |
Vladimir Marko | 2bc4780 | 2014-02-10 09:43:07 +0000 | [diff] [blame] | 296 | bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_); |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 297 | |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 298 | static bool GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, |
| 299 | MIR* move_result, const InlineMethod& method); |
| 300 | static bool GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, |
| 301 | MIR* move_result, const InlineMethod& method); |
| 302 | static bool GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, |
| 303 | MIR* move_result, const InlineMethod& method, uint32_t method_idx); |
| 304 | static bool GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, |
Vladimir Marko | e1fced1 | 2014-04-04 14:52:53 +0100 | [diff] [blame] | 305 | MIR* move_result, const InlineMethod& method, uint32_t method_idx); |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 306 | |
Vladimir Marko | e13717e | 2013-11-20 12:44:55 +0000 | [diff] [blame] | 307 | ReaderWriterMutex lock_; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 308 | /* |
| 309 | * Maps method indexes (for the particular DexFile) to Intrinsic defintions. |
| 310 | */ |
Ian Rogers | dce164a | 2014-01-02 17:00:38 -0800 | [diff] [blame] | 311 | SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_); |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 312 | const DexFile* dex_file_; |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 313 | |
| 314 | DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner); |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 315 | }; |
| 316 | |
| 317 | } // namespace art |
| 318 | |
| 319 | #endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ |