dex_file_method_inliner.h revision 5c96e6b4dc354a7439b211b93462fbe8edea5e57
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  kIntrinsicCas32,
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  // kIntrinsicUnsafeCas32
64  kIntrinsicFlagDontNeedWriteBarrier = 0,
65  kIntrinsicFlagNeedWriteBarrier = 1,
66
67  // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
68  kIntrinsicFlagIsLong     = 1,
69  kIntrinsicFlagIsVolatile = 2,
70  // kIntrinsicUnsafePut
71  kIntrinsicFlagIsObject   = 4,
72  kIntrinsicFlagIsOrdered  = 8,
73};
74
75struct Intrinsic {
76  IntrinsicOpcode opcode;
77  uint32_t data;
78};
79
80/**
81 * Handles inlining of methods from a particular DexFile.
82 *
83 * Intrinsics are a special case of inline methods. The DexFile indices for
84 * all the supported intrinsic methods are looked up once by the FindIntrinsics
85 * function and cached by this class for quick lookup by the method index.
86 *
87 * TODO: Detect short methods (at least getters, setters and empty functions)
88 * from the verifier and mark them for inlining. Inline these methods early
89 * during compilation to allow further optimizations. Similarly, provide
90 * additional information about intrinsics to the early phases of compilation.
91 */
92class DexFileMethodInliner {
93  public:
94    virtual ~DexFileMethodInliner();
95
96    /**
97     * Find all known intrinsic methods in the dex_file and cache their indices.
98     */
99    virtual void FindIntrinsics(const DexFile* dex_file) = 0;
100
101    /**
102     * Check whether a particular method index corresponds to an intrinsic function.
103     */
104    bool IsIntrinsic(uint32_t method_index) const;
105
106    /**
107     * Generate code for an intrinsic function invocation.
108     *
109     * TODO: This should be target-specific. For the time being,
110     * it's shared since it dispatches everything to backend.
111     */
112    bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const;
113
114  protected:
115    DexFileMethodInliner();
116
117    /**
118     * To avoid multiple lookups of a class by its descriptor, we cache its
119     * type index in the IndexCache. These are the indexes into the IndexCache
120     * class_indexes array.
121     */
122    enum ClassCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
123      kClassCacheFirst = 0,
124      kClassCacheBoolean = kClassCacheFirst,
125      kClassCacheByte,
126      kClassCacheChar,
127      kClassCacheShort,
128      kClassCacheInt,
129      kClassCacheLong,
130      kClassCacheFloat,
131      kClassCacheDouble,
132      kClassCacheVoid,
133      kClassCacheJavaLangObject,
134      kClassCacheJavaLangString,
135      kClassCacheJavaLangDouble,
136      kClassCacheJavaLangFloat,
137      kClassCacheJavaLangInteger,
138      kClassCacheJavaLangLong,
139      kClassCacheJavaLangShort,
140      kClassCacheJavaLangMath,
141      kClassCacheJavaLangStrictMath,
142      kClassCacheJavaLangThread,
143      kClassCacheLibcoreIoMemory,
144      kClassCacheSunMiscUnsafe,
145      kClassCacheLast
146    };
147
148    /**
149     * To avoid multiple lookups of a method name string, we cache its string
150     * index in the IndexCache. These are the indexes into the IndexCache
151     * name_indexes array.
152     */
153    enum NameCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
154      kNameCacheFirst = 0,
155      kNameCacheReverseBytes = kNameCacheFirst,
156      kNameCacheDoubleToRawLongBits,
157      kNameCacheLongBitsToDouble,
158      kNameCacheFloatToRawIntBits,
159      kNameCacheIntBitsToFloat,
160      kNameCacheAbs,
161      kNameCacheMax,
162      kNameCacheMin,
163      kNameCacheSqrt,
164      kNameCacheCharAt,
165      kNameCacheCompareTo,
166      kNameCacheIsEmpty,
167      kNameCacheIndexOf,
168      kNameCacheLength,
169      kNameCacheCurrentThread,
170      kNameCachePeekByte,
171      kNameCachePeekIntNative,
172      kNameCachePeekLongNative,
173      kNameCachePeekShortNative,
174      kNameCachePokeByte,
175      kNameCachePokeIntNative,
176      kNameCachePokeLongNative,
177      kNameCachePokeShortNative,
178      kNameCacheCompareAndSwapInt,
179      kNameCacheCompareAndSwapObject,
180      kNameCacheGetInt,
181      kNameCacheGetIntVolatile,
182      kNameCachePutInt,
183      kNameCachePutIntVolatile,
184      kNameCachePutOrderedInt,
185      kNameCacheGetLong,
186      kNameCacheGetLongVolatile,
187      kNameCachePutLong,
188      kNameCachePutLongVolatile,
189      kNameCachePutOrderedLong,
190      kNameCacheGetObject,
191      kNameCacheGetObjectVolatile,
192      kNameCachePutObject,
193      kNameCachePutObjectVolatile,
194      kNameCachePutOrderedObject,
195      kNameCacheLast
196    };
197
198    /**
199     * To avoid multiple lookups of a method signature, we cache its proto
200     * index in the IndexCache. These are the indexes into the IndexCache
201     * proto_indexes array.
202     */
203    enum ProtoCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
204      kProtoCacheFirst = 0,
205      kProtoCacheI_I = kProtoCacheFirst,
206      kProtoCacheJ_J,
207      kProtoCacheS_S,
208      kProtoCacheD_D,
209      kProtoCacheD_J,
210      kProtoCacheJ_D,
211      kProtoCacheF_I,
212      kProtoCacheI_F,
213      kProtoCacheII_I,
214      kProtoCacheI_C,
215      kProtoCacheString_I,
216      kProtoCache_Z,
217      kProtoCache_I,
218      kProtoCache_Thread,
219      kProtoCacheJ_B,
220      kProtoCacheJ_I,
221      kProtoCacheJ_S,
222      kProtoCacheJB_V,
223      kProtoCacheJI_V,
224      kProtoCacheJJ_V,
225      kProtoCacheJS_V,
226      kProtoCacheObjectJII_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