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 "base/mutex.h"
22 #include "base/macros.h"
23 #include "safe_map.h"
24 #include "dex/compiler_enums.h"
25 #include "dex_file.h"
26 #include "quick/inline_method_analyser.h"
27 
28 namespace art {
29 
30 namespace verifier {
31 class MethodVerifier;
32 }  // namespace verifier
33 
34 struct BasicBlock;
35 struct CallInfo;
36 struct MIR;
37 class MIRGraph;
38 class Mir2Lir;
39 
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:
54     DexFileMethodInliner();
55     ~DexFileMethodInliner();
56 
57     /**
58      * Analyse method code to determine if the method is a candidate for inlining.
59      * If it is, record its data for later.
60      *
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.
63      */
64     bool AnalyseMethodCode(verifier::MethodVerifier* verifier)
65         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
66 
67     /**
68      * Check whether a particular method index corresponds to an intrinsic function.
69      */
70     bool IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) LOCKS_EXCLUDED(lock_);
71 
72     /**
73      * Generate code for an intrinsic function invocation.
74      */
75     bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) LOCKS_EXCLUDED(lock_);
76 
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      */
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_);
92 
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       kClassCacheJavaLangRefReference,
111       kClassCacheJavaLangString,
112       kClassCacheJavaLangDouble,
113       kClassCacheJavaLangFloat,
114       kClassCacheJavaLangInteger,
115       kClassCacheJavaLangLong,
116       kClassCacheJavaLangShort,
117       kClassCacheJavaLangMath,
118       kClassCacheJavaLangStrictMath,
119       kClassCacheJavaLangThread,
120       kClassCacheLibcoreIoMemory,
121       kClassCacheSunMiscUnsafe,
122       kClassCacheJavaLangSystem,
123       kClassCacheJavaLangCharArray,
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,
134       kNameCacheReverse =  kNameCacheFirst,
135       kNameCacheReverseBytes,
136       kNameCacheDoubleToRawLongBits,
137       kNameCacheLongBitsToDouble,
138       kNameCacheFloatToRawIntBits,
139       kNameCacheIntBitsToFloat,
140       kNameCacheAbs,
141       kNameCacheMax,
142       kNameCacheMin,
143       kNameCacheSqrt,
144       kNameCacheCeil,
145       kNameCacheFloor,
146       kNameCacheRint,
147       kNameCacheRound,
148       kNameCacheReferenceGetReferent,
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,
164       kNameCacheCompareAndSwapLong,
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,
181       kNameCacheArrayCopy,
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,
196       kProtoCacheDD_D,
197       kProtoCacheF_F,
198       kProtoCacheFF_F,
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,
208       kProtoCache_Object,
209       kProtoCache_Thread,
210       kProtoCacheJ_B,
211       kProtoCacheJ_I,
212       kProtoCacheJ_S,
213       kProtoCacheJB_V,
214       kProtoCacheJI_V,
215       kProtoCacheJJ_J,
216       kProtoCacheJJ_V,
217       kProtoCacheJS_V,
218       kProtoCacheObjectJII_Z,
219       kProtoCacheObjectJJJ_Z,
220       kProtoCacheObjectJObjectObject_Z,
221       kProtoCacheObjectJ_I,
222       kProtoCacheObjectJI_V,
223       kProtoCacheObjectJ_J,
224       kProtoCacheObjectJJ_V,
225       kProtoCacheObjectJ_Object,
226       kProtoCacheObjectJObject_V,
227       kProtoCacheCharArrayICharArrayII_V,
228       kProtoCacheLast
229     };
230 
231   private:
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;
265       InlineMethod intrinsic;
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 
285     static const char* const kClassCacheNames[];
286     static const char* const kNameCacheNames[];
287     static const ProtoDef kProtoCacheDefs[];
288     static const IntrinsicDef kIntrinsicMethods[];
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 
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      */
307     void FindIntrinsics(const DexFile* dex_file) EXCLUSIVE_LOCKS_REQUIRED(lock_);
308 
309     friend class DexFileToMethodInlinerMap;
310 
311     bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_);
312 
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,
320                               MIR* move_result, const InlineMethod& method, uint32_t method_idx);
321 
322     ReaderWriterMutex lock_;
323     /*
324      * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
325      */
326     SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_);
327     const DexFile* dex_file_;
328 
329     DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
330 };
331 
332 }  // namespace art
333 
334 #endif  // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
335