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, |
Fred Shih | 4ee7a66 | 2014-07-11 09:59:27 -0700 | [diff] [blame] | 110 | kClassCacheJavaLangRefReference, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 111 | kClassCacheJavaLangString, |
| 112 | kClassCacheJavaLangDouble, |
| 113 | kClassCacheJavaLangFloat, |
| 114 | kClassCacheJavaLangInteger, |
| 115 | kClassCacheJavaLangLong, |
| 116 | kClassCacheJavaLangShort, |
| 117 | kClassCacheJavaLangMath, |
| 118 | kClassCacheJavaLangStrictMath, |
| 119 | kClassCacheJavaLangThread, |
| 120 | kClassCacheLibcoreIoMemory, |
| 121 | kClassCacheSunMiscUnsafe, |
DaniilSokolov | 70c4f06 | 2014-06-24 17:34:00 -0700 | [diff] [blame] | 122 | kClassCacheJavaLangSystem, |
| 123 | kClassCacheJavaLangCharArray, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 124 | kClassCacheLast |
| 125 | }; |
| 126 | |
| 127 | /** |
| 128 | * To avoid multiple lookups of a method name string, we cache its string |
| 129 | * index in the IndexCache. These are the indexes into the IndexCache |
| 130 | * name_indexes array. |
| 131 | */ |
| 132 | enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed |
| 133 | kNameCacheFirst = 0, |
Serban Constantinescu | 23abec9 | 2014-07-02 16:13:38 +0100 | [diff] [blame] | 134 | kNameCacheReverse = kNameCacheFirst, |
| 135 | kNameCacheReverseBytes, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 136 | kNameCacheDoubleToRawLongBits, |
| 137 | kNameCacheLongBitsToDouble, |
| 138 | kNameCacheFloatToRawIntBits, |
| 139 | kNameCacheIntBitsToFloat, |
| 140 | kNameCacheAbs, |
| 141 | kNameCacheMax, |
| 142 | kNameCacheMin, |
| 143 | kNameCacheSqrt, |
Serban Constantinescu | 2eba1fa | 2014-07-31 19:07:17 +0100 | [diff] [blame] | 144 | kNameCacheCeil, |
| 145 | kNameCacheFloor, |
| 146 | kNameCacheRint, |
| 147 | kNameCacheRound, |
Mathieu Chartier | cd48f2d | 2014-09-09 13:51:09 -0700 | [diff] [blame] | 148 | kNameCacheReferenceGetReferent, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 149 | kNameCacheCharAt, |
| 150 | kNameCacheCompareTo, |
| 151 | kNameCacheIsEmpty, |
| 152 | kNameCacheIndexOf, |
| 153 | kNameCacheLength, |
| 154 | kNameCacheCurrentThread, |
| 155 | kNameCachePeekByte, |
| 156 | kNameCachePeekIntNative, |
| 157 | kNameCachePeekLongNative, |
| 158 | kNameCachePeekShortNative, |
| 159 | kNameCachePokeByte, |
| 160 | kNameCachePokeIntNative, |
| 161 | kNameCachePokeLongNative, |
| 162 | kNameCachePokeShortNative, |
| 163 | kNameCacheCompareAndSwapInt, |
Vladimir Marko | 1c282e2 | 2013-11-21 14:49:47 +0000 | [diff] [blame] | 164 | kNameCacheCompareAndSwapLong, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 165 | kNameCacheCompareAndSwapObject, |
| 166 | kNameCacheGetInt, |
| 167 | kNameCacheGetIntVolatile, |
| 168 | kNameCachePutInt, |
| 169 | kNameCachePutIntVolatile, |
| 170 | kNameCachePutOrderedInt, |
| 171 | kNameCacheGetLong, |
| 172 | kNameCacheGetLongVolatile, |
| 173 | kNameCachePutLong, |
| 174 | kNameCachePutLongVolatile, |
| 175 | kNameCachePutOrderedLong, |
| 176 | kNameCacheGetObject, |
| 177 | kNameCacheGetObjectVolatile, |
| 178 | kNameCachePutObject, |
| 179 | kNameCachePutObjectVolatile, |
| 180 | kNameCachePutOrderedObject, |
DaniilSokolov | 70c4f06 | 2014-06-24 17:34:00 -0700 | [diff] [blame] | 181 | kNameCacheArrayCopy, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 182 | kNameCacheLast |
| 183 | }; |
| 184 | |
| 185 | /** |
| 186 | * To avoid multiple lookups of a method signature, we cache its proto |
| 187 | * index in the IndexCache. These are the indexes into the IndexCache |
| 188 | * proto_indexes array. |
| 189 | */ |
| 190 | enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed |
| 191 | kProtoCacheFirst = 0, |
| 192 | kProtoCacheI_I = kProtoCacheFirst, |
| 193 | kProtoCacheJ_J, |
| 194 | kProtoCacheS_S, |
| 195 | kProtoCacheD_D, |
Serban Constantinescu | 23abec9 | 2014-07-02 16:13:38 +0100 | [diff] [blame] | 196 | kProtoCacheDD_D, |
Yixin Shou | dbb17e3 | 2014-02-07 05:09:30 -0800 | [diff] [blame] | 197 | kProtoCacheF_F, |
Serban Constantinescu | 23abec9 | 2014-07-02 16:13:38 +0100 | [diff] [blame] | 198 | kProtoCacheFF_F, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 199 | kProtoCacheD_J, |
| 200 | kProtoCacheJ_D, |
| 201 | kProtoCacheF_I, |
| 202 | kProtoCacheI_F, |
| 203 | kProtoCacheII_I, |
| 204 | kProtoCacheI_C, |
| 205 | kProtoCacheString_I, |
| 206 | kProtoCache_Z, |
| 207 | kProtoCache_I, |
Fred Shih | 4ee7a66 | 2014-07-11 09:59:27 -0700 | [diff] [blame] | 208 | kProtoCache_Object, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 209 | kProtoCache_Thread, |
| 210 | kProtoCacheJ_B, |
| 211 | kProtoCacheJ_I, |
| 212 | kProtoCacheJ_S, |
| 213 | kProtoCacheJB_V, |
| 214 | kProtoCacheJI_V, |
Serban Constantinescu | 23abec9 | 2014-07-02 16:13:38 +0100 | [diff] [blame] | 215 | kProtoCacheJJ_J, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 216 | kProtoCacheJJ_V, |
| 217 | kProtoCacheJS_V, |
| 218 | kProtoCacheObjectJII_Z, |
Vladimir Marko | 1c282e2 | 2013-11-21 14:49:47 +0000 | [diff] [blame] | 219 | kProtoCacheObjectJJJ_Z, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 220 | kProtoCacheObjectJObjectObject_Z, |
| 221 | kProtoCacheObjectJ_I, |
| 222 | kProtoCacheObjectJI_V, |
| 223 | kProtoCacheObjectJ_J, |
| 224 | kProtoCacheObjectJJ_V, |
| 225 | kProtoCacheObjectJ_Object, |
| 226 | kProtoCacheObjectJObject_V, |
DaniilSokolov | 70c4f06 | 2014-06-24 17:34:00 -0700 | [diff] [blame] | 227 | kProtoCacheCharArrayICharArrayII_V, |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 228 | kProtoCacheLast |
| 229 | }; |
| 230 | |
Ian Rogers | b48b9eb | 2014-02-28 16:20:21 -0800 | [diff] [blame] | 231 | private: |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 232 | /** |
| 233 | * The maximum number of method parameters we support in the ProtoDef. |
| 234 | */ |
| 235 | static constexpr uint32_t kProtoMaxParams = 6; |
| 236 | |
| 237 | /** |
| 238 | * The method signature (proto) definition using cached class indexes. |
| 239 | * The return_type and params are used with the IndexCache to look up |
| 240 | * appropriate class indexes to be passed to DexFile::FindProtoId(). |
| 241 | */ |
| 242 | struct ProtoDef { |
| 243 | ClassCacheIndex return_type; |
| 244 | uint8_t param_count; |
| 245 | ClassCacheIndex params[kProtoMaxParams]; |
| 246 | }; |
| 247 | |
| 248 | /** |
| 249 | * The method definition using cached class, name and proto indexes. |
| 250 | * The class index, method name index and proto index are used with |
| 251 | * IndexCache to look up appropriate parameters for DexFile::FindMethodId(). |
| 252 | */ |
| 253 | struct MethodDef { |
| 254 | ClassCacheIndex declaring_class; |
| 255 | NameCacheIndex name; |
| 256 | ProtoCacheIndex proto; |
| 257 | }; |
| 258 | |
| 259 | /** |
| 260 | * The definition of an intrinsic function binds the method definition |
| 261 | * to an Intrinsic. |
| 262 | */ |
| 263 | struct IntrinsicDef { |
| 264 | MethodDef method_def; |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 265 | InlineMethod intrinsic; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 266 | }; |
| 267 | |
| 268 | /** |
| 269 | * Cache for class, method name and method signature indexes used during |
| 270 | * intrinsic function lookup to avoid multiple lookups of the same items. |
| 271 | * |
| 272 | * Many classes have multiple intrinsics and/or they are used in multiple |
| 273 | * method signatures and we want to avoid repeated lookups since they are |
| 274 | * not exactly cheap. The method names and method signatures are sometimes |
| 275 | * reused and therefore cached as well. |
| 276 | */ |
| 277 | struct IndexCache { |
| 278 | IndexCache(); |
| 279 | |
| 280 | uint32_t class_indexes[kClassCacheLast - kClassCacheFirst]; |
| 281 | uint32_t name_indexes[kNameCacheLast - kNameCacheFirst]; |
| 282 | uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst]; |
| 283 | }; |
| 284 | |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 285 | static const char* const kClassCacheNames[]; |
| 286 | static const char* const kNameCacheNames[]; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 287 | static const ProtoDef kProtoCacheDefs[]; |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 288 | static const IntrinsicDef kIntrinsicMethods[]; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 289 | |
| 290 | static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1); |
| 291 | static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2); |
| 292 | |
| 293 | static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache, |
| 294 | ClassCacheIndex index); |
| 295 | static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache, |
| 296 | NameCacheIndex index); |
| 297 | static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache, |
| 298 | ProtoCacheIndex index); |
| 299 | static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache, |
| 300 | const MethodDef& method_def); |
| 301 | |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 302 | /** |
| 303 | * Find all known intrinsic methods in the dex_file and cache their indices. |
| 304 | * |
| 305 | * Only DexFileToMethodInlinerMap may call this function to initialize the inliner. |
| 306 | */ |
Vladimir Marko | e13717e | 2013-11-20 12:44:55 +0000 | [diff] [blame] | 307 | void FindIntrinsics(const DexFile* dex_file) EXCLUSIVE_LOCKS_REQUIRED(lock_); |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 308 | |
| 309 | friend class DexFileToMethodInlinerMap; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 310 | |
Vladimir Marko | 2bc4780 | 2014-02-10 09:43:07 +0000 | [diff] [blame] | 311 | bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_); |
Vladimir Marko | 5816ed4 | 2013-11-27 17:04:20 +0000 | [diff] [blame] | 312 | |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 313 | static bool GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, |
| 314 | MIR* move_result, const InlineMethod& method); |
| 315 | static bool GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, |
| 316 | MIR* move_result, const InlineMethod& method); |
| 317 | static bool GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, |
| 318 | MIR* move_result, const InlineMethod& method, uint32_t method_idx); |
| 319 | static bool GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, |
Vladimir Marko | e1fced1 | 2014-04-04 14:52:53 +0100 | [diff] [blame] | 320 | MIR* move_result, const InlineMethod& method, uint32_t method_idx); |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 321 | |
Vladimir Marko | e13717e | 2013-11-20 12:44:55 +0000 | [diff] [blame] | 322 | ReaderWriterMutex lock_; |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 323 | /* |
| 324 | * Maps method indexes (for the particular DexFile) to Intrinsic defintions. |
| 325 | */ |
Ian Rogers | dce164a | 2014-01-02 17:00:38 -0800 | [diff] [blame] | 326 | SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_); |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 327 | const DexFile* dex_file_; |
Vladimir Marko | 867a2b3 | 2013-12-10 13:01:13 +0000 | [diff] [blame] | 328 | |
| 329 | DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner); |
Vladimir Marko | 5c96e6b | 2013-11-14 15:34:17 +0000 | [diff] [blame] | 330 | }; |
| 331 | |
| 332 | } // namespace art |
| 333 | |
| 334 | #endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_ |