dex_file_method_inliner.h revision d85614222fa062ec809af9d65f04ab6b7dc1c248
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      kNameCacheGet,
145      kNameCacheCharAt,
146      kNameCacheCompareTo,
147      kNameCacheIsEmpty,
148      kNameCacheIndexOf,
149      kNameCacheLength,
150      kNameCacheCurrentThread,
151      kNameCachePeekByte,
152      kNameCachePeekIntNative,
153      kNameCachePeekLongNative,
154      kNameCachePeekShortNative,
155      kNameCachePokeByte,
156      kNameCachePokeIntNative,
157      kNameCachePokeLongNative,
158      kNameCachePokeShortNative,
159      kNameCacheCompareAndSwapInt,
160      kNameCacheCompareAndSwapLong,
161      kNameCacheCompareAndSwapObject,
162      kNameCacheGetInt,
163      kNameCacheGetIntVolatile,
164      kNameCachePutInt,
165      kNameCachePutIntVolatile,
166      kNameCachePutOrderedInt,
167      kNameCacheGetLong,
168      kNameCacheGetLongVolatile,
169      kNameCachePutLong,
170      kNameCachePutLongVolatile,
171      kNameCachePutOrderedLong,
172      kNameCacheGetObject,
173      kNameCacheGetObjectVolatile,
174      kNameCachePutObject,
175      kNameCachePutObjectVolatile,
176      kNameCachePutOrderedObject,
177      kNameCacheArrayCopy,
178      kNameCacheLast
179    };
180
181    /**
182     * To avoid multiple lookups of a method signature, we cache its proto
183     * index in the IndexCache. These are the indexes into the IndexCache
184     * proto_indexes array.
185     */
186    enum ProtoCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
187      kProtoCacheFirst = 0,
188      kProtoCacheI_I = kProtoCacheFirst,
189      kProtoCacheJ_J,
190      kProtoCacheS_S,
191      kProtoCacheD_D,
192      kProtoCacheDD_D,
193      kProtoCacheF_F,
194      kProtoCacheFF_F,
195      kProtoCacheD_J,
196      kProtoCacheJ_D,
197      kProtoCacheF_I,
198      kProtoCacheI_F,
199      kProtoCacheII_I,
200      kProtoCacheI_C,
201      kProtoCacheString_I,
202      kProtoCache_Z,
203      kProtoCache_I,
204      kProtoCache_Object,
205      kProtoCache_Thread,
206      kProtoCacheJ_B,
207      kProtoCacheJ_I,
208      kProtoCacheJ_S,
209      kProtoCacheJB_V,
210      kProtoCacheJI_V,
211      kProtoCacheJJ_J,
212      kProtoCacheJJ_V,
213      kProtoCacheJS_V,
214      kProtoCacheObjectJII_Z,
215      kProtoCacheObjectJJJ_Z,
216      kProtoCacheObjectJObjectObject_Z,
217      kProtoCacheObjectJ_I,
218      kProtoCacheObjectJI_V,
219      kProtoCacheObjectJ_J,
220      kProtoCacheObjectJJ_V,
221      kProtoCacheObjectJ_Object,
222      kProtoCacheObjectJObject_V,
223      kProtoCacheCharArrayICharArrayII_V,
224      kProtoCacheLast
225    };
226
227  private:
228    /**
229     * The maximum number of method parameters we support in the ProtoDef.
230     */
231    static constexpr uint32_t kProtoMaxParams = 6;
232
233    /**
234     * The method signature (proto) definition using cached class indexes.
235     * The return_type and params are used with the IndexCache to look up
236     * appropriate class indexes to be passed to DexFile::FindProtoId().
237     */
238    struct ProtoDef {
239      ClassCacheIndex return_type;
240      uint8_t param_count;
241      ClassCacheIndex params[kProtoMaxParams];
242    };
243
244    /**
245     * The method definition using cached class, name and proto indexes.
246     * The class index, method name index and proto index are used with
247     * IndexCache to look up appropriate parameters for DexFile::FindMethodId().
248     */
249    struct MethodDef {
250      ClassCacheIndex declaring_class;
251      NameCacheIndex name;
252      ProtoCacheIndex proto;
253    };
254
255    /**
256     * The definition of an intrinsic function binds the method definition
257     * to an Intrinsic.
258     */
259    struct IntrinsicDef {
260      MethodDef method_def;
261      InlineMethod intrinsic;
262    };
263
264    /**
265     * Cache for class, method name and method signature indexes used during
266     * intrinsic function lookup to avoid multiple lookups of the same items.
267     *
268     * Many classes have multiple intrinsics and/or they are used in multiple
269     * method signatures and we want to avoid repeated lookups since they are
270     * not exactly cheap. The method names and method signatures are sometimes
271     * reused and therefore cached as well.
272     */
273    struct IndexCache {
274      IndexCache();
275
276      uint32_t class_indexes[kClassCacheLast - kClassCacheFirst];
277      uint32_t name_indexes[kNameCacheLast - kNameCacheFirst];
278      uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst];
279    };
280
281    static const char* const kClassCacheNames[];
282    static const char* const kNameCacheNames[];
283    static const ProtoDef kProtoCacheDefs[];
284    static const IntrinsicDef kIntrinsicMethods[];
285
286    static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
287    static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
288
289    static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache,
290                                   ClassCacheIndex index);
291    static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache,
292                                  NameCacheIndex index);
293    static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
294                                   ProtoCacheIndex index);
295    static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
296                                    const MethodDef& method_def);
297
298    /**
299     * Find all known intrinsic methods in the dex_file and cache their indices.
300     *
301     * Only DexFileToMethodInlinerMap may call this function to initialize the inliner.
302     */
303    void FindIntrinsics(const DexFile* dex_file) EXCLUSIVE_LOCKS_REQUIRED(lock_);
304
305    friend class DexFileToMethodInlinerMap;
306
307    bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_);
308
309    static bool GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
310                               MIR* move_result, const InlineMethod& method);
311    static bool GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
312                                   MIR* move_result, const InlineMethod& method);
313    static bool GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
314                              MIR* move_result, const InlineMethod& method, uint32_t method_idx);
315    static bool GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
316                              MIR* move_result, const InlineMethod& method, uint32_t method_idx);
317
318    ReaderWriterMutex lock_;
319    /*
320     * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
321     */
322    SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_);
323    const DexFile* dex_file_;
324
325    DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
326};
327
328}  // namespace art
329
330#endif  // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
331