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