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