blob: c03f89c8fa8805081c15a05fea36cad6ab6ad83e [file] [log] [blame]
Vladimir Marko5c96e6b2013-11-14 15:34:17 +00001/*
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 Markoe13717e2013-11-20 12:44:55 +000021#include "base/mutex.h"
22#include "base/macros.h"
Ian Rogersdce164a2014-01-02 17:00:38 -080023#include "safe_map.h"
Vladimir Marko5816ed42013-11-27 17:04:20 +000024#include "dex/compiler_enums.h"
25#include "dex_file.h"
Vladimir Markoe3e02602014-03-12 15:42:41 +000026#include "quick/inline_method_analyser.h"
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000027
28namespace art {
29
Vladimir Marko2bc47802014-02-10 09:43:07 +000030namespace verifier {
31class MethodVerifier;
32} // namespace verifier
33
Vladimir Marko9820b7c2014-01-02 16:40:37 +000034struct BasicBlock;
Ian Rogersb48b9eb2014-02-28 16:20:21 -080035struct CallInfo;
Vladimir Marko9820b7c2014-01-02 16:40:37 +000036struct MIR;
37class MIRGraph;
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000038class Mir2Lir;
39
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000040/**
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 */
52class DexFileMethodInliner {
53 public:
Vladimir Marko867a2b32013-12-10 13:01:13 +000054 DexFileMethodInliner();
55 ~DexFileMethodInliner();
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000056
57 /**
Vladimir Marko5816ed42013-11-27 17:04:20 +000058 * Analyse method code to determine if the method is a candidate for inlining.
59 * If it is, record its data for later.
60 *
Vladimir Marko84c072c2014-02-17 15:07:04 +000061 * @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 Marko5816ed42013-11-27 17:04:20 +000063 */
Vladimir Marko2bc47802014-02-10 09:43:07 +000064 bool AnalyseMethodCode(verifier::MethodVerifier* verifier)
65 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
Vladimir Marko5816ed42013-11-27 17:04:20 +000066
67 /**
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000068 * Check whether a particular method index corresponds to an intrinsic function.
69 */
Vladimir Markoe13717e2013-11-20 12:44:55 +000070 bool IsIntrinsic(uint32_t method_index) LOCKS_EXCLUDED(lock_);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000071
72 /**
73 * Generate code for an intrinsic function invocation.
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000074 */
Vladimir Markoe13717e2013-11-20 12:44:55 +000075 bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) LOCKS_EXCLUDED(lock_);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000076
Vladimir Marko5816ed42013-11-27 17:04:20 +000077 /**
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 Marko9820b7c2014-01-02 16:40:37 +000085 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 Marko5816ed42013-11-27 17:04:20 +000092
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000093 /**
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 Marko1c282e22013-11-21 14:49:47 +0000155 kNameCacheCompareAndSwapLong,
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000156 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 Shoudbb17e32014-02-07 05:09:30 -0800186 kProtoCacheF_F,
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000187 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 Marko1c282e22013-11-21 14:49:47 +0000205 kProtoCacheObjectJJJ_Z,
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000206 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 Rogersb48b9eb2014-02-28 16:20:21 -0800216 private:
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000217 /**
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 Marko5816ed42013-11-27 17:04:20 +0000250 InlineMethod intrinsic;
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000251 };
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 Marko5816ed42013-11-27 17:04:20 +0000270 static const char* const kClassCacheNames[];
271 static const char* const kNameCacheNames[];
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000272 static const ProtoDef kProtoCacheDefs[];
Vladimir Marko867a2b32013-12-10 13:01:13 +0000273 static const IntrinsicDef kIntrinsicMethods[];
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000274
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 Marko867a2b32013-12-10 13:01:13 +0000287 /**
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 Markoe13717e2013-11-20 12:44:55 +0000292 void FindIntrinsics(const DexFile* dex_file) EXCLUSIVE_LOCKS_REQUIRED(lock_);
Vladimir Marko867a2b32013-12-10 13:01:13 +0000293
294 friend class DexFileToMethodInlinerMap;
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000295
Vladimir Marko2bc47802014-02-10 09:43:07 +0000296 bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_);
Vladimir Marko5816ed42013-11-27 17:04:20 +0000297
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000298 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 Markoe1fced12014-04-04 14:52:53 +0100305 MIR* move_result, const InlineMethod& method, uint32_t method_idx);
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000306
Vladimir Markoe13717e2013-11-20 12:44:55 +0000307 ReaderWriterMutex lock_;
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000308 /*
309 * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
310 */
Ian Rogersdce164a2014-01-02 17:00:38 -0800311 SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000312 const DexFile* dex_file_;
Vladimir Marko867a2b32013-12-10 13:01:13 +0000313
314 DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
Vladimir Marko5c96e6b2013-11-14 15:34:17 +0000315};
316
317} // namespace art
318
319#endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_