dex_file_method_inliner.h revision 1c282e2b9a9b432e132b2c332f861cad9feb4a73
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 <map>
22
23namespace art {
24
25class CallInfo;
26class DexFile;
27class Mir2Lir;
28
29enum IntrinsicOpcode {
30  kIntrinsicDoubleCvt,
31  kIntrinsicFloatCvt,
32  kIntrinsicReverseBytes,
33  kIntrinsicAbsInt,
34  kIntrinsicAbsLong,
35  kIntrinsicMinMaxInt,
36  kIntrinsicSqrt,
37  kIntrinsicCharAt,
38  kIntrinsicCompareTo,
39  kIntrinsicIsEmptyOrLength,
40  kIntrinsicIndexOf,
41  kIntrinsicCurrentThread,
42  kIntrinsicPeek,
43  kIntrinsicPoke,
44  kIntrinsicCas,
45  kIntrinsicUnsafeGet,
46  kIntrinsicUnsafePut,
47};
48
49enum IntrinsicFlags {
50  kIntrinsicFlagNone = 0,
51
52  // kIntrinsicMinMaxInt
53  kIntrinsicFlagMax = kIntrinsicFlagNone,
54  kIntrinsicFlagMin = 1,
55
56  // kIntrinsicIsEmptyOrLength
57  kIntrinsicFlagLength  = kIntrinsicFlagNone,
58  kIntrinsicFlagIsEmpty = 1,
59
60  // kIntrinsicIndexOf
61  kIntrinsicFlagBase0 = 1,
62
63  // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
64  kIntrinsicFlagIsLong     = 1,
65  // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
66  kIntrinsicFlagIsVolatile = 2,
67  // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
68  kIntrinsicFlagIsObject   = 4,
69  // kIntrinsicUnsafePut
70  kIntrinsicFlagIsOrdered  = 8,
71};
72
73struct Intrinsic {
74  IntrinsicOpcode opcode;
75  uint32_t data;
76};
77
78/**
79 * Handles inlining of methods from a particular DexFile.
80 *
81 * Intrinsics are a special case of inline methods. The DexFile indices for
82 * all the supported intrinsic methods are looked up once by the FindIntrinsics
83 * function and cached by this class for quick lookup by the method index.
84 *
85 * TODO: Detect short methods (at least getters, setters and empty functions)
86 * from the verifier and mark them for inlining. Inline these methods early
87 * during compilation to allow further optimizations. Similarly, provide
88 * additional information about intrinsics to the early phases of compilation.
89 */
90class DexFileMethodInliner {
91  public:
92    virtual ~DexFileMethodInliner();
93
94    /**
95     * Find all known intrinsic methods in the dex_file and cache their indices.
96     */
97    virtual void FindIntrinsics(const DexFile* dex_file) = 0;
98
99    /**
100     * Check whether a particular method index corresponds to an intrinsic function.
101     */
102    bool IsIntrinsic(uint32_t method_index) const;
103
104    /**
105     * Generate code for an intrinsic function invocation.
106     *
107     * TODO: This should be target-specific. For the time being,
108     * it's shared since it dispatches everything to backend.
109     */
110    bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const;
111
112  protected:
113    DexFileMethodInliner();
114
115    /**
116     * To avoid multiple lookups of a class by its descriptor, we cache its
117     * type index in the IndexCache. These are the indexes into the IndexCache
118     * class_indexes array.
119     */
120    enum ClassCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
121      kClassCacheFirst = 0,
122      kClassCacheBoolean = kClassCacheFirst,
123      kClassCacheByte,
124      kClassCacheChar,
125      kClassCacheShort,
126      kClassCacheInt,
127      kClassCacheLong,
128      kClassCacheFloat,
129      kClassCacheDouble,
130      kClassCacheVoid,
131      kClassCacheJavaLangObject,
132      kClassCacheJavaLangString,
133      kClassCacheJavaLangDouble,
134      kClassCacheJavaLangFloat,
135      kClassCacheJavaLangInteger,
136      kClassCacheJavaLangLong,
137      kClassCacheJavaLangShort,
138      kClassCacheJavaLangMath,
139      kClassCacheJavaLangStrictMath,
140      kClassCacheJavaLangThread,
141      kClassCacheLibcoreIoMemory,
142      kClassCacheSunMiscUnsafe,
143      kClassCacheLast
144    };
145
146    /**
147     * To avoid multiple lookups of a method name string, we cache its string
148     * index in the IndexCache. These are the indexes into the IndexCache
149     * name_indexes array.
150     */
151    enum NameCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
152      kNameCacheFirst = 0,
153      kNameCacheReverseBytes = kNameCacheFirst,
154      kNameCacheDoubleToRawLongBits,
155      kNameCacheLongBitsToDouble,
156      kNameCacheFloatToRawIntBits,
157      kNameCacheIntBitsToFloat,
158      kNameCacheAbs,
159      kNameCacheMax,
160      kNameCacheMin,
161      kNameCacheSqrt,
162      kNameCacheCharAt,
163      kNameCacheCompareTo,
164      kNameCacheIsEmpty,
165      kNameCacheIndexOf,
166      kNameCacheLength,
167      kNameCacheCurrentThread,
168      kNameCachePeekByte,
169      kNameCachePeekIntNative,
170      kNameCachePeekLongNative,
171      kNameCachePeekShortNative,
172      kNameCachePokeByte,
173      kNameCachePokeIntNative,
174      kNameCachePokeLongNative,
175      kNameCachePokeShortNative,
176      kNameCacheCompareAndSwapInt,
177      kNameCacheCompareAndSwapLong,
178      kNameCacheCompareAndSwapObject,
179      kNameCacheGetInt,
180      kNameCacheGetIntVolatile,
181      kNameCachePutInt,
182      kNameCachePutIntVolatile,
183      kNameCachePutOrderedInt,
184      kNameCacheGetLong,
185      kNameCacheGetLongVolatile,
186      kNameCachePutLong,
187      kNameCachePutLongVolatile,
188      kNameCachePutOrderedLong,
189      kNameCacheGetObject,
190      kNameCacheGetObjectVolatile,
191      kNameCachePutObject,
192      kNameCachePutObjectVolatile,
193      kNameCachePutOrderedObject,
194      kNameCacheLast
195    };
196
197    /**
198     * To avoid multiple lookups of a method signature, we cache its proto
199     * index in the IndexCache. These are the indexes into the IndexCache
200     * proto_indexes array.
201     */
202    enum ProtoCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
203      kProtoCacheFirst = 0,
204      kProtoCacheI_I = kProtoCacheFirst,
205      kProtoCacheJ_J,
206      kProtoCacheS_S,
207      kProtoCacheD_D,
208      kProtoCacheD_J,
209      kProtoCacheJ_D,
210      kProtoCacheF_I,
211      kProtoCacheI_F,
212      kProtoCacheII_I,
213      kProtoCacheI_C,
214      kProtoCacheString_I,
215      kProtoCache_Z,
216      kProtoCache_I,
217      kProtoCache_Thread,
218      kProtoCacheJ_B,
219      kProtoCacheJ_I,
220      kProtoCacheJ_S,
221      kProtoCacheJB_V,
222      kProtoCacheJI_V,
223      kProtoCacheJJ_V,
224      kProtoCacheJS_V,
225      kProtoCacheObjectJII_Z,
226      kProtoCacheObjectJJJ_Z,
227      kProtoCacheObjectJObjectObject_Z,
228      kProtoCacheObjectJ_I,
229      kProtoCacheObjectJI_V,
230      kProtoCacheObjectJ_J,
231      kProtoCacheObjectJJ_V,
232      kProtoCacheObjectJ_Object,
233      kProtoCacheObjectJObject_V,
234      kProtoCacheLast
235    };
236
237    /**
238     * The maximum number of method parameters we support in the ProtoDef.
239     */
240    static constexpr uint32_t kProtoMaxParams = 6;
241
242    /**
243     * The method signature (proto) definition using cached class indexes.
244     * The return_type and params are used with the IndexCache to look up
245     * appropriate class indexes to be passed to DexFile::FindProtoId().
246     */
247    struct ProtoDef {
248      ClassCacheIndex return_type;
249      uint8_t param_count;
250      ClassCacheIndex params[kProtoMaxParams];
251    };
252
253    /**
254     * The method definition using cached class, name and proto indexes.
255     * The class index, method name index and proto index are used with
256     * IndexCache to look up appropriate parameters for DexFile::FindMethodId().
257     */
258    struct MethodDef {
259      ClassCacheIndex declaring_class;
260      NameCacheIndex name;
261      ProtoCacheIndex proto;
262    };
263
264    /**
265     * The definition of an intrinsic function binds the method definition
266     * to an Intrinsic.
267     */
268    struct IntrinsicDef {
269      MethodDef method_def;
270      Intrinsic intrinsic;
271    };
272
273    /**
274     * Cache for class, method name and method signature indexes used during
275     * intrinsic function lookup to avoid multiple lookups of the same items.
276     *
277     * Many classes have multiple intrinsics and/or they are used in multiple
278     * method signatures and we want to avoid repeated lookups since they are
279     * not exactly cheap. The method names and method signatures are sometimes
280     * reused and therefore cached as well.
281     */
282    struct IndexCache {
283      IndexCache();
284
285      uint32_t class_indexes[kClassCacheLast - kClassCacheFirst];
286      uint32_t name_indexes[kNameCacheLast - kNameCacheFirst];
287      uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst];
288    };
289
290    static const char* kClassCacheNames[];
291    static const char* kNameCacheNames[];
292    static const ProtoDef kProtoCacheDefs[];
293
294    static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
295    static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
296
297    static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache,
298                                   ClassCacheIndex index);
299    static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache,
300                                  NameCacheIndex index);
301    static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
302                                   ProtoCacheIndex index);
303    static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
304                                    const MethodDef& method_def);
305
306    void DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache,
307                          const IntrinsicDef* defs, uint32_t def_count);
308
309    /*
310     * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
311     */
312    std::map<uint32_t, Intrinsic> intrinsics_;
313    const DexFile* dex_file_;
314};
315
316}  // namespace art
317
318#endif  // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
319