diff options
| author | 2013-01-07 12:00:42 -0800 | |
|---|---|---|
| committer | 2013-01-07 12:00:43 -0800 | |
| commit | 1a25aa432314bcf008c11e3514afc0b7aeb64d5c (patch) | |
| tree | d6a9831d89fde0f4a31762f4514d9d42f8c41e56 /src | |
| parent | 1e5ba286ab9e815e3121b408019fcaad0d4b17ec (diff) | |
| parent | 80537bb742dff4ccdf6d04b1c0bb7d2179acc8cb (diff) | |
Merge "Fix and reenable lock dumping in stack dumps." into dalvik-dev
Diffstat (limited to 'src')
| -rw-r--r-- | src/heap.cc | 5 | ||||
| -rw-r--r-- | src/monitor.cc | 58 | ||||
| -rw-r--r-- | src/signal_catcher.cc | 2 | ||||
| -rw-r--r-- | src/thread.cc | 10 | ||||
| -rw-r--r-- | src/thread.h | 3 | ||||
| -rw-r--r-- | src/timing_logger.h | 8 | ||||
| -rw-r--r-- | src/verifier/method_verifier.cc | 17 | ||||
| -rw-r--r-- | src/verifier/method_verifier.h | 4 | ||||
| -rw-r--r-- | src/verifier/reg_type.cc | 2 | ||||
| -rw-r--r-- | src/verifier/reg_type.h | 41 | ||||
| -rw-r--r-- | src/verifier/reg_type_cache.cc | 45 | ||||
| -rw-r--r-- | src/verifier/reg_type_cache.h | 5 | ||||
| -rw-r--r-- | src/verifier/reg_type_test.cc | 2 |
13 files changed, 112 insertions, 90 deletions
diff --git a/src/heap.cc b/src/heap.cc index 7edbcf0460..1cdc9c904c 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -396,7 +396,8 @@ void Heap::DumpGcPerformanceInfo() { LOG(INFO) << "Total time spent in GC: " << PrettyDuration(total_duration); LOG(INFO) << "Mean GC size throughput: " << PrettySize(GetTotalBytesFreed() / total_seconds) << "/s"; - LOG(INFO) << "Mean GC object throughput: " << GetTotalObjectsFreed() / total_seconds << "/s"; + LOG(INFO) << "Mean GC object throughput: " + << (GetTotalObjectsFreed() / total_seconds) << " objects/s"; } LOG(INFO) << "Total number of allocations: " << total_objects_allocated; LOG(INFO) << "Total bytes allocated " << PrettySize(total_bytes_allocated); @@ -406,7 +407,7 @@ void Heap::DumpGcPerformanceInfo() { << PrettyDuration(allocation_time / total_objects_allocated); } LOG(INFO) << "Total mutator paused time: " << PrettyDuration(total_paused_time); - LOG(INFO) << "Total time waiting for GC to complete time: " << PrettyDuration(total_wait_time_); + LOG(INFO) << "Total time waiting for GC to complete: " << PrettyDuration(total_wait_time_); } Heap::~Heap() { diff --git a/src/monitor.cc b/src/monitor.cc index 6172136d4a..33383ebc59 100644 --- a/src/monitor.cc +++ b/src/monitor.cc @@ -901,41 +901,35 @@ void Monitor::DescribeLocks(std::ostream& os, StackVisitor* stack_visitor) { return; // No "tries" implies no synchronization, so no held locks to report. } - // TODO: Enable dex register lock descriptions, disabling as for the portable path GetVReg is - // unimplemented. There is also a possible deadlock relating to the verifier calling - // ClassLoader.loadClass and reentering managed code whilst the ThreadList lock is held. - const bool kEnableDexRegisterLockDescriptions = false; - if (kEnableDexRegisterLockDescriptions) { - // Ask the verifier for the dex pcs of all the monitor-enter instructions corresponding to - // the locks held in this stack frame. - std::vector<uint32_t> monitor_enter_dex_pcs; - verifier::MethodVerifier::FindLocksAtDexPc(m, stack_visitor->GetDexPc(), monitor_enter_dex_pcs); - if (monitor_enter_dex_pcs.empty()) { - return; - } + // Ask the verifier for the dex pcs of all the monitor-enter instructions corresponding to + // the locks held in this stack frame. + std::vector<uint32_t> monitor_enter_dex_pcs; + verifier::MethodVerifier::FindLocksAtDexPc(m, stack_visitor->GetDexPc(), monitor_enter_dex_pcs); + if (monitor_enter_dex_pcs.empty()) { + return; + } - // Verification is an iterative process, so it can visit the same monitor-enter instruction - // repeatedly with increasingly accurate type information. Our callers don't want to see - // duplicates. - STLSortAndRemoveDuplicates(&monitor_enter_dex_pcs); - - for (size_t i = 0; i < monitor_enter_dex_pcs.size(); ++i) { - // The verifier works in terms of the dex pcs of the monitor-enter instructions. - // We want the registers used by those instructions (so we can read the values out of them). - uint32_t dex_pc = monitor_enter_dex_pcs[i]; - uint16_t monitor_enter_instruction = code_item->insns_[dex_pc]; - - // Quick sanity check. - if ((monitor_enter_instruction & 0xff) != Instruction::MONITOR_ENTER) { - LOG(FATAL) << "expected monitor-enter @" << dex_pc << "; was " - << reinterpret_cast<void*>(monitor_enter_instruction); - } + // Verification is an iterative process, so it can visit the same monitor-enter instruction + // repeatedly with increasingly accurate type information. We don't want duplicates. + // TODO: is this fixed if we share the other std::vector-returning verifier code? + STLSortAndRemoveDuplicates(&monitor_enter_dex_pcs); + + for (size_t i = 0; i < monitor_enter_dex_pcs.size(); ++i) { + // The verifier works in terms of the dex pcs of the monitor-enter instructions. + // We want the registers used by those instructions (so we can read the values out of them). + uint32_t dex_pc = monitor_enter_dex_pcs[i]; + uint16_t monitor_enter_instruction = code_item->insns_[dex_pc]; - uint16_t monitor_register = ((monitor_enter_instruction >> 8) & 0xff); - Object* o = reinterpret_cast<Object*>(stack_visitor->GetVReg(m, monitor_register, - kReferenceVReg)); - DumpLockedObject(os, o); + // Quick sanity check. + if ((monitor_enter_instruction & 0xff) != Instruction::MONITOR_ENTER) { + LOG(FATAL) << "expected monitor-enter @" << dex_pc << "; was " + << reinterpret_cast<void*>(monitor_enter_instruction); } + + uint16_t monitor_register = ((monitor_enter_instruction >> 8) & 0xff); + Object* o = reinterpret_cast<Object*>(stack_visitor->GetVReg(m, monitor_register, + kReferenceVReg)); + DumpLockedObject(os, o); } } diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc index 9fdf4e9927..c021dd1d2c 100644 --- a/src/signal_catcher.cc +++ b/src/signal_catcher.cc @@ -124,7 +124,7 @@ void SignalCatcher::HandleSigQuit() { thread_list->SuspendAll(); Thread* self = Thread::Current(); Locks::mutator_lock_->AssertExclusiveHeld(self); - const char* old_cause = self->StartAssertNoThreadSuspension("Handling sigquit"); + const char* old_cause = self->StartAssertNoThreadSuspension("Handling SIGQUIT"); ThreadState old_state = self->SetStateUnsafe(kRunnable); std::ostringstream os; diff --git a/src/thread.cc b/src/thread.cc index 484806e3f9..439e8f60fa 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -773,7 +773,11 @@ void Thread::DumpState(std::ostream& os, const Thread* thread, pid_t tid) { } os << " prio=" << priority << " tid=" << thread->GetThinLockId() - << " " << thread->GetState() << "\n"; + << " " << thread->GetState(); + if (thread->IsStillStarting()) { + os << " (still starting up)"; + } + os << "\n"; } else { os << '"' << ::art::GetThreadName(tid) << '"' << " prio=" << priority @@ -996,12 +1000,12 @@ Thread::Thread(bool daemon) bool Thread::IsStillStarting() const { // You might think you can check whether the state is kStarting, but for much of thread startup, - // the thread might also be in kVmWait. + // the thread is in kNative; it might also be in kVmWait. // You might think you can check whether the peer is NULL, but the peer is actually created and // assigned fairly early on, and needs to be. // It turns out that the last thing to change is the thread name; that's a good proxy for "has // this thread _ever_ entered kRunnable". - return (*name_ == kThreadNameDuringStartup); + return (jpeer_ == NULL && opeer_ == NULL) || (*name_ == kThreadNameDuringStartup); } void Thread::AssertNoPendingException() const { diff --git a/src/thread.h b/src/thread.h index e8f69dba4f..ea499600fe 100644 --- a/src/thread.h +++ b/src/thread.h @@ -289,8 +289,7 @@ class PACKED(4) Thread { } bool HasPeer() const { - CHECK(jpeer_ == NULL); - return opeer_ != NULL; + return jpeer_ != NULL || opeer_ != NULL; } RuntimeStats* GetStats() { diff --git a/src/timing_logger.h b/src/timing_logger.h index b0a3e660c4..3b3dcfc1aa 100644 --- a/src/timing_logger.h +++ b/src/timing_logger.h @@ -175,9 +175,11 @@ class CumulativeLogger { mean -= mean % (divisor / 1000); std_dev -= std_dev % (divisor / 1000); } - os << name_ << ": " << std::setw(8) - << FormatDuration(mean * kAdjust, tu) << " std_dev " - << FormatDuration(std_dev * kAdjust, tu) << " " << labels_[i] << "\n"; + os << StringPrintf("%s: %10s (std_dev %8s) %s\n", + name_.c_str(), + FormatDuration(mean * kAdjust, tu).c_str(), + FormatDuration(std_dev * kAdjust, tu).c_str(), + labels_[i].c_str()); } uint64_t total_mean_x2 = total_time_squared_; uint64_t mean_total_ns = GetTotalTime(); diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc index 41098cb75c..6611d3ca58 100644 --- a/src/verifier/method_verifier.cc +++ b/src/verifier/method_verifier.cc @@ -295,7 +295,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, co uint64_t start_ns = NanoTime(); MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item, method_idx, - method, method_access_flags); + method, method_access_flags, true); if (verifier.Verify()) { // Verification completed, however failures may be pending that didn't cause the verification // to hard fail. @@ -331,7 +331,7 @@ void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_i const DexFile::CodeItem* code_item, AbstractMethod* method, uint32_t method_access_flags) { MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item, - dex_method_idx, method, method_access_flags); + dex_method_idx, method, method_access_flags, true); verifier.Verify(); verifier.DumpFailures(os); os << verifier.info_messages_.str(); @@ -346,15 +346,17 @@ std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_method_idx, AbstractMethod* method, uint32_t method_access_flags, uint32_t dex_pc) { MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item, - dex_method_idx, method, method_access_flags); + dex_method_idx, method, method_access_flags, true); verifier.Verify(); return verifier.DescribeVRegs(dex_pc); } MethodVerifier::MethodVerifier(const DexFile* dex_file, DexCache* dex_cache, ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item, - uint32_t dex_method_idx, AbstractMethod* method, uint32_t method_access_flags) - : work_insn_idx_(-1), + uint32_t dex_method_idx, AbstractMethod* method, uint32_t method_access_flags, + bool can_load_classes) + : reg_types_(can_load_classes), + work_insn_idx_(-1), dex_method_idx_(dex_method_idx), foo_method_(method), method_access_flags_(method_access_flags), @@ -368,7 +370,8 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, DexCache* dex_cache, have_pending_hard_failure_(false), have_pending_runtime_throw_failure_(false), new_instance_count_(0), - monitor_enter_count_(0) { + monitor_enter_count_(0), + can_load_classes_(can_load_classes) { } void MethodVerifier::FindLocksAtDexPc(AbstractMethod* m, uint32_t dex_pc, @@ -376,7 +379,7 @@ void MethodVerifier::FindLocksAtDexPc(AbstractMethod* m, uint32_t dex_pc, MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), - m, m->GetAccessFlags()); + m, m->GetAccessFlags(), false); verifier.interesting_dex_pc_ = dex_pc; verifier.monitor_enter_dex_pcs_ = &monitor_enter_dex_pcs; verifier.FindLocksAtDexPc(); diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h index b6762692eb..a02cc258b7 100644 --- a/src/verifier/method_verifier.h +++ b/src/verifier/method_verifier.h @@ -227,7 +227,7 @@ class MethodVerifier { private: explicit MethodVerifier(const DexFile* dex_file, DexCache* dex_cache, ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item, - uint32_t method_idx, AbstractMethod* method, uint32_t access_flags) + uint32_t method_idx, AbstractMethod* method, uint32_t access_flags, bool can_load_classes) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Adds the given string to the beginning of the last failure message. @@ -670,6 +670,8 @@ class MethodVerifier { // The number of occurrences of specific opcodes. size_t new_instance_count_; size_t monitor_enter_count_; + + const bool can_load_classes_; }; std::ostream& operator<<(std::ostream& os, const MethodVerifier::FailureKind& rhs); diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc index dc41cebc56..ab1da1e2c3 100644 --- a/src/verifier/reg_type.cc +++ b/src/verifier/reg_type.cc @@ -173,7 +173,7 @@ const RegType& RegType::GetSuperClass(RegTypeCache* cache) const { } } else { if (!IsUnresolvedMergedReference() && !IsUnresolvedSuperClass() && - GetDescriptor()->CharAt(0) == '[') { + GetDescriptor()[0] == '[') { // Super class of all arrays is Object. return cache->JavaLangObject(true); } else { diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h index c610e06388..65ee88a639 100644 --- a/src/verifier/reg_type.h +++ b/src/verifier/reg_type.h @@ -263,9 +263,8 @@ class RegType { Class* GetClass() const { DCHECK(!IsUnresolvedReference()); - DCHECK(klass_or_descriptor_ != NULL); - DCHECK(klass_or_descriptor_->IsClass()); - return down_cast<Class*>(klass_or_descriptor_); + DCHECK(klass_ != NULL); + return klass_; } bool IsJavaLangObject() const { @@ -274,7 +273,7 @@ class RegType { bool IsArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass()) { - return GetDescriptor()->CharAt(0) == '['; + return descriptor_[0] == '['; } else if (HasClass()) { return GetClass()->IsArrayClass(); } else { @@ -285,8 +284,8 @@ class RegType { bool IsObjectArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass()) { // Primitive arrays will always resolve - DCHECK(GetDescriptor()->CharAt(1) == 'L' || GetDescriptor()->CharAt(1) == '['); - return GetDescriptor()->CharAt(0) == '['; + DCHECK(descriptor_[1] == 'L' || descriptor_[1] == '['); + return descriptor_[0] == '['; } else if (HasClass()) { Class* type = GetClass(); return type->IsArrayClass() && !type->GetComponentType()->IsPrimitive(); @@ -330,11 +329,9 @@ class RegType { return IsUnresolvedTypes() || (IsNonZeroReferenceTypes() && GetClass()->IsInstantiable()); } - String* GetDescriptor() const { + std::string GetDescriptor() const { DCHECK(IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass()); - DCHECK(klass_or_descriptor_ != NULL); - DCHECK(klass_or_descriptor_->GetClass()->IsStringClass()); - return down_cast<String*>(klass_or_descriptor_); + return descriptor_; } uint16_t GetId() const { @@ -402,9 +399,9 @@ class RegType { private: friend class RegTypeCache; - RegType(Type type, Object* klass_or_descriptor, + RegType(Type type, Class* klass, uint32_t allocation_pc_or_constant_or_merged_types, uint16_t cache_id) - : type_(type), klass_or_descriptor_(klass_or_descriptor), + : type_(type), klass_(klass), allocation_pc_or_constant_or_merged_types_(allocation_pc_or_constant_or_merged_types), cache_id_(cache_id) { DCHECK(IsConstant() || IsConstantLo() || IsConstantHi() || @@ -412,16 +409,26 @@ class RegType { allocation_pc_or_constant_or_merged_types == 0); if (!IsConstant() && !IsLongConstant() && !IsLongConstantHigh() && !IsUndefined() && !IsConflict() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass()) { - DCHECK(klass_or_descriptor != NULL); - DCHECK(IsUnresolvedTypes() || klass_or_descriptor_->IsClass()); - DCHECK(!IsUnresolvedTypes() || klass_or_descriptor_->GetClass()->IsStringClass()); + DCHECK(klass_ != NULL); + DCHECK(klass_->IsClass()); + DCHECK(!IsUnresolvedTypes()); } } + RegType(Type type, const std::string& descriptor, uint32_t allocation_pc, uint16_t cache_id) + : type_(type), + klass_(NULL), + descriptor_(descriptor), + allocation_pc_or_constant_or_merged_types_(allocation_pc), + cache_id_(cache_id) { + } + const Type type_; // The current type of the register - // If known the type of the register, else a String for the descriptor - Object* klass_or_descriptor_; + // If known the type of the register... + Class* klass_; + // ...else a String for the descriptor. + std::string descriptor_; // Overloaded field that: // - if IsConstant() holds a 32bit constant value diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc index 1b91321b13..3bf5ad886a 100644 --- a/src/verifier/reg_type_cache.cc +++ b/src/verifier/reg_type_cache.cc @@ -74,11 +74,11 @@ const RegType& RegTypeCache::From(RegType::Type type, ClassLoader* loader, const DCHECK_GT(entries_.size(), static_cast<size_t>(type)); RegType* entry = entries_[type]; if (entry == NULL) { - Class* klass = NULL; + Class* c = NULL; if (strlen(descriptor) != 0) { - klass = Runtime::Current()->GetClassLinker()->FindSystemClass(descriptor); + c = Runtime::Current()->GetClassLinker()->FindSystemClass(descriptor); } - entry = new RegType(type, klass, 0, type); + entry = new RegType(type, c, 0, type); entries_[type] = entry; } return *entry; @@ -95,30 +95,37 @@ const RegType& RegTypeCache::From(RegType::Type type, ClassLoader* loader, const return *cur_entry; } } else if (cur_entry->IsUnresolvedReference() && - cur_entry->GetDescriptor()->Equals(descriptor)) { + cur_entry->GetDescriptor() == descriptor) { return *cur_entry; } } - Class* klass = Runtime::Current()->GetClassLinker()->FindClass(descriptor, loader); - if (klass != NULL) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Class* c; + if (can_load_classes_) { + c = class_linker->FindClass(descriptor, loader); + } else { + c = class_linker->LookupClass(descriptor, loader); + } + if (c != NULL) { // Able to resolve so create resolved register type that is precise if we // know the type is final. - RegType* entry = new RegType(klass->IsFinal() ? RegType::kRegTypePreciseReference - : RegType::kRegTypeReference, - klass, 0, entries_.size()); + RegType* entry = new RegType(c->IsFinal() ? RegType::kRegTypePreciseReference + : RegType::kRegTypeReference, + c, 0, entries_.size()); entries_.push_back(entry); return *entry; } else { // TODO: we assume unresolved, but we may be able to do better by validating whether the // descriptor string is valid // Unable to resolve so create unresolved register type - DCHECK(Thread::Current()->IsExceptionPending()); - Thread::Current()->ClearException(); + if (can_load_classes_) { + DCHECK(Thread::Current()->IsExceptionPending()); + Thread::Current()->ClearException(); + } else { + DCHECK(!Thread::Current()->IsExceptionPending()); + } if (IsValidDescriptor(descriptor)) { - String* string_descriptor = - Runtime::Current()->GetInternTable()->InternStrong(descriptor); - RegType* entry = new RegType(RegType::kRegTypeUnresolvedReference, string_descriptor, 0, - entries_.size()); + RegType* entry = new RegType(RegType::kRegTypeUnresolvedReference, descriptor, 0, entries_.size()); entries_.push_back(entry); return *entry; } else { @@ -214,7 +221,7 @@ const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) { const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) { RegType* entry; if (type.IsUnresolvedTypes()) { - String* descriptor = type.GetDescriptor(); + std::string descriptor(type.GetDescriptor()); for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) { RegType* cur_entry = entries_[i]; if (cur_entry->IsUnresolvedAndUninitializedReference() && @@ -245,7 +252,7 @@ const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocat const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) { RegType* entry; if (uninit_type.IsUnresolvedTypes()) { - String* descriptor = uninit_type.GetDescriptor(); + std::string descriptor(uninit_type.GetDescriptor()); for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) { RegType* cur_entry = entries_[i]; if (cur_entry->IsUnresolvedReference() && cur_entry->GetDescriptor() == descriptor) { @@ -271,7 +278,7 @@ const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) { // TODO: implement descriptor version. RegType* entry; if (type.IsUnresolvedTypes()) { - String* descriptor = type.GetDescriptor(); + std::string descriptor(type.GetDescriptor()); for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) { RegType* cur_entry = entries_[i]; if (cur_entry->IsUnresolvedAndUninitializedThisReference() && @@ -354,7 +361,7 @@ const RegType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) { const RegType& RegTypeCache::GetComponentType(const RegType& array, ClassLoader* loader) { CHECK(array.IsArrayTypes()); if (array.IsUnresolvedTypes()) { - std::string descriptor(array.GetDescriptor()->ToModifiedUtf8()); + std::string descriptor(array.GetDescriptor()); std::string component(descriptor.substr(1, descriptor.size() - 1)); return FromDescriptor(loader, component.c_str(), false); } else { diff --git a/src/verifier/reg_type_cache.h b/src/verifier/reg_type_cache.h index 1cd3fba0bd..54f42fd857 100644 --- a/src/verifier/reg_type_cache.h +++ b/src/verifier/reg_type_cache.h @@ -26,7 +26,8 @@ namespace verifier { class RegTypeCache { public: - explicit RegTypeCache() : entries_(RegType::kRegTypeLastFixedLocation + 1) { + explicit RegTypeCache(bool can_load_classes) + : entries_(RegType::kRegTypeLastFixedLocation + 1), can_load_classes_(can_load_classes) { Undefined(); // ensure Undefined is initialized } ~RegTypeCache() { @@ -142,6 +143,8 @@ class RegTypeCache { private: // The allocated entries std::vector<RegType*> entries_; + // Whether or not we're allowed to load classes. + const bool can_load_classes_; DISALLOW_COPY_AND_ASSIGN(RegTypeCache); }; diff --git a/src/verifier/reg_type_test.cc b/src/verifier/reg_type_test.cc index 18e9a65cf4..c66477c84c 100644 --- a/src/verifier/reg_type_test.cc +++ b/src/verifier/reg_type_test.cc @@ -27,7 +27,7 @@ class RegTypeTest : public CommonTest {}; TEST_F(RegTypeTest, Primitives) { ScopedObjectAccess soa(Thread::Current()); - RegTypeCache cache; + RegTypeCache cache(true); const RegType& bool_reg_type = cache.Boolean(); EXPECT_FALSE(bool_reg_type.IsUndefined()); |