reg_type_cache.cc revision 7da9586b559290e1c16207c6513ffe485de61655
1/* 2 * Copyright (C) 2012 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 "reg_type_cache-inl.h" 18 19#include "base/casts.h" 20#include "class_linker-inl.h" 21#include "dex_file-inl.h" 22#include "mirror/class-inl.h" 23#include "mirror/object-inl.h" 24 25namespace art { 26namespace verifier { 27 28bool RegTypeCache::primitive_initialized_ = false; 29uint16_t RegTypeCache::primitive_count_ = 0; 30PreciseConstType* RegTypeCache::small_precise_constants_[kMaxSmallConstant - kMinSmallConstant + 1]; 31 32static bool MatchingPrecisionForClass(RegType* entry, bool precise) 33 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 34 if (entry->IsPreciseReference() == precise) { 35 // We were or weren't looking for a precise reference and we found what we need. 36 return true; 37 } else { 38 if (!precise && entry->GetClass()->CannotBeAssignedFromOtherTypes()) { 39 // We weren't looking for a precise reference, as we're looking up based on a descriptor, but 40 // we found a matching entry based on the descriptor. Return the precise entry in that case. 41 return true; 42 } 43 return false; 44 } 45} 46 47void RegTypeCache::FillPrimitiveAndSmallConstantTypes() { 48 entries_.push_back(UndefinedType::GetInstance()); 49 entries_.push_back(ConflictType::GetInstance()); 50 entries_.push_back(BooleanType::GetInstance()); 51 entries_.push_back(ByteType::GetInstance()); 52 entries_.push_back(ShortType::GetInstance()); 53 entries_.push_back(CharType::GetInstance()); 54 entries_.push_back(IntegerType::GetInstance()); 55 entries_.push_back(LongLoType::GetInstance()); 56 entries_.push_back(LongHiType::GetInstance()); 57 entries_.push_back(FloatType::GetInstance()); 58 entries_.push_back(DoubleLoType::GetInstance()); 59 entries_.push_back(DoubleHiType::GetInstance()); 60 for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) { 61 int32_t i = value - kMinSmallConstant; 62 DCHECK_EQ(entries_.size(), small_precise_constants_[i]->GetId()); 63 entries_.push_back(small_precise_constants_[i]); 64 } 65 DCHECK_EQ(entries_.size(), primitive_count_); 66} 67 68RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, 69 bool precise) { 70 DCHECK(RegTypeCache::primitive_initialized_); 71 if (descriptor[1] == '\0') { 72 switch (descriptor[0]) { 73 case 'Z': 74 return Boolean(); 75 case 'B': 76 return Byte(); 77 case 'S': 78 return Short(); 79 case 'C': 80 return Char(); 81 case 'I': 82 return Integer(); 83 case 'J': 84 return LongLo(); 85 case 'F': 86 return Float(); 87 case 'D': 88 return DoubleLo(); 89 case 'V': // For void types, conflict types. 90 default: 91 return Conflict(); 92 } 93 } else if (descriptor[0] == 'L' || descriptor[0] == '[') { 94 return From(loader, descriptor, precise); 95 } else { 96 return Conflict(); 97 } 98}; 99 100RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const { 101 CHECK(RegTypeCache::primitive_initialized_); 102 switch (prim_type) { 103 case Primitive::kPrimBoolean: 104 return *BooleanType::GetInstance(); 105 case Primitive::kPrimByte: 106 return *ByteType::GetInstance(); 107 case Primitive::kPrimShort: 108 return *ShortType::GetInstance(); 109 case Primitive::kPrimChar: 110 return *CharType::GetInstance(); 111 case Primitive::kPrimInt: 112 return *IntegerType::GetInstance(); 113 case Primitive::kPrimLong: 114 return *LongLoType::GetInstance(); 115 case Primitive::kPrimFloat: 116 return *FloatType::GetInstance(); 117 case Primitive::kPrimDouble: 118 return *DoubleLoType::GetInstance(); 119 case Primitive::kPrimVoid: 120 default: 121 return *ConflictType::GetInstance(); 122 } 123} 124 125bool RegTypeCache::MatchDescriptor(size_t idx, const char* descriptor, bool precise) { 126 RegType* entry = entries_[idx]; 127 if (entry->descriptor_ != descriptor) { 128 return false; 129 } 130 if (entry->HasClass()) { 131 return MatchingPrecisionForClass(entry, precise); 132 } 133 // There is no notion of precise unresolved references, the precise information is just dropped 134 // on the floor. 135 DCHECK(entry->IsUnresolvedReference()); 136 return true; 137} 138 139mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassLoader* loader) { 140 // Class was not found, must create new type. 141 // Try resolving class 142 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 143 Thread* self = Thread::Current(); 144 StackHandleScope<1> hs(self); 145 Handle<mirror::ClassLoader> class_loader(hs.NewHandle(loader)); 146 mirror::Class* klass = NULL; 147 if (can_load_classes_) { 148 klass = class_linker->FindClass(self, descriptor, class_loader); 149 } else { 150 klass = class_linker->LookupClass(descriptor, loader); 151 if (klass != nullptr && !klass->IsLoaded()) { 152 // We found the class but without it being loaded its not safe for use. 153 klass = nullptr; 154 } 155 } 156 return klass; 157} 158 159RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor, 160 bool precise) { 161 // Try looking up the class in the cache first. 162 for (size_t i = primitive_count_; i < entries_.size(); i++) { 163 if (MatchDescriptor(i, descriptor, precise)) { 164 return *(entries_[i]); 165 } 166 } 167 // Class not found in the cache, will create a new type for that. 168 // Try resolving class. 169 mirror::Class* klass = ResolveClass(descriptor, loader); 170 if (klass != NULL) { 171 // Class resolved, first look for the class in the list of entries 172 // Class was not found, must create new type. 173 // To pass the verification, the type should be imprecise, 174 // instantiable or an interface with the precise type set to false. 175 DCHECK(!precise || klass->IsInstantiable()); 176 // Create a precise type if: 177 // 1- Class is final and NOT an interface. a precise interface is meaningless !! 178 // 2- Precise Flag passed as true. 179 RegType* entry; 180 // Create an imprecise type if we can't tell for a fact that it is precise. 181 if (klass->CannotBeAssignedFromOtherTypes() || precise) { 182 DCHECK(!(klass->IsAbstract()) || klass->IsArrayClass()); 183 DCHECK(!klass->IsInterface()); 184 entry = new PreciseReferenceType(klass, descriptor, entries_.size()); 185 } else { 186 entry = new ReferenceType(klass, descriptor, entries_.size()); 187 } 188 AddEntry(entry); 189 return *entry; 190 } else { // Class not resolved. 191 // We tried loading the class and failed, this might get an exception raised 192 // so we want to clear it before we go on. 193 if (can_load_classes_) { 194 DCHECK(Thread::Current()->IsExceptionPending()); 195 Thread::Current()->ClearException(); 196 } else { 197 DCHECK(!Thread::Current()->IsExceptionPending()); 198 } 199 if (IsValidDescriptor(descriptor)) { 200 RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size()); 201 AddEntry(entry); 202 return *entry; 203 } else { 204 // The descriptor is broken return the unknown type as there's nothing sensible that 205 // could be done at runtime 206 return Conflict(); 207 } 208 } 209} 210 211RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) { 212 DCHECK(klass != nullptr && !klass->IsErroneous()); 213 if (klass->IsPrimitive()) { 214 // Note: precise isn't used for primitive classes. A char is assignable to an int. All 215 // primitive classes are final. 216 return RegTypeFromPrimitiveType(klass->GetPrimitiveType()); 217 } else { 218 // Look for the reference in the list of entries to have. 219 for (size_t i = primitive_count_; i < entries_.size(); i++) { 220 RegType* cur_entry = entries_[i]; 221 if (cur_entry->klass_.Read() == klass && MatchingPrecisionForClass(cur_entry, precise)) { 222 return *cur_entry; 223 } 224 } 225 // No reference to the class was found, create new reference. 226 RegType* entry; 227 if (precise) { 228 entry = new PreciseReferenceType(klass, descriptor, entries_.size()); 229 } else { 230 entry = new ReferenceType(klass, descriptor, entries_.size()); 231 } 232 AddEntry(entry); 233 return *entry; 234 } 235} 236 237RegTypeCache::RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) { 238 if (kIsDebugBuild && can_load_classes) { 239 Thread::Current()->AssertThreadSuspensionIsAllowable(); 240 } 241 entries_.reserve(64); 242 FillPrimitiveAndSmallConstantTypes(); 243} 244 245RegTypeCache::~RegTypeCache() { 246 CHECK_LE(primitive_count_, entries_.size()); 247 // Delete only the non primitive types. 248 if (entries_.size() == kNumPrimitivesAndSmallConstants) { 249 // All entries are from the global pool, nothing to delete. 250 return; 251 } 252 std::vector<RegType*>::iterator non_primitive_begin = entries_.begin(); 253 std::advance(non_primitive_begin, kNumPrimitivesAndSmallConstants); 254 STLDeleteContainerPointers(non_primitive_begin, entries_.end()); 255} 256 257void RegTypeCache::ShutDown() { 258 if (RegTypeCache::primitive_initialized_) { 259 UndefinedType::Destroy(); 260 ConflictType::Destroy(); 261 BooleanType::Destroy(); 262 ByteType::Destroy(); 263 ShortType::Destroy(); 264 CharType::Destroy(); 265 IntegerType::Destroy(); 266 LongLoType::Destroy(); 267 LongHiType::Destroy(); 268 FloatType::Destroy(); 269 DoubleLoType::Destroy(); 270 DoubleHiType::Destroy(); 271 for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) { 272 PreciseConstType* type = small_precise_constants_[value - kMinSmallConstant]; 273 delete type; 274 small_precise_constants_[value - kMinSmallConstant] = nullptr; 275 } 276 RegTypeCache::primitive_initialized_ = false; 277 RegTypeCache::primitive_count_ = 0; 278 } 279} 280 281template <class Type> 282Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) { 283 mirror::Class* klass = NULL; 284 // Try loading the class from linker. 285 if (!descriptor.empty()) { 286 klass = art::Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), 287 descriptor.c_str()); 288 } 289 Type* entry = Type::CreateInstance(klass, descriptor, RegTypeCache::primitive_count_); 290 RegTypeCache::primitive_count_++; 291 return entry; 292} 293 294void RegTypeCache::CreatePrimitiveAndSmallConstantTypes() { 295 CreatePrimitiveTypeInstance<UndefinedType>(""); 296 CreatePrimitiveTypeInstance<ConflictType>(""); 297 CreatePrimitiveTypeInstance<BooleanType>("Z"); 298 CreatePrimitiveTypeInstance<ByteType>("B"); 299 CreatePrimitiveTypeInstance<ShortType>("S"); 300 CreatePrimitiveTypeInstance<CharType>("C"); 301 CreatePrimitiveTypeInstance<IntegerType>("I"); 302 CreatePrimitiveTypeInstance<LongLoType>("J"); 303 CreatePrimitiveTypeInstance<LongHiType>("J"); 304 CreatePrimitiveTypeInstance<FloatType>("F"); 305 CreatePrimitiveTypeInstance<DoubleLoType>("D"); 306 CreatePrimitiveTypeInstance<DoubleHiType>("D"); 307 for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) { 308 PreciseConstType* type = new PreciseConstType(value, primitive_count_); 309 small_precise_constants_[value - kMinSmallConstant] = type; 310 primitive_count_++; 311 } 312} 313 314RegType& RegTypeCache::FromUnresolvedMerge(RegType& left, RegType& right) { 315 std::set<uint16_t> types; 316 if (left.IsUnresolvedMergedReference()) { 317 types = (down_cast<UnresolvedMergedType*>(&left))->GetMergedTypes(); 318 } else { 319 types.insert(left.GetId()); 320 } 321 if (right.IsUnresolvedMergedReference()) { 322 std::set<uint16_t> right_types = (down_cast<UnresolvedMergedType*>(&right))->GetMergedTypes(); 323 types.insert(right_types.begin(), right_types.end()); 324 } else { 325 types.insert(right.GetId()); 326 } 327 // Check if entry already exists. 328 for (size_t i = primitive_count_; i < entries_.size(); i++) { 329 RegType* cur_entry = entries_[i]; 330 if (cur_entry->IsUnresolvedMergedReference()) { 331 std::set<uint16_t> cur_entry_types = 332 (down_cast<UnresolvedMergedType*>(cur_entry))->GetMergedTypes(); 333 if (cur_entry_types == types) { 334 return *cur_entry; 335 } 336 } 337 } 338 // Create entry. 339 RegType* entry = new UnresolvedMergedType(left.GetId(), right.GetId(), this, entries_.size()); 340 AddEntry(entry); 341 if (kIsDebugBuild) { 342 UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry); 343 std::set<uint16_t> check_types = tmp_entry->GetMergedTypes(); 344 CHECK(check_types == types); 345 } 346 return *entry; 347} 348 349RegType& RegTypeCache::FromUnresolvedSuperClass(RegType& child) { 350 // Check if entry already exists. 351 for (size_t i = primitive_count_; i < entries_.size(); i++) { 352 RegType* cur_entry = entries_[i]; 353 if (cur_entry->IsUnresolvedSuperClass()) { 354 UnresolvedSuperClass* tmp_entry = 355 down_cast<UnresolvedSuperClass*>(cur_entry); 356 uint16_t unresolved_super_child_id = 357 tmp_entry->GetUnresolvedSuperClassChildId(); 358 if (unresolved_super_child_id == child.GetId()) { 359 return *cur_entry; 360 } 361 } 362 } 363 RegType* entry = new UnresolvedSuperClass(child.GetId(), this, entries_.size()); 364 AddEntry(entry); 365 return *entry; 366} 367 368UninitializedType& RegTypeCache::Uninitialized(RegType& type, uint32_t allocation_pc) { 369 UninitializedType* entry = NULL; 370 const std::string& descriptor(type.GetDescriptor()); 371 if (type.IsUnresolvedTypes()) { 372 for (size_t i = primitive_count_; i < entries_.size(); i++) { 373 RegType* cur_entry = entries_[i]; 374 if (cur_entry->IsUnresolvedAndUninitializedReference() && 375 down_cast<UnresolvedUninitializedRefType*>(cur_entry)->GetAllocationPc() == allocation_pc && 376 (cur_entry->GetDescriptor() == descriptor)) { 377 return *down_cast<UnresolvedUninitializedRefType*>(cur_entry); 378 } 379 } 380 entry = new UnresolvedUninitializedRefType(descriptor, allocation_pc, entries_.size()); 381 } else { 382 mirror::Class* klass = type.GetClass(); 383 for (size_t i = primitive_count_; i < entries_.size(); i++) { 384 RegType* cur_entry = entries_[i]; 385 if (cur_entry->IsUninitializedReference() && 386 down_cast<UninitializedReferenceType*>(cur_entry) 387 ->GetAllocationPc() == allocation_pc && 388 cur_entry->GetClass() == klass) { 389 return *down_cast<UninitializedReferenceType*>(cur_entry); 390 } 391 } 392 entry = new UninitializedReferenceType(klass, descriptor, allocation_pc, entries_.size()); 393 } 394 AddEntry(entry); 395 return *entry; 396} 397 398RegType& RegTypeCache::FromUninitialized(RegType& uninit_type) { 399 RegType* entry; 400 401 if (uninit_type.IsUnresolvedTypes()) { 402 const std::string& descriptor(uninit_type.GetDescriptor()); 403 for (size_t i = primitive_count_; i < entries_.size(); i++) { 404 RegType* cur_entry = entries_[i]; 405 if (cur_entry->IsUnresolvedReference() && 406 cur_entry->GetDescriptor() == descriptor) { 407 return *cur_entry; 408 } 409 } 410 entry = new UnresolvedReferenceType(descriptor.c_str(), entries_.size()); 411 } else { 412 mirror::Class* klass = uninit_type.GetClass(); 413 if (uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) { 414 // For uninitialized "this reference" look for reference types that are not precise. 415 for (size_t i = primitive_count_; i < entries_.size(); i++) { 416 RegType* cur_entry = entries_[i]; 417 if (cur_entry->IsReference() && cur_entry->GetClass() == klass) { 418 return *cur_entry; 419 } 420 } 421 entry = new ReferenceType(klass, "", entries_.size()); 422 } else if (klass->IsInstantiable()) { 423 // We're uninitialized because of allocation, look or create a precise type as allocations 424 // may only create objects of that type. 425 for (size_t i = primitive_count_; i < entries_.size(); i++) { 426 RegType* cur_entry = entries_[i]; 427 if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) { 428 return *cur_entry; 429 } 430 } 431 entry = new PreciseReferenceType(klass, uninit_type.GetDescriptor(), entries_.size()); 432 } else { 433 return Conflict(); 434 } 435 } 436 AddEntry(entry); 437 return *entry; 438} 439 440ImpreciseConstType& RegTypeCache::ByteConstant() { 441 ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::min(), false); 442 DCHECK(result.IsImpreciseConstant()); 443 return *down_cast<ImpreciseConstType*>(&result); 444} 445 446ImpreciseConstType& RegTypeCache::CharConstant() { 447 int32_t jchar_max = static_cast<int32_t>(std::numeric_limits<jchar>::max()); 448 ConstantType& result = FromCat1Const(jchar_max, false); 449 DCHECK(result.IsImpreciseConstant()); 450 return *down_cast<ImpreciseConstType*>(&result); 451} 452 453ImpreciseConstType& RegTypeCache::ShortConstant() { 454 ConstantType& result = FromCat1Const(std::numeric_limits<jshort>::min(), false); 455 DCHECK(result.IsImpreciseConstant()); 456 return *down_cast<ImpreciseConstType*>(&result); 457} 458 459ImpreciseConstType& RegTypeCache::IntConstant() { 460 ConstantType& result = FromCat1Const(std::numeric_limits<jint>::max(), false); 461 DCHECK(result.IsImpreciseConstant()); 462 return *down_cast<ImpreciseConstType*>(&result); 463} 464 465ImpreciseConstType& RegTypeCache::PosByteConstant() { 466 ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::max(), false); 467 DCHECK(result.IsImpreciseConstant()); 468 return *down_cast<ImpreciseConstType*>(&result); 469} 470 471ImpreciseConstType& RegTypeCache::PosShortConstant() { 472 ConstantType& result = FromCat1Const(std::numeric_limits<jshort>::max(), false); 473 DCHECK(result.IsImpreciseConstant()); 474 return *down_cast<ImpreciseConstType*>(&result); 475} 476 477UninitializedType& RegTypeCache::UninitializedThisArgument(RegType& type) { 478 UninitializedType* entry; 479 const std::string& descriptor(type.GetDescriptor()); 480 if (type.IsUnresolvedTypes()) { 481 for (size_t i = primitive_count_; i < entries_.size(); i++) { 482 RegType* cur_entry = entries_[i]; 483 if (cur_entry->IsUnresolvedAndUninitializedThisReference() && 484 cur_entry->GetDescriptor() == descriptor) { 485 return *down_cast<UninitializedType*>(cur_entry); 486 } 487 } 488 entry = new UnresolvedUninitializedThisRefType(descriptor, entries_.size()); 489 } else { 490 mirror::Class* klass = type.GetClass(); 491 for (size_t i = primitive_count_; i < entries_.size(); i++) { 492 RegType* cur_entry = entries_[i]; 493 if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) { 494 return *down_cast<UninitializedType*>(cur_entry); 495 } 496 } 497 entry = new UninitializedThisReferenceType(klass, descriptor, entries_.size()); 498 } 499 AddEntry(entry); 500 return *entry; 501} 502 503ConstantType& RegTypeCache::FromCat1NonSmallConstant(int32_t value, bool precise) { 504 for (size_t i = primitive_count_; i < entries_.size(); i++) { 505 RegType* cur_entry = entries_[i]; 506 if (cur_entry->klass_.IsNull() && cur_entry->IsConstant() && 507 cur_entry->IsPreciseConstant() == precise && 508 (down_cast<ConstantType*>(cur_entry))->ConstantValue() == value) { 509 return *down_cast<ConstantType*>(cur_entry); 510 } 511 } 512 ConstantType* entry; 513 if (precise) { 514 entry = new PreciseConstType(value, entries_.size()); 515 } else { 516 entry = new ImpreciseConstType(value, entries_.size()); 517 } 518 AddEntry(entry); 519 return *entry; 520} 521 522ConstantType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) { 523 for (size_t i = primitive_count_; i < entries_.size(); i++) { 524 RegType* cur_entry = entries_[i]; 525 if (cur_entry->IsConstantLo() && (cur_entry->IsPrecise() == precise) && 526 (down_cast<ConstantType*>(cur_entry))->ConstantValueLo() == value) { 527 return *down_cast<ConstantType*>(cur_entry); 528 } 529 } 530 ConstantType* entry; 531 if (precise) { 532 entry = new PreciseConstLoType(value, entries_.size()); 533 } else { 534 entry = new ImpreciseConstLoType(value, entries_.size()); 535 } 536 AddEntry(entry); 537 return *entry; 538} 539 540ConstantType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) { 541 for (size_t i = primitive_count_; i < entries_.size(); i++) { 542 RegType* cur_entry = entries_[i]; 543 if (cur_entry->IsConstantHi() && (cur_entry->IsPrecise() == precise) && 544 (down_cast<ConstantType*>(cur_entry))->ConstantValueHi() == value) { 545 return *down_cast<ConstantType*>(cur_entry); 546 } 547 } 548 ConstantType* entry; 549 if (precise) { 550 entry = new PreciseConstHiType(value, entries_.size()); 551 } else { 552 entry = new ImpreciseConstHiType(value, entries_.size()); 553 } 554 AddEntry(entry); 555 return *entry; 556} 557 558RegType& RegTypeCache::GetComponentType(RegType& array, mirror::ClassLoader* loader) { 559 if (!array.IsArrayTypes()) { 560 return Conflict(); 561 } else if (array.IsUnresolvedTypes()) { 562 const std::string& descriptor(array.GetDescriptor()); 563 const std::string component(descriptor.substr(1, descriptor.size() - 1)); 564 return FromDescriptor(loader, component.c_str(), false); 565 } else { 566 mirror::Class* klass = array.GetClass()->GetComponentType(); 567 if (klass->IsErroneous()) { 568 // Arrays may have erroneous component types, use unresolved in that case. 569 // We assume that the primitive classes are not erroneous, so we know it is a 570 // reference type. 571 return FromDescriptor(loader, klass->GetDescriptor().c_str(), false); 572 } else { 573 return FromClass(klass->GetDescriptor().c_str(), klass, 574 klass->CannotBeAssignedFromOtherTypes()); 575 } 576 } 577} 578 579void RegTypeCache::Dump(std::ostream& os) { 580 for (size_t i = 0; i < entries_.size(); i++) { 581 RegType* cur_entry = entries_[i]; 582 if (cur_entry != NULL) { 583 os << i << ": " << cur_entry->Dump() << "\n"; 584 } 585 } 586} 587 588void RegTypeCache::VisitRoots(RootCallback* callback, void* arg) { 589 for (RegType* entry : entries_) { 590 entry->VisitRoots(callback, arg); 591 } 592} 593 594void RegTypeCache::AddEntry(RegType* new_entry) { 595 entries_.push_back(new_entry); 596} 597 598} // namespace verifier 599} // namespace art 600