dex_file_method_inliner.cc revision e13717e796d338b08ea66f6a7e3470ca44de707f
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#include <algorithm>
18#include "base/macros.h"
19#include "base/mutex.h"
20#include "base/mutex-inl.h"
21#include "thread.h"
22#include "thread-inl.h"
23#include "dex/mir_graph.h"
24
25#include "dex_file_method_inliner.h"
26
27namespace art {
28
29const uint32_t DexFileMethodInliner::kIndexUnresolved;
30const char* DexFileMethodInliner::kClassCacheNames[] = {
31    "Z",                       // kClassCacheBoolean
32    "B",                       // kClassCacheByte
33    "C",                       // kClassCacheChar
34    "S",                       // kClassCacheShort
35    "I",                       // kClassCacheInt
36    "J",                       // kClassCacheLong
37    "F",                       // kClassCacheFloat
38    "D",                       // kClassCacheDouble
39    "V",                       // kClassCacheVoid
40    "Ljava/lang/Object;",      // kClassCacheJavaLangObject
41    "Ljava/lang/String;",      // kClassCacheJavaLangString
42    "Ljava/lang/Double;",      // kClassCacheJavaLangDouble
43    "Ljava/lang/Float;",       // kClassCacheJavaLangFloat
44    "Ljava/lang/Integer;",     // kClassCacheJavaLangInteger
45    "Ljava/lang/Long;",        // kClassCacheJavaLangLong
46    "Ljava/lang/Short;",       // kClassCacheJavaLangShort
47    "Ljava/lang/Math;",        // kClassCacheJavaLangMath
48    "Ljava/lang/StrictMath;",  // kClassCacheJavaLangStrictMath
49    "Ljava/lang/Thread;",      // kClassCacheJavaLangThread
50    "Llibcore/io/Memory;",     // kClassCacheLibcoreIoMemory
51    "Lsun/misc/Unsafe;",       // kClassCacheSunMiscUnsafe
52};
53
54const char* DexFileMethodInliner::kNameCacheNames[] = {
55    "reverseBytes",          // kNameCacheReverseBytes
56    "doubleToRawLongBits",   // kNameCacheDoubleToRawLongBits
57    "longBitsToDouble",      // kNameCacheLongBitsToDouble
58    "floatToRawIntBits",     // kNameCacheFloatToRawIntBits
59    "intBitsToFloat",        // kNameCacheIntBitsToFloat
60    "abs",                   // kNameCacheAbs
61    "max",                   // kNameCacheMax
62    "min",                   // kNameCacheMin
63    "sqrt",                  // kNameCacheSqrt
64    "charAt",                // kNameCacheCharAt
65    "compareTo",             // kNameCacheCompareTo
66    "isEmpty",               // kNameCacheIsEmpty
67    "indexOf",               // kNameCacheIndexOf
68    "length",                // kNameCacheLength
69    "currentThread",         // kNameCacheCurrentThread
70    "peekByte",              // kNameCachePeekByte
71    "peekIntNative",         // kNameCachePeekIntNative
72    "peekLongNative",        // kNameCachePeekLongNative
73    "peekShortNative",       // kNameCachePeekShortNative
74    "pokeByte",              // kNameCachePokeByte
75    "pokeIntNative",         // kNameCachePokeIntNative
76    "pokeLongNative",        // kNameCachePokeLongNative
77    "pokeShortNative",       // kNameCachePokeShortNative
78    "compareAndSwapInt",     // kNameCacheCompareAndSwapInt
79    "compareAndSwapLong",    // kNameCacheCompareAndSwapLong
80    "compareAndSwapObject",  // kNameCacheCompareAndSwapObject
81    "getInt",                // kNameCacheGetInt
82    "getIntVolatile",        // kNameCacheGetIntVolatile
83    "putInt",                // kNameCachePutInt
84    "putIntVolatile",        // kNameCachePutIntVolatile
85    "putOrderedInt",         // kNameCachePutOrderedInt
86    "getLong",               // kNameCacheGetLong
87    "getLongVolatile",       // kNameCacheGetLongVolatile
88    "putLong",               // kNameCachePutLong
89    "putLongVolatile",       // kNameCachePutLongVolatile
90    "putOrderedLong",        // kNameCachePutOrderedLong
91    "getObject",             // kNameCacheGetObject
92    "getObjectVolatile",     // kNameCacheGetObjectVolatile
93    "putObject",             // kNameCachePutObject
94    "putObjectVolatile",     // kNameCachePutObjectVolatile
95    "putOrderedObject",      // kNameCachePutOrderedObject
96};
97
98const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
99    // kProtoCacheI_I
100    { kClassCacheInt, 1, { kClassCacheInt } },
101    // kProtoCacheJ_J
102    { kClassCacheLong, 1, { kClassCacheLong } },
103    // kProtoCacheS_S
104    { kClassCacheShort, 1, { kClassCacheShort } },
105    // kProtoCacheD_D
106    { kClassCacheDouble, 1, { kClassCacheDouble } },
107    // kProtoCacheD_J
108    { kClassCacheLong, 1, { kClassCacheDouble } },
109    // kProtoCacheJ_D
110    { kClassCacheDouble, 1, { kClassCacheLong } },
111    // kProtoCacheF_I
112    { kClassCacheInt, 1, { kClassCacheFloat } },
113    // kProtoCacheI_F
114    { kClassCacheFloat, 1, { kClassCacheInt } },
115    // kProtoCacheII_I
116    { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } },
117    // kProtoCacheI_C
118    { kClassCacheChar, 1, { kClassCacheInt } },
119    // kProtoCacheString_I
120    { kClassCacheInt, 1, { kClassCacheJavaLangString } },
121    // kProtoCache_Z
122    { kClassCacheBoolean, 0, { } },
123    // kProtoCache_I
124    { kClassCacheInt, 0, { } },
125    // kProtoCache_Thread
126    { kClassCacheJavaLangThread, 0, { } },
127    // kProtoCacheJ_B
128    { kClassCacheByte, 1, { kClassCacheLong } },
129    // kProtoCacheJ_I
130    { kClassCacheInt, 1, { kClassCacheLong } },
131    // kProtoCacheJ_S
132    { kClassCacheShort, 1, { kClassCacheLong } },
133    // kProtoCacheJB_V
134    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } },
135    // kProtoCacheJI_V
136    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
137    // kProtoCacheJJ_V
138    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
139    // kProtoCacheJS_V
140    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } },
141    // kProtoCacheObjectJII_Z
142    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
143        kClassCacheInt, kClassCacheInt } },
144    // kProtoCacheObjectJJJ_Z
145    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
146        kClassCacheLong, kClassCacheLong } },
147    // kProtoCacheObjectJObjectObject_Z
148    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
149        kClassCacheJavaLangObject, kClassCacheJavaLangObject } },
150    // kProtoCacheObjectJ_I
151    { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
152    // kProtoCacheObjectJI_V
153    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
154    // kProtoCacheObjectJ_J
155    { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
156    // kProtoCacheObjectJJ_V
157    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
158    // kProtoCacheObjectJ_Object
159    { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
160    // kProtoCacheObjectJObject_V
161    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong,
162        kClassCacheJavaLangObject } },
163};
164
165const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
166#define INTRINSIC(c, n, p, o, d) \
167    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
168
169    INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
170    INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
171    INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
172    INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
173
174    INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
175    INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
176    INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
177
178    INTRINSIC(JavaLangMath,       Abs, I_I, kIntrinsicAbsInt, 0),
179    INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
180    INTRINSIC(JavaLangMath,       Abs, J_J, kIntrinsicAbsLong, 0),
181    INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
182    INTRINSIC(JavaLangMath,       Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
183    INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
184    INTRINSIC(JavaLangMath,       Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
185    INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
186    INTRINSIC(JavaLangMath,       Sqrt, D_D, kIntrinsicSqrt, 0),
187    INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
188
189    INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
190    INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
191    INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
192    INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
193    INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
194    INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
195
196    INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
197
198    INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
199    INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
200    INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
201    INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
202    INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
203    INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
204    INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
205    INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
206
207    INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
208              kIntrinsicFlagNone),
209    INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
210              kIntrinsicFlagIsLong),
211    INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
212              kIntrinsicFlagIsObject),
213
214#define UNSAFE_GET_PUT(type, code, type_flags) \
215    INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
216              type_flags & ~kIntrinsicFlagIsObject), \
217    INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
218              (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
219    INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
220              type_flags), \
221    INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
222              type_flags | kIntrinsicFlagIsVolatile), \
223    INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
224              type_flags | kIntrinsicFlagIsOrdered)
225
226    UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
227    UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
228    UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
229#undef UNSAFE_GET_PUT
230
231#undef INTRINSIC
232};
233
234DexFileMethodInliner::DexFileMethodInliner()
235    : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock),
236      dex_file_(NULL) {
237  COMPILE_ASSERT(kClassCacheFirst == 0, kClassCacheFirst_not_0);
238  COMPILE_ASSERT(arraysize(kClassCacheNames) == kClassCacheLast, bad_arraysize_kClassCacheNames);
239  COMPILE_ASSERT(kNameCacheFirst == 0, kNameCacheFirst_not_0);
240  COMPILE_ASSERT(arraysize(kNameCacheNames) == kNameCacheLast, bad_arraysize_kNameCacheNames);
241  COMPILE_ASSERT(kProtoCacheFirst == 0, kProtoCacheFirst_not_0);
242  COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames);
243}
244
245DexFileMethodInliner::~DexFileMethodInliner() {
246}
247
248bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
249  ReaderMutexLock mu(Thread::Current(), lock_);
250  return intrinsics_.find(method_index) != intrinsics_.end();
251}
252
253bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
254  Intrinsic intrinsic;
255  {
256    ReaderMutexLock mu(Thread::Current(), lock_);
257    auto it = intrinsics_.find(info->index);
258    if (it == intrinsics_.end()) {
259      return false;
260    }
261    intrinsic = it->second;
262  }
263  switch (intrinsic.opcode) {
264    case kIntrinsicDoubleCvt:
265      return backend->GenInlinedDoubleCvt(info);
266    case kIntrinsicFloatCvt:
267      return backend->GenInlinedFloatCvt(info);
268    case kIntrinsicReverseBytes:
269      return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.data));
270    case kIntrinsicAbsInt:
271      return backend->GenInlinedAbsInt(info);
272    case kIntrinsicAbsLong:
273      return backend->GenInlinedAbsLong(info);
274    case kIntrinsicMinMaxInt:
275      return backend->GenInlinedMinMaxInt(info, intrinsic.data & kIntrinsicFlagMin);
276    case kIntrinsicSqrt:
277      return backend->GenInlinedSqrt(info);
278    case kIntrinsicCharAt:
279      return backend->GenInlinedCharAt(info);
280    case kIntrinsicCompareTo:
281      return backend->GenInlinedStringCompareTo(info);
282    case kIntrinsicIsEmptyOrLength:
283      return backend->GenInlinedStringIsEmptyOrLength(info, intrinsic.data & kIntrinsicFlagIsEmpty);
284    case kIntrinsicIndexOf:
285      return backend->GenInlinedIndexOf(info, intrinsic.data & kIntrinsicFlagBase0);
286    case kIntrinsicCurrentThread:
287      return backend->GenInlinedCurrentThread(info);
288    case kIntrinsicPeek:
289      return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.data));
290    case kIntrinsicPoke:
291      return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.data));
292    case kIntrinsicCas:
293      return backend->GenInlinedCas(info, intrinsic.data & kIntrinsicFlagIsLong,
294                                    intrinsic.data & kIntrinsicFlagIsObject);
295    case kIntrinsicUnsafeGet:
296      return backend->GenInlinedUnsafeGet(info, intrinsic.data & kIntrinsicFlagIsLong,
297                                          intrinsic.data & kIntrinsicFlagIsVolatile);
298    case kIntrinsicUnsafePut:
299      return backend->GenInlinedUnsafePut(info, intrinsic.data & kIntrinsicFlagIsLong,
300                                          intrinsic.data & kIntrinsicFlagIsObject,
301                                          intrinsic.data & kIntrinsicFlagIsVolatile,
302                                          intrinsic.data & kIntrinsicFlagIsOrdered);
303    default:
304      LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
305      return false;  // avoid warning "control reaches end of non-void function"
306  }
307}
308
309uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache,
310                                              ClassCacheIndex index) {
311  uint32_t* class_index = &cache->class_indexes[index];
312  if (*class_index != kIndexUnresolved) {
313    return *class_index;
314  }
315
316  const DexFile::StringId* string_id = dex_file->FindStringId(kClassCacheNames[index]);
317  if (string_id == nullptr) {
318    *class_index = kIndexNotFound;
319    return *class_index;
320  }
321  uint32_t string_index = dex_file->GetIndexForStringId(*string_id);
322
323  const DexFile::TypeId* type_id = dex_file->FindTypeId(string_index);
324  if (type_id == nullptr) {
325    *class_index = kIndexNotFound;
326    return *class_index;
327  }
328  *class_index = dex_file->GetIndexForTypeId(*type_id);
329  return *class_index;
330}
331
332uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache,
333                                             NameCacheIndex index) {
334  uint32_t* name_index = &cache->name_indexes[index];
335  if (*name_index != kIndexUnresolved) {
336    return *name_index;
337  }
338
339  const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]);
340  if (string_id == nullptr) {
341    *name_index = kIndexNotFound;
342    return *name_index;
343  }
344  *name_index = dex_file->GetIndexForStringId(*string_id);
345  return *name_index;
346}
347
348uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
349                                              ProtoCacheIndex index) {
350  uint32_t* proto_index = &cache->proto_indexes[index];
351  if (*proto_index != kIndexUnresolved) {
352    return *proto_index;
353  }
354
355  const ProtoDef& proto_def = kProtoCacheDefs[index];
356  uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type);
357  if (return_index == kIndexNotFound) {
358    *proto_index = kIndexNotFound;
359    return *proto_index;
360  }
361  uint16_t return_type = static_cast<uint16_t>(return_index);
362  DCHECK_EQ(static_cast<uint32_t>(return_type), return_index);
363
364  uint32_t signature_length = proto_def.param_count;
365  uint16_t signature_type_idxs[kProtoMaxParams];
366  for (uint32_t i = 0; i != signature_length; ++i) {
367    uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]);
368    if (param_index == kIndexNotFound) {
369      *proto_index = kIndexNotFound;
370      return *proto_index;
371    }
372    signature_type_idxs[i] = static_cast<uint16_t>(param_index);
373    DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index);
374  }
375
376  const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs,
377                                                           signature_length);
378  if (proto_id == nullptr) {
379    *proto_index = kIndexNotFound;
380    return *proto_index;
381  }
382  *proto_index = dex_file->GetIndexForProtoId(*proto_id);
383  return *proto_index;
384}
385
386uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
387                                               const MethodDef& method_def) {
388  uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class);
389  if (declaring_class_index == kIndexNotFound) {
390    return kIndexNotFound;
391  }
392  uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name);
393  if (name_index == kIndexNotFound) {
394    return kIndexNotFound;
395  }
396  uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto);
397  if (proto_index == kIndexNotFound) {
398    return kIndexNotFound;
399  }
400  const DexFile::MethodId* method_id =
401      dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index),
402                             dex_file->GetStringId(name_index),
403                             dex_file->GetProtoId(proto_index));
404  if (method_id == nullptr) {
405    return kIndexNotFound;
406  }
407  return dex_file->GetIndexForMethodId(*method_id);
408}
409
410DexFileMethodInliner::IndexCache::IndexCache() {
411  std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved);
412  std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved);
413  std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
414}
415
416void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
417  DCHECK(dex_file != nullptr);
418  DCHECK(dex_file_ == nullptr);
419  IndexCache cache;
420  for (const IntrinsicDef& def : kIntrinsicMethods) {
421    uint32_t method_id = FindMethodIndex(dex_file, &cache, def.method_def);
422    if (method_id != kIndexNotFound) {
423      DCHECK(intrinsics_.find(method_id) == intrinsics_.end());
424      intrinsics_[method_id] = def.intrinsic;
425    }
426  }
427  dex_file_ = dex_file;
428}
429
430}  // namespace art
431