• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
28  namespace art {
29  
30  namespace verifier {
31  class MethodVerifier;
32  }  // namespace verifier
33  
34  class BasicBlock;
35  struct CallInfo;
36  class MIR;
37  class MIRGraph;
38  class 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   */
52  class 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 or special function.
69       */
70      InlineMethodFlags IsIntrinsicOrSpecial(uint32_t method_index) LOCKS_EXCLUDED(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) LOCKS_EXCLUDED(lock_);
76  
77      /**
78       * Generate code for an intrinsic function invocation.
79       */
80      bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) LOCKS_EXCLUDED(lock_);
81  
82      /**
83       * Check whether a particular method index corresponds to a special function.
84       */
85      bool IsSpecial(uint32_t method_index) LOCKS_EXCLUDED(lock_);
86  
87      /**
88       * Generate code for a special function.
89       */
90      bool GenSpecial(Mir2Lir* backend, uint32_t method_idx) LOCKS_EXCLUDED(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          LOCKS_EXCLUDED(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          LOCKS_EXCLUDED(lock_);
103  
104      /**
105       * Check whether a particular method index is a string init.
106       */
107      bool IsStringInitMethodIndex(uint32_t method_index) LOCKS_EXCLUDED(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        kNameCacheSqrt,
166        kNameCacheCeil,
167        kNameCacheFloor,
168        kNameCacheRint,
169        kNameCacheRound,
170        kNameCacheReferenceGetReferent,
171        kNameCacheCharAt,
172        kNameCacheCompareTo,
173        kNameCacheGetCharsNoCheck,
174        kNameCacheIsEmpty,
175        kNameCacheIndexOf,
176        kNameCacheLength,
177        kNameCacheInit,
178        kNameCacheNewStringFromBytes,
179        kNameCacheNewStringFromChars,
180        kNameCacheNewStringFromString,
181        kNameCacheCurrentThread,
182        kNameCachePeekByte,
183        kNameCachePeekIntNative,
184        kNameCachePeekLongNative,
185        kNameCachePeekShortNative,
186        kNameCachePokeByte,
187        kNameCachePokeIntNative,
188        kNameCachePokeLongNative,
189        kNameCachePokeShortNative,
190        kNameCacheCompareAndSwapInt,
191        kNameCacheCompareAndSwapLong,
192        kNameCacheCompareAndSwapObject,
193        kNameCacheGetInt,
194        kNameCacheGetIntVolatile,
195        kNameCachePutInt,
196        kNameCachePutIntVolatile,
197        kNameCachePutOrderedInt,
198        kNameCacheGetLong,
199        kNameCacheGetLongVolatile,
200        kNameCachePutLong,
201        kNameCachePutLongVolatile,
202        kNameCachePutOrderedLong,
203        kNameCacheGetObject,
204        kNameCacheGetObjectVolatile,
205        kNameCachePutObject,
206        kNameCachePutObjectVolatile,
207        kNameCachePutOrderedObject,
208        kNameCacheArrayCopy,
209        kNameCacheLast
210      };
211  
212      /**
213       * To avoid multiple lookups of a method signature, we cache its proto
214       * index in the IndexCache. These are the indexes into the IndexCache
215       * proto_indexes array.
216       */
217      enum ProtoCacheIndex : uint8_t {  // unit8_t to save space, make larger if needed
218        kProtoCacheFirst = 0,
219        kProtoCacheI_I = kProtoCacheFirst,
220        kProtoCacheJ_J,
221        kProtoCacheS_S,
222        kProtoCacheD_D,
223        kProtoCacheDD_D,
224        kProtoCacheF_F,
225        kProtoCacheFF_F,
226        kProtoCacheD_J,
227        kProtoCacheJ_D,
228        kProtoCacheF_I,
229        kProtoCacheI_F,
230        kProtoCacheII_I,
231        kProtoCacheI_C,
232        kProtoCacheString_I,
233        kProtoCache_Z,
234        kProtoCache_I,
235        kProtoCache_Object,
236        kProtoCache_Thread,
237        kProtoCacheJ_B,
238        kProtoCacheJ_I,
239        kProtoCacheJ_S,
240        kProtoCacheJB_V,
241        kProtoCacheJI_V,
242        kProtoCacheJJ_J,
243        kProtoCacheJJ_V,
244        kProtoCacheJS_V,
245        kProtoCacheObjectJII_Z,
246        kProtoCacheObjectJJJ_Z,
247        kProtoCacheObjectJObjectObject_Z,
248        kProtoCacheObjectJ_I,
249        kProtoCacheObjectJI_V,
250        kProtoCacheObjectJ_J,
251        kProtoCacheObjectJJ_V,
252        kProtoCacheObjectJ_Object,
253        kProtoCacheObjectJObject_V,
254        kProtoCacheCharArrayICharArrayII_V,
255        kProtoCacheIICharArrayI_V,
256        kProtoCacheByteArrayIII_String,
257        kProtoCacheIICharArray_String,
258        kProtoCacheString_String,
259        kProtoCache_V,
260        kProtoCacheByteArray_V,
261        kProtoCacheByteArrayI_V,
262        kProtoCacheByteArrayII_V,
263        kProtoCacheByteArrayIII_V,
264        kProtoCacheByteArrayIIString_V,
265        kProtoCacheByteArrayString_V,
266        kProtoCacheByteArrayIICharset_V,
267        kProtoCacheByteArrayCharset_V,
268        kProtoCacheCharArray_V,
269        kProtoCacheCharArrayII_V,
270        kProtoCacheIICharArray_V,
271        kProtoCacheIntArrayII_V,
272        kProtoCacheString_V,
273        kProtoCacheStringBuffer_V,
274        kProtoCacheStringBuilder_V,
275        kProtoCacheLast
276      };
277  
278    private:
279      /**
280       * The maximum number of method parameters we support in the ProtoDef.
281       */
282      static constexpr uint32_t kProtoMaxParams = 6;
283  
284      /**
285       * The method signature (proto) definition using cached class indexes.
286       * The return_type and params are used with the IndexCache to look up
287       * appropriate class indexes to be passed to DexFile::FindProtoId().
288       */
289      struct ProtoDef {
290        ClassCacheIndex return_type;
291        uint8_t param_count;
292        ClassCacheIndex params[kProtoMaxParams];
293      };
294  
295      /**
296       * The method definition using cached class, name and proto indexes.
297       * The class index, method name index and proto index are used with
298       * IndexCache to look up appropriate parameters for DexFile::FindMethodId().
299       */
300      struct MethodDef {
301        ClassCacheIndex declaring_class;
302        NameCacheIndex name;
303        ProtoCacheIndex proto;
304      };
305  
306      /**
307       * The definition of an intrinsic function binds the method definition
308       * to an Intrinsic.
309       */
310      struct IntrinsicDef {
311        MethodDef method_def;
312        InlineMethod intrinsic;
313      };
314  
315      /**
316       * Cache for class, method name and method signature indexes used during
317       * intrinsic function lookup to avoid multiple lookups of the same items.
318       *
319       * Many classes have multiple intrinsics and/or they are used in multiple
320       * method signatures and we want to avoid repeated lookups since they are
321       * not exactly cheap. The method names and method signatures are sometimes
322       * reused and therefore cached as well.
323       */
324      struct IndexCache {
325        IndexCache();
326  
327        uint32_t class_indexes[kClassCacheLast - kClassCacheFirst];
328        uint32_t name_indexes[kNameCacheLast - kNameCacheFirst];
329        uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst];
330      };
331  
332      static const char* const kClassCacheNames[];
333      static const char* const kNameCacheNames[];
334      static const ProtoDef kProtoCacheDefs[];
335      static const IntrinsicDef kIntrinsicMethods[];
336  
337      static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
338      static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
339  
340      static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache,
341                                     ClassCacheIndex index);
342      static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache,
343                                    NameCacheIndex index);
344      static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
345                                     ProtoCacheIndex index);
346      static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
347                                      const MethodDef& method_def);
348  
349      /**
350       * Find all known intrinsic methods in the dex_file and cache their indices.
351       *
352       * Only DexFileToMethodInlinerMap may call this function to initialize the inliner.
353       */
354      void FindIntrinsics(const DexFile* dex_file) EXCLUSIVE_LOCKS_REQUIRED(lock_);
355  
356      friend class DexFileToMethodInlinerMap;
357  
358      bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_);
359  
360      static bool GenInlineConst(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
361                                 MIR* move_result, const InlineMethod& method);
362      static bool GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
363                                     MIR* move_result, const InlineMethod& method);
364      static bool GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
365                                MIR* move_result, const InlineMethod& method);
366      static bool GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
367                                MIR* move_result, const InlineMethod& method);
368  
369      ReaderWriterMutex lock_;
370      /*
371       * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
372       */
373      SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_);
374      const DexFile* dex_file_;
375  
376      DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
377  };
378  
379  }  // namespace art
380  
381  #endif  // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
382