dex_file_method_inliner.h revision 0e54c0160c84894696c05af6cad9eae3690f9496
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
34class BasicBlock;
35struct CallInfo;
36class 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_REQUIRES(Locks::mutator_lock_) REQUIRES(!lock_);
66
67    /**
68     * Check whether a particular method index corresponds to an intrinsic or special function.
69     */
70    InlineMethodFlags IsIntrinsicOrSpecial(uint32_t method_index) REQUIRES(!lock_);
71
72    /**
73     * Check whether a particular method index corresponds to an intrinsic function.
74     */
75    bool IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) REQUIRES(!lock_);
76
77    /**
78     * Generate code for an intrinsic function invocation.
79     */
80    bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) REQUIRES(!lock_);
81
82    /**
83     * Check whether a particular method index corresponds to a special function.
84     */
85    bool IsSpecial(uint32_t method_index) REQUIRES(!lock_);
86
87    /**
88     * Generate code for a special function.
89     */
90    bool GenSpecial(Mir2Lir* backend, uint32_t method_idx) REQUIRES(!lock_);
91
92    /**
93     * Try to inline an invoke.
94     */
95    bool GenInline(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke, uint32_t method_idx)
96        REQUIRES(!lock_);
97
98    /**
99     * Gets the thread pointer entrypoint offset for a string init method index and pointer size.
100     */
101    uint32_t GetOffsetForStringInit(uint32_t method_index, size_t pointer_size)
102        REQUIRES(!lock_);
103
104    /**
105     * Check whether a particular method index is a string init.
106     */
107    bool IsStringInitMethodIndex(uint32_t method_index) REQUIRES(!lock_);
108
109    /**
110     * To avoid multiple lookups of a class by its descriptor, we cache its
111     * type index in the IndexCache. These are the indexes into the IndexCache
112     * class_indexes array.
113     */
114    enum ClassCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
115      kClassCacheFirst = 0,
116      kClassCacheBoolean = kClassCacheFirst,
117      kClassCacheByte,
118      kClassCacheChar,
119      kClassCacheShort,
120      kClassCacheInt,
121      kClassCacheLong,
122      kClassCacheFloat,
123      kClassCacheDouble,
124      kClassCacheVoid,
125      kClassCacheJavaLangByteArray,
126      kClassCacheJavaLangCharArray,
127      kClassCacheJavaLangIntArray,
128      kClassCacheJavaLangObject,
129      kClassCacheJavaLangRefReference,
130      kClassCacheJavaLangString,
131      kClassCacheJavaLangStringBuffer,
132      kClassCacheJavaLangStringBuilder,
133      kClassCacheJavaLangStringFactory,
134      kClassCacheJavaLangDouble,
135      kClassCacheJavaLangFloat,
136      kClassCacheJavaLangInteger,
137      kClassCacheJavaLangLong,
138      kClassCacheJavaLangShort,
139      kClassCacheJavaLangMath,
140      kClassCacheJavaLangStrictMath,
141      kClassCacheJavaLangThread,
142      kClassCacheJavaNioCharsetCharset,
143      kClassCacheLibcoreIoMemory,
144      kClassCacheSunMiscUnsafe,
145      kClassCacheJavaLangSystem,
146      kClassCacheLast
147    };
148
149    /**
150     * To avoid multiple lookups of a method name string, we cache its string
151     * index in the IndexCache. These are the indexes into the IndexCache
152     * name_indexes array.
153     */
154    enum NameCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
155      kNameCacheFirst = 0,
156      kNameCacheReverse =  kNameCacheFirst,
157      kNameCacheReverseBytes,
158      kNameCacheDoubleToRawLongBits,
159      kNameCacheLongBitsToDouble,
160      kNameCacheFloatToRawIntBits,
161      kNameCacheIntBitsToFloat,
162      kNameCacheAbs,
163      kNameCacheMax,
164      kNameCacheMin,
165      kNameCacheCos,
166      kNameCacheSin,
167      kNameCacheAcos,
168      kNameCacheAsin,
169      kNameCacheAtan,
170      kNameCacheAtan2,
171      kNameCacheCbrt,
172      kNameCacheCosh,
173      kNameCacheExp,
174      kNameCacheExpm1,
175      kNameCacheHypot,
176      kNameCacheLog,
177      kNameCacheLog10,
178      kNameCacheNextAfter,
179      kNameCacheSinh,
180      kNameCacheTan,
181      kNameCacheTanh,
182      kNameCacheSqrt,
183      kNameCacheCeil,
184      kNameCacheFloor,
185      kNameCacheRint,
186      kNameCacheRound,
187      kNameCacheReferenceGetReferent,
188      kNameCacheCharAt,
189      kNameCacheCompareTo,
190      kNameCacheEquals,
191      kNameCacheGetCharsNoCheck,
192      kNameCacheIsEmpty,
193      kNameCacheFloatToIntBits,
194      kNameCacheDoubleToLongBits,
195      kNameCacheIsInfinite,
196      kNameCacheIsNaN,
197      kNameCacheIndexOf,
198      kNameCacheLength,
199      kNameCacheInit,
200      kNameCacheNewStringFromBytes,
201      kNameCacheNewStringFromChars,
202      kNameCacheNewStringFromString,
203      kNameCacheCurrentThread,
204      kNameCachePeekByte,
205      kNameCachePeekIntNative,
206      kNameCachePeekLongNative,
207      kNameCachePeekShortNative,
208      kNameCachePokeByte,
209      kNameCachePokeIntNative,
210      kNameCachePokeLongNative,
211      kNameCachePokeShortNative,
212      kNameCacheCompareAndSwapInt,
213      kNameCacheCompareAndSwapLong,
214      kNameCacheCompareAndSwapObject,
215      kNameCacheGetInt,
216      kNameCacheGetIntVolatile,
217      kNameCachePutInt,
218      kNameCachePutIntVolatile,
219      kNameCachePutOrderedInt,
220      kNameCacheGetLong,
221      kNameCacheGetLongVolatile,
222      kNameCachePutLong,
223      kNameCachePutLongVolatile,
224      kNameCachePutOrderedLong,
225      kNameCacheGetObject,
226      kNameCacheGetObjectVolatile,
227      kNameCachePutObject,
228      kNameCachePutObjectVolatile,
229      kNameCachePutOrderedObject,
230      kNameCacheGetAndAddInt,
231      kNameCacheGetAndAddLong,
232      kNameCacheGetAndSetInt,
233      kNameCacheGetAndSetLong,
234      kNameCacheGetAndSetObject,
235      kNameCacheLoadFence,
236      kNameCacheStoreFence,
237      kNameCacheFullFence,
238      kNameCacheArrayCopy,
239      kNameCacheBitCount,
240      kNameCacheCompare,
241      kNameCacheHighestOneBit,
242      kNameCacheLowestOneBit,
243      kNameCacheNumberOfLeadingZeros,
244      kNameCacheNumberOfTrailingZeros,
245      kNameCacheRotateRight,
246      kNameCacheRotateLeft,
247      kNameCacheSignum,
248      kNameCacheLast
249    };
250
251    /**
252     * To avoid multiple lookups of a method signature, we cache its proto
253     * index in the IndexCache. These are the indexes into the IndexCache
254     * proto_indexes array.
255     */
256    enum ProtoCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
257      kProtoCacheFirst = 0,
258      kProtoCacheI_I = kProtoCacheFirst,
259      kProtoCacheJ_J,
260      kProtoCacheS_S,
261      kProtoCacheD_D,
262      kProtoCacheDD_D,
263      kProtoCacheF_F,
264      kProtoCacheFF_F,
265      kProtoCacheD_J,
266      kProtoCacheD_Z,
267      kProtoCacheJ_D,
268      kProtoCacheF_I,
269      kProtoCacheF_Z,
270      kProtoCacheI_F,
271      kProtoCacheII_I,
272      kProtoCacheI_C,
273      kProtoCacheString_I,
274      kProtoCache_Z,
275      kProtoCache_I,
276      kProtoCache_Object,
277      kProtoCache_Thread,
278      kProtoCacheJ_B,
279      kProtoCacheJ_I,
280      kProtoCacheJ_S,
281      kProtoCacheJB_V,
282      kProtoCacheJI_V,
283      kProtoCacheJJ_J,
284      kProtoCacheJJ_I,
285      kProtoCacheJJ_V,
286      kProtoCacheJS_V,
287      kProtoCacheObject_Z,
288      kProtoCacheJI_J,
289      kProtoCacheObjectJII_Z,
290      kProtoCacheObjectJJJ_Z,
291      kProtoCacheObjectJObjectObject_Z,
292      kProtoCacheObjectJ_I,
293      kProtoCacheObjectJI_I,
294      kProtoCacheObjectJI_V,
295      kProtoCacheObjectJ_J,
296      kProtoCacheObjectJJ_J,
297      kProtoCacheObjectJJ_V,
298      kProtoCacheObjectJ_Object,
299      kProtoCacheObjectJObject_V,
300      kProtoCacheObjectJObject_Object,
301      kProtoCacheCharArrayICharArrayII_V,
302      kProtoCacheObjectIObjectII_V,
303      kProtoCacheIICharArrayI_V,
304      kProtoCacheByteArrayIII_String,
305      kProtoCacheIICharArray_String,
306      kProtoCacheString_String,
307      kProtoCache_V,
308      kProtoCacheByteArray_V,
309      kProtoCacheByteArrayI_V,
310      kProtoCacheByteArrayII_V,
311      kProtoCacheByteArrayIII_V,
312      kProtoCacheByteArrayIIString_V,
313      kProtoCacheByteArrayString_V,
314      kProtoCacheByteArrayIICharset_V,
315      kProtoCacheByteArrayCharset_V,
316      kProtoCacheCharArray_V,
317      kProtoCacheCharArrayII_V,
318      kProtoCacheIICharArray_V,
319      kProtoCacheIntArrayII_V,
320      kProtoCacheString_V,
321      kProtoCacheStringBuffer_V,
322      kProtoCacheStringBuilder_V,
323      kProtoCacheLast
324    };
325
326  private:
327    /**
328     * The maximum number of method parameters we support in the ProtoDef.
329     */
330    static constexpr uint32_t kProtoMaxParams = 6;
331
332    /**
333     * The method signature (proto) definition using cached class indexes.
334     * The return_type and params are used with the IndexCache to look up
335     * appropriate class indexes to be passed to DexFile::FindProtoId().
336     */
337    struct ProtoDef {
338      ClassCacheIndex return_type;
339      uint8_t param_count;
340      ClassCacheIndex params[kProtoMaxParams];
341    };
342
343    /**
344     * The method definition using cached class, name and proto indexes.
345     * The class index, method name index and proto index are used with
346     * IndexCache to look up appropriate parameters for DexFile::FindMethodId().
347     */
348    struct MethodDef {
349      ClassCacheIndex declaring_class;
350      NameCacheIndex name;
351      ProtoCacheIndex proto;
352    };
353
354    /**
355     * The definition of an intrinsic function binds the method definition
356     * to an Intrinsic.
357     */
358    struct IntrinsicDef {
359      MethodDef method_def;
360      InlineMethod intrinsic;
361    };
362
363    /**
364     * Cache for class, method name and method signature indexes used during
365     * intrinsic function lookup to avoid multiple lookups of the same items.
366     *
367     * Many classes have multiple intrinsics and/or they are used in multiple
368     * method signatures and we want to avoid repeated lookups since they are
369     * not exactly cheap. The method names and method signatures are sometimes
370     * reused and therefore cached as well.
371     */
372    struct IndexCache {
373      IndexCache();
374
375      uint32_t class_indexes[kClassCacheLast - kClassCacheFirst];
376      uint32_t name_indexes[kNameCacheLast - kNameCacheFirst];
377      uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst];
378    };
379
380    static const char* const kClassCacheNames[];
381    static const char* const kNameCacheNames[];
382    static const ProtoDef kProtoCacheDefs[];
383    static const IntrinsicDef kIntrinsicMethods[];
384
385    static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
386    static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
387
388    static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache,
389                                   ClassCacheIndex index);
390    static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache,
391                                  NameCacheIndex index);
392    static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
393                                   ProtoCacheIndex index);
394    static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
395                                    const MethodDef& method_def);
396
397    /**
398     * Find all known intrinsic methods in the dex_file and cache their indices.
399     *
400     * Only DexFileToMethodInlinerMap may call this function to initialize the inliner.
401     */
402    void FindIntrinsics(const DexFile* dex_file) REQUIRES(lock_);
403
404    friend class DexFileToMethodInlinerMap;
405
406    bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) REQUIRES(!lock_);
407
408    static bool GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
409                               MIR* move_result, const InlineMethod& method);
410    static bool GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
411                                   MIR* move_result, const InlineMethod& method);
412    static bool GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
413                              MIR* move_result, const InlineMethod& method);
414    static bool GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
415                              MIR* move_result, const InlineMethod& method);
416
417    ReaderWriterMutex lock_;
418    /*
419     * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
420     */
421    SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_);
422    const DexFile* dex_file_;
423
424    DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
425};
426
427}  // namespace art
428
429#endif  // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
430