dex_file_method_inliner.h revision 2eba1fa7e9e5f91e18ae3778d529520bd2c78d55
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
28namespace art {
29
30namespace verifier {
31class MethodVerifier;
32}  // namespace verifier
33
34struct BasicBlock;
35struct CallInfo;
36struct MIR;
37class MIRGraph;
38class 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 */
52class 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      kNameCacheGet,
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