dex_file_method_inliner.cc revision e4a50ee34695a9d90cf03fbb1e8afd1e434f6ee1
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 "dex/mir_graph.h"
20
21#include "dex_file_method_inliner.h"
22
23namespace art {
24
25const char* DexFileMethodInliner::kClassCacheNames[] = {
26    "Z",                       // kClassCacheBoolean
27    "B",                       // kClassCacheByte
28    "C",                       // kClassCacheChar
29    "S",                       // kClassCacheShort
30    "I",                       // kClassCacheInt
31    "J",                       // kClassCacheLong
32    "F",                       // kClassCacheFloat
33    "D",                       // kClassCacheDouble
34    "V",                       // kClassCacheVoid
35    "Ljava/lang/Object;",      // kClassCacheJavaLangObject
36    "Ljava/lang/String;",      // kClassCacheJavaLangString
37    "Ljava/lang/Double;",      // kClassCacheJavaLangDouble
38    "Ljava/lang/Float;",       // kClassCacheJavaLangFloat
39    "Ljava/lang/Integer;",     // kClassCacheJavaLangInteger
40    "Ljava/lang/Long;",        // kClassCacheJavaLangLong
41    "Ljava/lang/Short;",       // kClassCacheJavaLangShort
42    "Ljava/lang/Math;",        // kClassCacheJavaLangMath
43    "Ljava/lang/StrictMath;",  // kClassCacheJavaLangStrictMath
44    "Ljava/lang/Thread;",      // kClassCacheJavaLangThread
45    "Llibcore/io/Memory;",     // kClassCacheLibcoreIoMemory
46    "Lsun/misc/Unsafe;",       // kClassCacheSunMiscUnsafe
47};
48
49const char* DexFileMethodInliner::kNameCacheNames[] = {
50    "reverseBytes",          // kNameCacheReverseBytes
51    "doubleToRawLongBits",   // kNameCacheDoubleToRawLongBits
52    "longBitsToDouble",      // kNameCacheLongBitsToDouble
53    "floatToRawIntBits",     // kNameCacheFloatToRawIntBits
54    "intBitsToFloat",        // kNameCacheIntBitsToFloat
55    "abs",                   // kNameCacheAbs
56    "max",                   // kNameCacheMax
57    "min",                   // kNameCacheMin
58    "sqrt",                  // kNameCacheSqrt
59    "charAt",                // kNameCacheCharAt
60    "compareTo",             // kNameCacheCompareTo
61    "is_empty",              // kNameCacheIsEmpty
62    "index_of",              // kNameCacheIndexOf
63    "length",                // kNameCacheLength
64    "currentThread",         // kNameCacheCurrentThread
65    "peekByte",              // kNameCachePeekByte
66    "peekIntNative",         // kNameCachePeekIntNative
67    "peekLongNative",        // kNameCachePeekLongNative
68    "peekShortNative",       // kNameCachePeekShortNative
69    "pokeByte",              // kNameCachePokeByte
70    "pokeIntNative",         // kNameCachePokeIntNative
71    "pokeLongNative",        // kNameCachePokeLongNative
72    "pokeShortNative",       // kNameCachePokeShortNative
73    "compareAndSwapInt",     // kNameCacheCompareAndSwapInt
74    "compareAndSwapObject",  // kNameCacheCompareAndSwapObject
75    "getInt",                // kNameCacheGetInt
76    "getIntVolatile",        // kNameCacheGetIntVolatile
77    "putInt",                // kNameCachePutInt
78    "putIntVolatile",        // kNameCachePutIntVolatile
79    "putOrderedInt",         // kNameCachePutOrderedInt
80    "getLong",               // kNameCacheGetLong
81    "getLongVolatile",       // kNameCacheGetLongVolatile
82    "putLong",               // kNameCachePutLong
83    "putLongVolatile",       // kNameCachePutLongVolatile
84    "putOrderedLong",        // kNameCachePutOrderedLong
85    "getObject",             // kNameCacheGetObject
86    "getObjectVolatile",     // kNameCacheGetObjectVolatile
87    "putObject",             // kNameCachePutObject
88    "putObjectVolatile",     // kNameCachePutObjectVolatile
89    "putOrderedObject",      // kNameCachePutOrderedObject
90};
91
92const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
93    // kProtoCacheI_I
94    { kClassCacheInt, 1, { kClassCacheInt } },
95    // kProtoCacheJ_J
96    { kClassCacheLong, 1, { kClassCacheLong } },
97    // kProtoCacheS_S
98    { kClassCacheShort, 1, { kClassCacheShort } },
99    // kProtoCacheD_D
100    { kClassCacheDouble, 1, { kClassCacheDouble } },
101    // kProtoCacheD_J
102    { kClassCacheLong, 1, { kClassCacheDouble } },
103    // kProtoCacheJ_D
104    { kClassCacheDouble, 1, { kClassCacheLong } },
105    // kProtoCacheF_I
106    { kClassCacheInt, 1, { kClassCacheFloat } },
107    // kProtoCacheI_F
108    { kClassCacheFloat, 1, { kClassCacheInt } },
109    // kProtoCacheII_I
110    { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } },
111    // kProtoCacheI_C
112    { kClassCacheChar, 1, { kClassCacheInt } },
113    // kProtoCacheString_I
114    { kClassCacheInt, 1, { kClassCacheJavaLangString } },
115    // kProtoCache_Z
116    { kClassCacheBoolean, 0, { } },
117    // kProtoCache_I
118    { kClassCacheInt, 0, { } },
119    // kProtoCache_Thread
120    { kClassCacheJavaLangThread, 0, { } },
121    // kProtoCacheJ_B
122    { kClassCacheByte, 1, { kClassCacheLong } },
123    // kProtoCacheJ_I
124    { kClassCacheInt, 1, { kClassCacheLong } },
125    // kProtoCacheJ_S
126    { kClassCacheShort, 1, { kClassCacheLong } },
127    // kProtoCacheJB_V
128    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } },
129    // kProtoCacheJI_V
130    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
131    // kProtoCacheJJ_V
132    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
133    // kProtoCacheJS_V
134    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } },
135    // kProtoCacheObjectJII_Z
136    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
137        kClassCacheInt, kClassCacheInt } },
138    // kProtoCacheObjectJObjectObject_Z
139    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
140        kClassCacheJavaLangObject, kClassCacheJavaLangObject } },
141    // kProtoCacheObjectJ_I
142    { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
143    // kProtoCacheObjectJI_V
144    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
145    // kProtoCacheObjectJ_J
146    { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
147    // kProtoCacheObjectJJ_V
148    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
149    // kProtoCacheObjectJ_Object
150    { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
151    // kProtoCacheObjectJObject_V
152    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong,
153        kClassCacheJavaLangObject } },
154};
155
156DexFileMethodInliner::~DexFileMethodInliner() {
157}
158
159DexFileMethodInliner::DexFileMethodInliner()
160    : dex_file_(NULL) {
161  COMPILE_ASSERT(kClassCacheFirst == 0, kClassCacheFirst_not_0);
162  COMPILE_ASSERT(arraysize(kClassCacheNames) == kClassCacheLast, bad_arraysize_kClassCacheNames);
163  COMPILE_ASSERT(kNameCacheFirst == 0, kNameCacheFirst_not_0);
164  COMPILE_ASSERT(arraysize(kNameCacheNames) == kNameCacheLast, bad_arraysize_kNameCacheNames);
165  COMPILE_ASSERT(kProtoCacheFirst == 0, kProtoCacheFirst_not_0);
166  COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames);
167}
168
169bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) const {
170  return intrinsics_.find(method_index) != intrinsics_.end();
171}
172
173bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) const {
174  auto it = intrinsics_.find(info->index);
175  if (it == intrinsics_.end()) {
176    return false;
177  }
178  const Intrinsic& intrinsic = it->second;
179  switch (intrinsic.opcode) {
180    case kIntrinsicDoubleCvt:
181      return backend->GenInlinedDoubleCvt(info);
182    case kIntrinsicFloatCvt:
183      return backend->GenInlinedFloatCvt(info);
184    case kIntrinsicReverseBytes:
185      return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.data));
186    case kIntrinsicAbsInt:
187      return backend->GenInlinedAbsInt(info);
188    case kIntrinsicAbsLong:
189      return backend->GenInlinedAbsLong(info);
190    case kIntrinsicMinMaxInt:
191      return backend->GenInlinedMinMaxInt(info, intrinsic.data & kIntrinsicFlagMin);
192    case kIntrinsicSqrt:
193      return backend->GenInlinedSqrt(info);
194    case kIntrinsicCharAt:
195      return backend->GenInlinedCharAt(info);
196    case kIntrinsicCompareTo:
197      return backend->GenInlinedStringCompareTo(info);
198    case kIntrinsicIsEmptyOrLength:
199      return backend->GenInlinedStringIsEmptyOrLength(info, intrinsic.data & kIntrinsicFlagIsEmpty);
200    case kIntrinsicIndexOf:
201      return backend->GenInlinedIndexOf(info, intrinsic.data & kIntrinsicFlagBase0);
202    case kIntrinsicCurrentThread:
203      return backend->GenInlinedCurrentThread(info);
204    case kIntrinsicPeek:
205      return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.data));
206    case kIntrinsicPoke:
207      return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.data));
208    case kIntrinsicCas32:
209      return backend->GenInlinedCas32(info, intrinsic.data & kIntrinsicFlagNeedWriteBarrier);
210    case kIntrinsicUnsafeGet:
211      return backend->GenInlinedUnsafeGet(info, intrinsic.data & kIntrinsicFlagIsLong,
212                                          intrinsic.data & kIntrinsicFlagIsVolatile);
213    case kIntrinsicUnsafePut:
214      return backend->GenInlinedUnsafePut(info, intrinsic.data & kIntrinsicFlagIsLong,
215                                          intrinsic.data & kIntrinsicFlagIsObject,
216                                          intrinsic.data & kIntrinsicFlagIsVolatile,
217                                          intrinsic.data & kIntrinsicFlagIsOrdered);
218    default:
219      LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
220      return false;  // avoid warning "control reaches end of non-void function"
221  }
222}
223
224uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache,
225                                              ClassCacheIndex index) {
226  uint32_t* class_index = &cache->class_indexes[index];
227  if (*class_index != kIndexUnresolved) {
228    return *class_index;
229  }
230
231  const DexFile::StringId* string_id = dex_file->FindStringId(kClassCacheNames[index]);
232  if (string_id == nullptr) {
233    *class_index = kIndexNotFound;
234    return *class_index;
235  }
236  uint32_t string_index = dex_file->GetIndexForStringId(*string_id);
237
238  const DexFile::TypeId* type_id = dex_file->FindTypeId(string_index);
239  if (type_id == nullptr) {
240    *class_index = kIndexNotFound;
241    return *class_index;
242  }
243  *class_index = dex_file->GetIndexForTypeId(*type_id);
244  return *class_index;
245}
246
247uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache,
248                                             NameCacheIndex index) {
249  uint32_t* name_index = &cache->name_indexes[index];
250  if (*name_index != kIndexUnresolved) {
251    return *name_index;
252  }
253
254  const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]);
255  if (string_id == nullptr) {
256    *name_index = kIndexNotFound;
257    return *name_index;
258  }
259  *name_index = dex_file->GetIndexForStringId(*string_id);
260  return *name_index;
261}
262
263uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
264                                              ProtoCacheIndex index) {
265  uint32_t* proto_index = &cache->proto_indexes[index];
266  if (*proto_index != kIndexUnresolved) {
267    return *proto_index;
268  }
269
270  const ProtoDef& proto_def = kProtoCacheDefs[index];
271  uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type);
272  if (return_index == kIndexNotFound) {
273    *proto_index = kIndexNotFound;
274    return *proto_index;
275  }
276  uint16_t return_type = static_cast<uint16_t>(return_index);
277  DCHECK_EQ(static_cast<uint32_t>(return_type), return_index);
278
279  uint32_t signature_length = proto_def.param_count;
280  uint16_t signature_type_idxs[kProtoMaxParams];
281  for (uint32_t i = 0; i != signature_length; ++i) {
282    uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]);
283    if (param_index == kIndexNotFound) {
284      *proto_index = kIndexNotFound;
285      return *proto_index;
286    }
287    signature_type_idxs[i] = static_cast<uint16_t>(param_index);
288    DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index);
289  }
290
291  const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs,
292                                                           signature_length);
293  if (proto_id == nullptr) {
294    *proto_index = kIndexNotFound;
295    return *proto_index;
296  }
297  *proto_index = dex_file->GetIndexForProtoId(*proto_id);
298  return *proto_index;
299}
300
301uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
302                                               const MethodDef& method_def) {
303  uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class);
304  if (declaring_class_index == kIndexNotFound) {
305    return kIndexNotFound;
306  }
307  uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name);
308  if (name_index == kIndexNotFound) {
309    return kIndexNotFound;
310  }
311  uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto);
312  if (proto_index == kIndexNotFound) {
313    return kIndexNotFound;
314  }
315  const DexFile::MethodId* method_id =
316      dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index),
317                             dex_file->GetStringId(name_index),
318                             dex_file->GetProtoId(proto_index));
319  if (method_id == nullptr) {
320    return kIndexNotFound;
321  }
322  return dex_file->GetIndexForMethodId(*method_id);
323}
324
325DexFileMethodInliner::IndexCache::IndexCache() {
326  std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved);
327  std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved);
328  std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
329}
330
331void DexFileMethodInliner::DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache,
332                                            const IntrinsicDef* defs, uint32_t def_count) {
333  DCHECK(dex_file != nullptr);
334  DCHECK(dex_file_ == nullptr);
335  for (uint32_t i = 0u; i != def_count; ++i) {
336    uint32_t method_id = FindMethodIndex(dex_file, cache, defs[i].method_def);
337    if (method_id != kIndexNotFound) {
338      DCHECK(intrinsics_.find(method_id) == intrinsics_.end());
339      intrinsics_[method_id] = defs[i].intrinsic;
340    }
341  }
342  dex_file_ = dex_file;
343}
344
345}  // namespace art
346