Fix object verification.
Refactor VERIFY_OBJECT_ENABLED to become less brittle to change enum and global
constant.
Change-Id: Ie405106be81dce9a913730c7f46a5659582fa18b
diff --git a/src/base/mutex.cc b/src/base/mutex.cc
index 1975f3b..912e7fd 100644
--- a/src/base/mutex.cc
+++ b/src/base/mutex.cc
@@ -25,7 +25,7 @@
#include "mutex-inl.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
-#include "thread.h"
+#include "thread-inl.h"
#include "utils.h"
namespace art {
diff --git a/src/compiler/driver/compiler_driver_test.cc b/src/compiler/driver/compiler_driver_test.cc
index cbfc2ae..aef3a33 100644
--- a/src/compiler/driver/compiler_driver_test.cc
+++ b/src/compiler/driver/compiler_driver_test.cc
@@ -29,6 +29,7 @@
#include "mirror/dex_cache.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
namespace art {
diff --git a/src/compiler/jni/jni_compiler_test.cc b/src/compiler/jni/jni_compiler_test.cc
index 77dd51e..6c9a6df 100644
--- a/src/compiler/jni/jni_compiler_test.cc
+++ b/src/compiler/jni/jni_compiler_test.cc
@@ -25,6 +25,7 @@
#include "mirror/class_loader.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "mirror/stack_trace_element.h"
#include "runtime.h"
#include "ScopedLocalRef.h"
diff --git a/src/exception_test.cc b/src/exception_test.cc
index f0bec1b..1b4332f 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -19,6 +19,7 @@
#include "dex_file.h"
#include "gtest/gtest.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "mirror/stack_trace_element.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
diff --git a/src/heap.cc b/src/heap.cc
index a3a3a28..d7432a3 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -192,7 +192,7 @@
total_wait_time_(0),
measure_allocation_time_(false),
total_allocation_time_(0),
- verify_objects_(false) {
+ verify_object_mode_(kHeapVerificationNotPermitted) {
if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
LOG(INFO) << "Heap() entering";
}
@@ -587,15 +587,13 @@
return IsHeapAddress(obj) && GetLiveBitmap()->Test(obj);
}
-#if VERIFY_OBJECT_ENABLED
-void Heap::VerifyObject(const Object* obj) {
- if (obj == NULL || this == NULL || !verify_objects_ || Thread::Current() == NULL ||
+void Heap::VerifyObjectImpl(const mirror::Object* obj) {
+ if (Thread::Current() == NULL ||
Runtime::Current()->GetThreadList()->GetLockOwner() == Thread::Current()->GetTid()) {
return;
}
VerifyObjectBody(obj);
}
-#endif
void Heap::DumpSpaces() {
// TODO: C++0x auto
@@ -632,7 +630,7 @@
}
// Ignore early dawn of the universe verifications
- if (!VERIFY_OBJECT_FAST && GetObjectsAllocated() > 10) {
+ if (verify_object_mode_ != kVerifyAllFast && GetObjectsAllocated() > 10) {
const byte* raw_addr = reinterpret_cast<const byte*>(obj) +
mirror::Object::ClassOffset().Int32Value();
const mirror::Class* c = *reinterpret_cast<mirror::Class* const *>(raw_addr);
@@ -1458,7 +1456,7 @@
allocation_stack_.swap(live_stack_);
// Sort the live stack so that we can quickly binary search it later.
- if (VERIFY_OBJECT_ENABLED) {
+ if (verify_object_mode_ > kNoHeapVerification) {
std::sort(live_stack_->Begin(), live_stack_->End());
}
}
diff --git a/src/heap.h b/src/heap.h
index 7af15cd..a2c2d98 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -34,11 +34,6 @@
#include "safe_map.h"
#include "thread_pool.h"
-#define VERIFY_OBJECT_ENABLED 0
-
-// Fast verification means we do not verify the classes of objects.
-#define VERIFY_OBJECT_FAST 1
-
namespace art {
namespace mirror {
class Class;
@@ -80,6 +75,15 @@
};
std::ostream& operator<<(std::ostream& os, const GcCause& policy);
+// How we want to sanity check the heap's correctness.
+enum HeapVerificationMode {
+ kHeapVerificationNotPermitted, // Too early in runtime start-up for heap to be verified.
+ kNoHeapVerification, // Production default.
+ kVerifyAllFast, // Sanity check all heap accesses with quick(er) tests.
+ kVerifyAll // Sanity check all heap accesses.
+};
+const HeapVerificationMode kDesiredHeapVerification = kNoHeapVerification;
+
class Heap {
public:
static const size_t kDefaultInitialSize = 2 * MB;
@@ -106,14 +110,15 @@
mirror::Object* AllocObject(Thread* self, mirror::Class* klass, size_t num_bytes)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Check sanity of given reference. Requires the heap lock.
-#if VERIFY_OBJECT_ENABLED
- void VerifyObject(const mirror::Object* o);
-#else
- void VerifyObject(const mirror::Object*) {}
-#endif
+ // The given reference is believed to be to an object in the Java heap, check the soundness of it.
+ void VerifyObjectImpl(const mirror::Object* o);
+ void VerifyObject(const mirror::Object* o) {
+ if (o != NULL && this != NULL && verify_object_mode_ > kNoHeapVerification) {
+ VerifyObjectImpl(o);
+ }
+ }
- // Check sanity of all live references. Requires the heap lock.
+ // Check sanity of all live references.
void VerifyHeap() LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
static void RootMatchesObjectVisitor(const mirror::Object* root, void* arg);
bool VerifyHeapReferences()
@@ -219,19 +224,23 @@
return finalizer_reference_zombie_offset_;
}
+ // Enable verification of object references when the runtime is sufficiently initialized.
void EnableObjectValidation() {
-#if VERIFY_OBJECT_ENABLED
- VerifyHeap();
-#endif
- verify_objects_ = true;
+ verify_object_mode_ = kDesiredHeapVerification;
+ if (verify_object_mode_ > kNoHeapVerification) {
+ VerifyHeap();
+ }
}
+ // Disable object reference verification for image writing.
void DisableObjectValidation() {
- verify_objects_ = false;
+ verify_object_mode_ = kHeapVerificationNotPermitted;
}
+ // Other checks may be performed if we know the heap should be in a sane state.
bool IsObjectValidationEnabled() const {
- return verify_objects_;
+ return kDesiredHeapVerification > kNoHeapVerification &&
+ verify_object_mode_ > kHeapVerificationNotPermitted;
}
void RecordFree(size_t freed_objects, size_t freed_bytes);
@@ -532,7 +541,9 @@
const bool measure_allocation_time_;
AtomicInteger total_allocation_time_;
- bool verify_objects_;
+ // The current state of heap verification, may be enabled or disabled.
+ HeapVerificationMode verify_object_mode_;
+
typedef std::vector<MarkSweep*> Collectors;
Collectors mark_sweep_collectors_;
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 4b820f9..67020d8 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -22,6 +22,7 @@
#include "common_test.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "ScopedLocalRef.h"
#include "sirt_ref.h"
diff --git a/src/mirror/dex_cache_test.cc b/src/mirror/dex_cache_test.cc
index 9817660..3d753e1 100644
--- a/src/mirror/dex_cache_test.cc
+++ b/src/mirror/dex_cache_test.cc
@@ -19,6 +19,7 @@
#include "dex_cache.h"
#include "heap.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "sirt_ref.h"
#include <stdio.h>
diff --git a/src/mirror/object-inl.h b/src/mirror/object-inl.h
index b6c8008..3913c81 100644
--- a/src/mirror/object-inl.h
+++ b/src/mirror/object-inl.h
@@ -263,6 +263,10 @@
Runtime::Current()->GetHeap()->WriteBarrierField(dst, field_offset, new_value);
}
+inline void Object::VerifyObject(const Object* obj) {
+ Runtime::Current()->GetHeap()->VerifyObject(obj);
+}
+
} // namespace mirror
} // namespace art
diff --git a/src/mirror/object.cc b/src/mirror/object.cc
index 5c65b83..4acb567 100644
--- a/src/mirror/object.cc
+++ b/src/mirror/object.cc
@@ -19,13 +19,15 @@
#include "array-inl.h"
#include "class.h"
#include "class-inl.h"
+#include "class_linker-inl.h"
#include "field.h"
#include "field-inl.h"
#include "gc/card_table-inl.h"
#include "heap.h"
+#include "iftable-inl.h"
#include "monitor.h"
#include "object-inl.h"
-#include "object_array.h"
+#include "object_array-inl.h"
#include "object_utils.h"
#include "runtime.h"
#include "sirt_ref.h"
@@ -80,8 +82,7 @@
return copy.get();
}
-#if VERIFY_OBJECT_ENABLED
-void Object::CheckFieldAssignment(MemberOffset field_offset, const Object* new_value) {
+void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, const Object* new_value) {
const Class* c = GetClass();
if (Runtime::Current()->GetClassLinker() == NULL ||
!Runtime::Current()->GetHeap()->IsObjectValidationEnabled() ||
@@ -123,7 +124,6 @@
LOG(FATAL) << "Failed to find field for assignment to " << reinterpret_cast<void*>(this)
<< " of type " << PrettyDescriptor(c) << " at offset " << field_offset;
}
-#endif
} // namespace mirror
} // namespace art
diff --git a/src/mirror/object.h b/src/mirror/object.h
index c404b61..0cce8d8 100644
--- a/src/mirror/object.h
+++ b/src/mirror/object.h
@@ -58,6 +58,8 @@
#define OFFSET_OF_OBJECT_MEMBER(type, field) \
MemberOffset(OFFSETOF_MEMBER(type, field))
+const bool kCheckFieldAssignments = false;
+
// C++ mirror of java.lang.Object
class MANAGED Object {
public:
@@ -231,15 +233,17 @@
}
private:
-#if VERIFY_OBJECT_ENABLED
static void VerifyObject(const Object* obj);
- void CheckFieldAssignment(MemberOffset field_offset, const Object* new_value)
+
+ // Verify the type correctness of stores to fields.
+ void CheckFieldAssignmentImpl(MemberOffset field_offset, const Object* new_value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-#else
- static void VerifyObject(const Object*) {}
- void CheckFieldAssignment(MemberOffset, const Object*)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {}
-#endif
+ void CheckFieldAssignment(MemberOffset field_offset, const Object* new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (kCheckFieldAssignments) {
+ CheckFieldAssignmentImpl(field_offset, new_value);
+ }
+ }
// Write barrier called post update to a reference bearing field.
static void WriteBarrierField(const Object* dst, MemberOffset offset, const Object* new_value);
diff --git a/src/oat/runtime/arm/context_arm.cc b/src/oat/runtime/arm/context_arm.cc
index 4612986..814e649 100644
--- a/src/oat/runtime/arm/context_arm.cc
+++ b/src/oat/runtime/arm/context_arm.cc
@@ -17,6 +17,7 @@
#include "context_arm.h"
#include "mirror/abstract_method.h"
+#include "mirror/object-inl.h"
#include "stack.h"
#include "thread.h"
diff --git a/src/oat/runtime/callee_save_frame.h b/src/oat/runtime/callee_save_frame.h
index 08cf9d8..dd2f3fa 100644
--- a/src/oat/runtime/callee_save_frame.h
+++ b/src/oat/runtime/callee_save_frame.h
@@ -18,7 +18,7 @@
#define ART_SRC_OAT_RUNTIME_CALLEE_SAVE_FRAME_H_
#include "base/mutex.h"
-#include "thread.h"
+#include "thread-inl.h"
namespace art {
namespace mirror {
diff --git a/src/oat/runtime/support_instrumentation.cc b/src/oat/runtime/support_instrumentation.cc
index f65717a..6598f19 100644
--- a/src/oat/runtime/support_instrumentation.cc
+++ b/src/oat/runtime/support_instrumentation.cc
@@ -17,7 +17,7 @@
#include "base/logging.h"
#include "instrumentation.h"
#include "runtime.h"
-#include "thread.h"
+#include "thread-inl.h"
#include "trace.h"
namespace art {
diff --git a/src/oat_test.cc b/src/oat_test.cc
index c4bd60e..a2ea71c 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -17,6 +17,7 @@
#include "mirror/abstract_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "oat_file.h"
#include "oat_writer.h"
#include "vector_output_stream.h"
diff --git a/src/thread-inl.h b/src/thread-inl.h
index 414b8d8..6c1ae59 100644
--- a/src/thread-inl.h
+++ b/src/thread-inl.h
@@ -124,6 +124,13 @@
return static_cast<ThreadState>(old_state);
}
+inline void Thread::VerifyStack() {
+ Heap* heap = Runtime::Current()->GetHeap();
+ if (heap->IsObjectValidationEnabled()) {
+ VerifyStackImpl();
+ }
+}
+
} // namespace art
#endif // ART_SRC_THREAD_INL_H_
diff --git a/src/thread.cc b/src/thread.cc
index 394d263..94c437f 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -2004,20 +2004,17 @@
ReleaseLongJumpContext(context);
}
-#if VERIFY_OBJECT_ENABLED
-static void VerifyObject(const Object* obj, void* arg) {
+static void VerifyObject(const mirror::Object* root, void* arg) {
Heap* heap = reinterpret_cast<Heap*>(arg);
- heap->VerifyObject(obj);
+ heap->VerifyObject(root);
}
-void Thread::VerifyStack() {
+void Thread::VerifyStackImpl() {
UniquePtr<Context> context(Context::Create());
RootCallbackVisitor visitorToCallback(VerifyObject, Runtime::Current()->GetHeap());
- ReferenceMapVisitor<RootCallbackVisitor> mapper(GetManagedStack(), GetInstrumentationStack(),
- context.get(), visitorToCallback);
+ ReferenceMapVisitor<RootCallbackVisitor> mapper(this, context.get(), visitorToCallback);
mapper.WalkStack();
}
-#endif
// Set the stack end to that to be used during a stack overflow
void Thread::SetStackEndForStackOverflow() {
diff --git a/src/thread.h b/src/thread.h
index 1992dc9..dd67a21 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -401,11 +401,7 @@
void VerifyRoots(VerifyRootVisitor* visitor, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-#if VERIFY_OBJECT_ENABLED
void VerifyStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-#else
- void VerifyStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_){}
-#endif
//
// Offsets of various members of native Thread class, used by compiled code.
@@ -610,6 +606,8 @@
}
friend class SignalCatcher; // For SetStateUnsafe.
+ void VerifyStackImpl() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void DumpState(std::ostream& os) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void DumpStack(std::ostream& os) const
LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc
index a16d896..92cfa99 100644
--- a/test/StackWalk/stack_walk_jni.cc
+++ b/test/StackWalk/stack_walk_jni.cc
@@ -22,6 +22,7 @@
#include "mirror/abstract_method.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "object_utils.h"
#include "jni.h"
#include "scoped_thread_state_change.h"