dex_file_method_inliner.cc revision 3bc01748ef1c3e43361bdf520947a9d656658bf8
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 "locks.h"
22#include "thread.h"
23#include "thread-inl.h"
24#include "dex/mir_graph.h"
25#include "dex_instruction.h"
26#include "dex_instruction-inl.h"
27#include "verifier/method_verifier.h"
28#include "verifier/method_verifier-inl.h"
29
30#include "dex_file_method_inliner.h"
31
32namespace art {
33
34namespace {  // anonymous namespace
35
36constexpr uint8_t kIGetIPutOpSizes[] = {
37    kWord,          // IGET, IPUT
38    kLong,          // IGET_WIDE, IPUT_WIDE
39    kWord,          // IGET_OBJECT, IPUT_OBJECT
40    kSignedByte,    // IGET_BOOLEAN, IPUT_BOOLEAN
41    kSignedByte,    // IGET_BYTE, IPUT_BYTE
42    kUnsignedHalf,  // IGET_CHAR, IPUT_CHAR
43    kSignedHalf,    // IGET_SHORT, IPUT_SHORT
44};
45
46}  // anonymous namespace
47
48const uint32_t DexFileMethodInliner::kIndexUnresolved;
49const char* const DexFileMethodInliner::kClassCacheNames[] = {
50    "Z",                       // kClassCacheBoolean
51    "B",                       // kClassCacheByte
52    "C",                       // kClassCacheChar
53    "S",                       // kClassCacheShort
54    "I",                       // kClassCacheInt
55    "J",                       // kClassCacheLong
56    "F",                       // kClassCacheFloat
57    "D",                       // kClassCacheDouble
58    "V",                       // kClassCacheVoid
59    "Ljava/lang/Object;",      // kClassCacheJavaLangObject
60    "Ljava/lang/String;",      // kClassCacheJavaLangString
61    "Ljava/lang/Double;",      // kClassCacheJavaLangDouble
62    "Ljava/lang/Float;",       // kClassCacheJavaLangFloat
63    "Ljava/lang/Integer;",     // kClassCacheJavaLangInteger
64    "Ljava/lang/Long;",        // kClassCacheJavaLangLong
65    "Ljava/lang/Short;",       // kClassCacheJavaLangShort
66    "Ljava/lang/Math;",        // kClassCacheJavaLangMath
67    "Ljava/lang/StrictMath;",  // kClassCacheJavaLangStrictMath
68    "Ljava/lang/Thread;",      // kClassCacheJavaLangThread
69    "Llibcore/io/Memory;",     // kClassCacheLibcoreIoMemory
70    "Lsun/misc/Unsafe;",       // kClassCacheSunMiscUnsafe
71};
72
73const char* const DexFileMethodInliner::kNameCacheNames[] = {
74    "reverseBytes",          // kNameCacheReverseBytes
75    "doubleToRawLongBits",   // kNameCacheDoubleToRawLongBits
76    "longBitsToDouble",      // kNameCacheLongBitsToDouble
77    "floatToRawIntBits",     // kNameCacheFloatToRawIntBits
78    "intBitsToFloat",        // kNameCacheIntBitsToFloat
79    "abs",                   // kNameCacheAbs
80    "max",                   // kNameCacheMax
81    "min",                   // kNameCacheMin
82    "sqrt",                  // kNameCacheSqrt
83    "charAt",                // kNameCacheCharAt
84    "compareTo",             // kNameCacheCompareTo
85    "isEmpty",               // kNameCacheIsEmpty
86    "indexOf",               // kNameCacheIndexOf
87    "length",                // kNameCacheLength
88    "currentThread",         // kNameCacheCurrentThread
89    "peekByte",              // kNameCachePeekByte
90    "peekIntNative",         // kNameCachePeekIntNative
91    "peekLongNative",        // kNameCachePeekLongNative
92    "peekShortNative",       // kNameCachePeekShortNative
93    "pokeByte",              // kNameCachePokeByte
94    "pokeIntNative",         // kNameCachePokeIntNative
95    "pokeLongNative",        // kNameCachePokeLongNative
96    "pokeShortNative",       // kNameCachePokeShortNative
97    "compareAndSwapInt",     // kNameCacheCompareAndSwapInt
98    "compareAndSwapLong",    // kNameCacheCompareAndSwapLong
99    "compareAndSwapObject",  // kNameCacheCompareAndSwapObject
100    "getInt",                // kNameCacheGetInt
101    "getIntVolatile",        // kNameCacheGetIntVolatile
102    "putInt",                // kNameCachePutInt
103    "putIntVolatile",        // kNameCachePutIntVolatile
104    "putOrderedInt",         // kNameCachePutOrderedInt
105    "getLong",               // kNameCacheGetLong
106    "getLongVolatile",       // kNameCacheGetLongVolatile
107    "putLong",               // kNameCachePutLong
108    "putLongVolatile",       // kNameCachePutLongVolatile
109    "putOrderedLong",        // kNameCachePutOrderedLong
110    "getObject",             // kNameCacheGetObject
111    "getObjectVolatile",     // kNameCacheGetObjectVolatile
112    "putObject",             // kNameCachePutObject
113    "putObjectVolatile",     // kNameCachePutObjectVolatile
114    "putOrderedObject",      // kNameCachePutOrderedObject
115};
116
117const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
118    // kProtoCacheI_I
119    { kClassCacheInt, 1, { kClassCacheInt } },
120    // kProtoCacheJ_J
121    { kClassCacheLong, 1, { kClassCacheLong } },
122    // kProtoCacheS_S
123    { kClassCacheShort, 1, { kClassCacheShort } },
124    // kProtoCacheD_D
125    { kClassCacheDouble, 1, { kClassCacheDouble } },
126    // kProtoCacheF_F
127    { kClassCacheFloat, 1, { kClassCacheFloat } },
128    // kProtoCacheD_J
129    { kClassCacheLong, 1, { kClassCacheDouble } },
130    // kProtoCacheJ_D
131    { kClassCacheDouble, 1, { kClassCacheLong } },
132    // kProtoCacheF_I
133    { kClassCacheInt, 1, { kClassCacheFloat } },
134    // kProtoCacheI_F
135    { kClassCacheFloat, 1, { kClassCacheInt } },
136    // kProtoCacheII_I
137    { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } },
138    // kProtoCacheI_C
139    { kClassCacheChar, 1, { kClassCacheInt } },
140    // kProtoCacheString_I
141    { kClassCacheInt, 1, { kClassCacheJavaLangString } },
142    // kProtoCache_Z
143    { kClassCacheBoolean, 0, { } },
144    // kProtoCache_I
145    { kClassCacheInt, 0, { } },
146    // kProtoCache_Thread
147    { kClassCacheJavaLangThread, 0, { } },
148    // kProtoCacheJ_B
149    { kClassCacheByte, 1, { kClassCacheLong } },
150    // kProtoCacheJ_I
151    { kClassCacheInt, 1, { kClassCacheLong } },
152    // kProtoCacheJ_S
153    { kClassCacheShort, 1, { kClassCacheLong } },
154    // kProtoCacheJB_V
155    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } },
156    // kProtoCacheJI_V
157    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
158    // kProtoCacheJJ_V
159    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
160    // kProtoCacheJS_V
161    { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } },
162    // kProtoCacheObjectJII_Z
163    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
164        kClassCacheInt, kClassCacheInt } },
165    // kProtoCacheObjectJJJ_Z
166    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
167        kClassCacheLong, kClassCacheLong } },
168    // kProtoCacheObjectJObjectObject_Z
169    { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
170        kClassCacheJavaLangObject, kClassCacheJavaLangObject } },
171    // kProtoCacheObjectJ_I
172    { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
173    // kProtoCacheObjectJI_V
174    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
175    // kProtoCacheObjectJ_J
176    { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
177    // kProtoCacheObjectJJ_V
178    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
179    // kProtoCacheObjectJ_Object
180    { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
181    // kProtoCacheObjectJObject_V
182    { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong,
183        kClassCacheJavaLangObject } },
184};
185
186const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
187#define INTRINSIC(c, n, p, o, d) \
188    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } }
189
190    INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
191    INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
192    INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
193    INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
194
195    INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
196    INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
197    INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
198
199    INTRINSIC(JavaLangMath,       Abs, I_I, kIntrinsicAbsInt, 0),
200    INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
201    INTRINSIC(JavaLangMath,       Abs, J_J, kIntrinsicAbsLong, 0),
202    INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
203    INTRINSIC(JavaLangMath,       Abs, F_F, kIntrinsicAbsFloat, 0),
204    INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0),
205    INTRINSIC(JavaLangMath,       Abs, D_D, kIntrinsicAbsDouble, 0),
206    INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0),
207    INTRINSIC(JavaLangMath,       Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
208    INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
209    INTRINSIC(JavaLangMath,       Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
210    INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
211    INTRINSIC(JavaLangMath,       Sqrt, D_D, kIntrinsicSqrt, 0),
212    INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
213
214    INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
215    INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
216    INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
217    INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
218    INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
219    INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
220
221    INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
222
223    INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
224    INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
225    INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
226    INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
227    INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
228    INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
229    INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
230    INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
231
232    INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
233              kIntrinsicFlagNone),
234    INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
235              kIntrinsicFlagIsLong),
236    INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
237              kIntrinsicFlagIsObject),
238
239#define UNSAFE_GET_PUT(type, code, type_flags) \
240    INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
241              type_flags & ~kIntrinsicFlagIsObject), \
242    INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
243              (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
244    INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
245              type_flags), \
246    INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
247              type_flags | kIntrinsicFlagIsVolatile), \
248    INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
249              type_flags | kIntrinsicFlagIsOrdered)
250
251    UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
252    UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
253    UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
254#undef UNSAFE_GET_PUT
255
256#undef INTRINSIC
257};
258
259DexFileMethodInliner::DexFileMethodInliner()
260    : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock),
261      dex_file_(NULL) {
262  COMPILE_ASSERT(kClassCacheFirst == 0, kClassCacheFirst_not_0);
263  COMPILE_ASSERT(arraysize(kClassCacheNames) == kClassCacheLast, bad_arraysize_kClassCacheNames);
264  COMPILE_ASSERT(kNameCacheFirst == 0, kNameCacheFirst_not_0);
265  COMPILE_ASSERT(arraysize(kNameCacheNames) == kNameCacheLast, bad_arraysize_kNameCacheNames);
266  COMPILE_ASSERT(kProtoCacheFirst == 0, kProtoCacheFirst_not_0);
267  COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames);
268}
269
270DexFileMethodInliner::~DexFileMethodInliner() {
271}
272
273bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
274  // We currently support only plain return or 2-instruction methods.
275
276  const DexFile::CodeItem* code_item = verifier->CodeItem();
277  DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
278  const Instruction* instruction = Instruction::At(code_item->insns_);
279  Instruction::Code opcode = instruction->Opcode();
280
281  InlineMethod method;
282  bool success;
283  switch (opcode) {
284    case Instruction::RETURN_VOID:
285      method.opcode = kInlineOpNop;
286      method.flags = kInlineSpecial;
287      method.d.data = 0u;
288      success = true;
289      break;
290    case Instruction::RETURN:
291    case Instruction::RETURN_OBJECT:
292    case Instruction::RETURN_WIDE:
293      success = AnalyseReturnMethod(code_item, &method);
294      break;
295    case Instruction::CONST:
296    case Instruction::CONST_4:
297    case Instruction::CONST_16:
298    case Instruction::CONST_HIGH16:
299      // TODO: Support wide constants (RETURN_WIDE).
300      success = AnalyseConstMethod(code_item, &method);
301      break;
302    case Instruction::IGET:
303    case Instruction::IGET_OBJECT:
304    case Instruction::IGET_BOOLEAN:
305    case Instruction::IGET_BYTE:
306    case Instruction::IGET_CHAR:
307    case Instruction::IGET_SHORT:
308    case Instruction::IGET_WIDE:
309      success = AnalyseIGetMethod(verifier, &method);
310      break;
311    case Instruction::IPUT:
312    case Instruction::IPUT_OBJECT:
313    case Instruction::IPUT_BOOLEAN:
314    case Instruction::IPUT_BYTE:
315    case Instruction::IPUT_CHAR:
316    case Instruction::IPUT_SHORT:
317    case Instruction::IPUT_WIDE:
318      success = AnalyseIPutMethod(verifier, &method);
319      break;
320    default:
321      success = false;
322      break;
323  }
324  return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
325}
326
327bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
328  ReaderMutexLock mu(Thread::Current(), lock_);
329  auto it = inline_methods_.find(method_index);
330  return it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0;
331}
332
333bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
334  InlineMethod intrinsic;
335  {
336    ReaderMutexLock mu(Thread::Current(), lock_);
337    auto it = inline_methods_.find(info->index);
338    if (it == inline_methods_.end() || (it->second.flags & kInlineIntrinsic) == 0) {
339      return false;
340    }
341    intrinsic = it->second;
342  }
343  switch (intrinsic.opcode) {
344    case kIntrinsicDoubleCvt:
345      return backend->GenInlinedDoubleCvt(info);
346    case kIntrinsicFloatCvt:
347      return backend->GenInlinedFloatCvt(info);
348    case kIntrinsicReverseBytes:
349      return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data));
350    case kIntrinsicAbsInt:
351      return backend->GenInlinedAbsInt(info);
352    case kIntrinsicAbsLong:
353      return backend->GenInlinedAbsLong(info);
354    case kIntrinsicAbsFloat:
355      return backend->GenInlinedAbsFloat(info);
356    case kIntrinsicAbsDouble:
357      return backend->GenInlinedAbsDouble(info);
358    case kIntrinsicMinMaxInt:
359      return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin);
360    case kIntrinsicSqrt:
361      return backend->GenInlinedSqrt(info);
362    case kIntrinsicCharAt:
363      return backend->GenInlinedCharAt(info);
364    case kIntrinsicCompareTo:
365      return backend->GenInlinedStringCompareTo(info);
366    case kIntrinsicIsEmptyOrLength:
367      return backend->GenInlinedStringIsEmptyOrLength(
368          info, intrinsic.d.data & kIntrinsicFlagIsEmpty);
369    case kIntrinsicIndexOf:
370      return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0);
371    case kIntrinsicCurrentThread:
372      return backend->GenInlinedCurrentThread(info);
373    case kIntrinsicPeek:
374      return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data));
375    case kIntrinsicPoke:
376      return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data));
377    case kIntrinsicCas:
378      return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong,
379                                    intrinsic.d.data & kIntrinsicFlagIsObject);
380    case kIntrinsicUnsafeGet:
381      return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong,
382                                          intrinsic.d.data & kIntrinsicFlagIsVolatile);
383    case kIntrinsicUnsafePut:
384      return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong,
385                                          intrinsic.d.data & kIntrinsicFlagIsObject,
386                                          intrinsic.d.data & kIntrinsicFlagIsVolatile,
387                                          intrinsic.d.data & kIntrinsicFlagIsOrdered);
388    default:
389      LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
390      return false;  // avoid warning "control reaches end of non-void function"
391  }
392}
393
394bool DexFileMethodInliner::IsSpecial(uint32_t method_index) {
395  ReaderMutexLock mu(Thread::Current(), lock_);
396  auto it = inline_methods_.find(method_index);
397  return it != inline_methods_.end() && (it->second.flags & kInlineSpecial) != 0;
398}
399
400bool DexFileMethodInliner::GenSpecial(Mir2Lir* backend, uint32_t method_idx) {
401  InlineMethod special;
402  {
403    ReaderMutexLock mu(Thread::Current(), lock_);
404    auto it = inline_methods_.find(method_idx);
405    if (it == inline_methods_.end() || (it->second.flags & kInlineSpecial) == 0) {
406      return false;
407    }
408    special = it->second;
409  }
410  return backend->SpecialMIR2LIR(special);
411}
412
413uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache,
414                                              ClassCacheIndex index) {
415  uint32_t* class_index = &cache->class_indexes[index];
416  if (*class_index != kIndexUnresolved) {
417    return *class_index;
418  }
419
420  const DexFile::StringId* string_id = dex_file->FindStringId(kClassCacheNames[index]);
421  if (string_id == nullptr) {
422    *class_index = kIndexNotFound;
423    return *class_index;
424  }
425  uint32_t string_index = dex_file->GetIndexForStringId(*string_id);
426
427  const DexFile::TypeId* type_id = dex_file->FindTypeId(string_index);
428  if (type_id == nullptr) {
429    *class_index = kIndexNotFound;
430    return *class_index;
431  }
432  *class_index = dex_file->GetIndexForTypeId(*type_id);
433  return *class_index;
434}
435
436uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache,
437                                             NameCacheIndex index) {
438  uint32_t* name_index = &cache->name_indexes[index];
439  if (*name_index != kIndexUnresolved) {
440    return *name_index;
441  }
442
443  const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]);
444  if (string_id == nullptr) {
445    *name_index = kIndexNotFound;
446    return *name_index;
447  }
448  *name_index = dex_file->GetIndexForStringId(*string_id);
449  return *name_index;
450}
451
452uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
453                                              ProtoCacheIndex index) {
454  uint32_t* proto_index = &cache->proto_indexes[index];
455  if (*proto_index != kIndexUnresolved) {
456    return *proto_index;
457  }
458
459  const ProtoDef& proto_def = kProtoCacheDefs[index];
460  uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type);
461  if (return_index == kIndexNotFound) {
462    *proto_index = kIndexNotFound;
463    return *proto_index;
464  }
465  uint16_t return_type = static_cast<uint16_t>(return_index);
466  DCHECK_EQ(static_cast<uint32_t>(return_type), return_index);
467
468  uint32_t signature_length = proto_def.param_count;
469  uint16_t signature_type_idxs[kProtoMaxParams];
470  for (uint32_t i = 0; i != signature_length; ++i) {
471    uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]);
472    if (param_index == kIndexNotFound) {
473      *proto_index = kIndexNotFound;
474      return *proto_index;
475    }
476    signature_type_idxs[i] = static_cast<uint16_t>(param_index);
477    DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index);
478  }
479
480  const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs,
481                                                           signature_length);
482  if (proto_id == nullptr) {
483    *proto_index = kIndexNotFound;
484    return *proto_index;
485  }
486  *proto_index = dex_file->GetIndexForProtoId(*proto_id);
487  return *proto_index;
488}
489
490uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
491                                               const MethodDef& method_def) {
492  uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class);
493  if (declaring_class_index == kIndexNotFound) {
494    return kIndexNotFound;
495  }
496  uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name);
497  if (name_index == kIndexNotFound) {
498    return kIndexNotFound;
499  }
500  uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto);
501  if (proto_index == kIndexNotFound) {
502    return kIndexNotFound;
503  }
504  const DexFile::MethodId* method_id =
505      dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index),
506                             dex_file->GetStringId(name_index),
507                             dex_file->GetProtoId(proto_index));
508  if (method_id == nullptr) {
509    return kIndexNotFound;
510  }
511  return dex_file->GetIndexForMethodId(*method_id);
512}
513
514DexFileMethodInliner::IndexCache::IndexCache() {
515  std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved);
516  std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved);
517  std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
518}
519
520void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
521  DCHECK(dex_file != nullptr);
522  DCHECK(dex_file_ == nullptr);
523  IndexCache cache;
524  for (const IntrinsicDef& def : kIntrinsicMethods) {
525    uint32_t method_idx = FindMethodIndex(dex_file, &cache, def.method_def);
526    if (method_idx != kIndexNotFound) {
527      DCHECK(inline_methods_.find(method_idx) == inline_methods_.end());
528      inline_methods_.Put(method_idx, def.intrinsic);
529    }
530  }
531  dex_file_ = dex_file;
532}
533
534bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) {
535  WriterMutexLock mu(Thread::Current(), lock_);
536  if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) {
537    inline_methods_.Put(method_idx, method);
538    return true;
539  } else {
540    if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") {
541      // TODO: String.length is both kIntrinsicIsEmptyOrLength and kInlineOpIGet.
542    } else {
543      LOG(ERROR) << "Inliner: " << PrettyMethod(method_idx, *dex_file_) << " already inline";
544    }
545    return false;
546  }
547}
548
549bool DexFileMethodInliner::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
550                                               InlineMethod* result) {
551  const Instruction* return_instruction = Instruction::At(code_item->insns_);
552  Instruction::Code return_opcode = return_instruction->Opcode();
553  uint16_t size = (return_opcode == Instruction::RETURN_WIDE) ? kLong : kWord;
554  uint16_t is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u;
555  uint32_t reg = return_instruction->VRegA_11x();
556  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
557  DCHECK_GE(reg, arg_start);
558  DCHECK_LT(size == kLong ? reg + 1 : reg, code_item->registers_size_);
559
560  result->opcode = kInlineOpReturnArg;
561  result->flags = kInlineSpecial;
562  InlineReturnArgData* data = &result->d.return_data;
563  data->arg = reg - arg_start;
564  data->op_size = size;
565  data->is_object = is_object;
566  data->reserved = 0u;
567  data->reserved2 = 0u;
568  return true;
569}
570
571bool DexFileMethodInliner::AnalyseConstMethod(const DexFile::CodeItem* code_item,
572                                              InlineMethod* result) {
573  const Instruction* instruction = Instruction::At(code_item->insns_);
574  const Instruction* return_instruction = instruction->Next();
575  Instruction::Code return_opcode = return_instruction->Opcode();
576  if (return_opcode != Instruction::RETURN &&
577      return_opcode != Instruction::RETURN_OBJECT) {
578    return false;
579  }
580
581  uint32_t return_reg = return_instruction->VRegA_11x();
582  DCHECK_LT(return_reg, code_item->registers_size_);
583
584  uint32_t vA, vB, dummy;
585  uint64_t dummy_wide;
586  instruction->Decode(vA, vB, dummy_wide, dummy, nullptr);
587  if (instruction->Opcode() == Instruction::CONST_HIGH16) {
588    vB <<= 16;
589  }
590  DCHECK_LT(vA, code_item->registers_size_);
591  if (vA != return_reg) {
592    return false;  // Not returning the value set by const?
593  }
594  if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
595    return false;  // Returning non-null reference constant?
596  }
597  result->opcode = kInlineOpNonWideConst;
598  result->flags = kInlineSpecial;
599  result->d.data = static_cast<uint64_t>(vB);
600  return true;
601}
602
603bool DexFileMethodInliner::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
604                                             InlineMethod* result) {
605  const DexFile::CodeItem* code_item = verifier->CodeItem();
606  const Instruction* instruction = Instruction::At(code_item->insns_);
607  Instruction::Code opcode = instruction->Opcode();
608  DCHECK_LT(static_cast<size_t>(opcode - Instruction::IGET), arraysize(kIGetIPutOpSizes));
609  uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IGET];
610
611  const Instruction* return_instruction = instruction->Next();
612  Instruction::Code return_opcode = return_instruction->Opcode();
613  if (!(return_opcode == Instruction::RETURN && size != kLong) &&
614      !(return_opcode == Instruction::RETURN_WIDE && size == kLong) &&
615      !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT)) {
616    return false;
617  }
618
619  uint32_t return_reg = return_instruction->VRegA_11x();
620  DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
621            code_item->registers_size_);
622
623  uint32_t dst_reg = instruction->VRegA_22c();
624  uint32_t object_reg = instruction->VRegB_22c();
625  uint32_t field_idx = instruction->VRegC_22c();
626  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
627  DCHECK_GE(object_reg, arg_start);
628  DCHECK_LT(object_reg, code_item->registers_size_);
629  DCHECK_LT(size == kLong ? dst_reg + 1 : dst_reg, code_item->registers_size_);
630  if (dst_reg != return_reg) {
631    return false;  // Not returning the value retrieved by IGET?
632  }
633
634  if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, false, verifier,
635                                                  &result->d.ifield_data)) {
636    return false;
637  }
638
639  result->opcode = kInlineOpIGet;
640  result->flags = kInlineSpecial;
641  InlineIGetIPutData* data = &result->d.ifield_data;
642  data->op_size = size;
643  data->is_object = (opcode == Instruction::IGET_OBJECT) ? 1u : 0u;
644  data->object_arg = object_reg - arg_start;  // Allow IGET on any register, not just "this".
645  data->src_arg = 0;
646  data->reserved = 0;
647  return true;
648}
649
650bool DexFileMethodInliner::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
651                                             InlineMethod* result) {
652  const DexFile::CodeItem* code_item = verifier->CodeItem();
653  const Instruction* instruction = Instruction::At(code_item->insns_);
654  Instruction::Code opcode = instruction->Opcode();
655  DCHECK_LT(static_cast<size_t>(opcode - Instruction::IPUT), arraysize(kIGetIPutOpSizes));
656  uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IPUT];
657
658  const Instruction* return_instruction = instruction->Next();
659  if (return_instruction->Opcode() != Instruction::RETURN_VOID) {
660    // TODO: Support returning an argument.
661    // This is needed by builder classes and generated accessor setters.
662    //    builder.setX(value): iput value, this, fieldX; return-object this;
663    //    object.access$nnn(value): iput value, this, fieldX; return value;
664    // Use InlineIGetIPutData::reserved to hold the information.
665    return false;
666  }
667
668  uint32_t src_reg = instruction->VRegA_22c();
669  uint32_t object_reg = instruction->VRegB_22c();
670  uint32_t field_idx = instruction->VRegC_22c();
671  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
672  DCHECK_GE(object_reg, arg_start);
673  DCHECK_LT(object_reg, code_item->registers_size_);
674  DCHECK_GE(src_reg, arg_start);
675  DCHECK_LT(size == kLong ? src_reg + 1 : src_reg, code_item->registers_size_);
676
677  if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, true, verifier,
678                                                  &result->d.ifield_data)) {
679    return false;
680  }
681
682  result->opcode = kInlineOpIPut;
683  result->flags = kInlineSpecial;
684  InlineIGetIPutData* data = &result->d.ifield_data;
685  data->op_size = size;
686  data->is_object = (opcode == Instruction::IPUT_OBJECT) ? 1u : 0u;
687  data->object_arg = object_reg - arg_start;  // Allow IPUT on any register, not just "this".
688  data->src_arg = src_reg - arg_start;
689  data->reserved = 0;
690  return true;
691}
692
693}  // namespace art
694