Print field info on mark sweep invalid ref crash.

Bug: 20557050
Change-Id: I3abb7a44e3b7ed3256653824fd1705aac5f7d72c
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index 2aed440..47d5a76 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -63,6 +63,17 @@
       FindInstanceFieldWithOffset(klass->GetSuperClass(), field_offset) : nullptr;
 }
 
+ArtField* ArtField::FindStaticFieldWithOffset(mirror::Class* klass, uint32_t field_offset) {
+  DCHECK(klass != nullptr);
+  auto* static_fields = klass->GetSFields();
+  for (size_t i = 0, count = klass->NumStaticFields(); i < count; ++i) {
+    if (static_fields[i].GetOffset().Uint32Value() == field_offset) {
+      return &static_fields[i];
+    }
+  }
+  return nullptr;
+}
+
 mirror::Class* ArtField::ProxyFindSystemClass(const char* descriptor) {
   DCHECK(GetDeclaringClass()->IsProxyClass());
   return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor);
diff --git a/runtime/art_field.h b/runtime/art_field.h
index c0620bf..9d3dbd9 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -161,6 +161,9 @@
   // Returns an instance field with this offset in the given class or null if not found.
   static ArtField* FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // Returns a static field with this offset in the given class or null if not found.
+  static ArtField* FindStaticFieldWithOffset(mirror::Class* klass, uint32_t field_offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/gc/accounting/heap_bitmap.h b/runtime/gc/accounting/heap_bitmap.h
index 245e074..1648aef 100644
--- a/runtime/gc/accounting/heap_bitmap.h
+++ b/runtime/gc/accounting/heap_bitmap.h
@@ -39,9 +39,11 @@
   void Clear(const mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
   template<typename LargeObjectSetVisitor>
   bool Set(const mirror::Object* obj, const LargeObjectSetVisitor& visitor)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) ALWAYS_INLINE;
   template<typename LargeObjectSetVisitor>
   bool AtomicTestAndSet(const mirror::Object* obj, const LargeObjectSetVisitor& visitor)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) ALWAYS_INLINE;
   ContinuousSpaceBitmap* GetContinuousSpaceBitmap(const mirror::Object* obj) const;
   LargeObjectBitmap* GetLargeObjectBitmap(const mirror::Object* obj) const;
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 55a8411..53e56da 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -368,10 +368,13 @@
 
 class MarkSweepMarkObjectSlowPath {
  public:
-  explicit MarkSweepMarkObjectSlowPath(MarkSweep* mark_sweep) : mark_sweep_(mark_sweep) {
+  explicit MarkSweepMarkObjectSlowPath(MarkSweep* mark_sweep, Object* holder = nullptr,
+                                       MemberOffset offset = MemberOffset(0))
+      : mark_sweep_(mark_sweep), holder_(holder), offset_(offset) {
   }
 
-  void operator()(const Object* obj) const ALWAYS_INLINE {
+  void operator()(const Object* obj) const ALWAYS_INLINE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (kProfileLargeObjects) {
       // TODO: Differentiate between marking and testing somehow.
       ++mark_sweep_->large_object_test_;
@@ -384,6 +387,13 @@
       LOG(INTERNAL_FATAL) << "Tried to mark " << obj << " not contained by any spaces";
       LOG(INTERNAL_FATAL) << "Attempting see if it's a bad root";
       mark_sweep_->VerifyRoots();
+      if (holder_ != nullptr) {
+        ArtField* field = holder_->FindFieldByOffset(offset_);
+        LOG(INTERNAL_FATAL) << "Field info: holder=" << holder_
+                            << " holder_type=" << PrettyTypeOf(holder_)
+                            << " offset=" << offset_.Uint32Value()
+                            << " field=" << (field != nullptr ? field->GetName() : "nullptr");
+      }
       PrintFileToLog("/proc/self/maps", LogSeverity::INTERNAL_FATAL);
       MemMap::DumpMaps(LOG(INTERNAL_FATAL), true);
       LOG(FATAL) << "Can't mark invalid object";
@@ -392,9 +402,11 @@
 
  private:
   MarkSweep* const mark_sweep_;
+  mirror::Object* const holder_;
+  MemberOffset offset_;
 };
 
-inline void MarkSweep::MarkObjectNonNull(Object* obj) {
+inline void MarkSweep::MarkObjectNonNull(Object* obj, Object* holder, MemberOffset offset) {
   DCHECK(obj != nullptr);
   if (kUseBakerOrBrooksReadBarrier) {
     // Verify all the objects have the correct pointer installed.
@@ -416,7 +428,7 @@
     if (kCountMarkedObjects) {
       ++mark_slowpath_count_;
     }
-    MarkSweepMarkObjectSlowPath visitor(this);
+    MarkSweepMarkObjectSlowPath visitor(this, holder, offset);
     // TODO: We already know that the object is not in the current_space_bitmap_ but MarkBitmap::Set
     // will check again.
     if (!mark_bitmap_->Set(obj, visitor)) {
@@ -456,9 +468,9 @@
 }
 
 // Used to mark objects when processing the mark stack. If an object is null, it is not marked.
-inline void MarkSweep::MarkObject(Object* obj) {
+inline void MarkSweep::MarkObject(Object* obj, Object* holder, MemberOffset offset) {
   if (obj != nullptr) {
-    MarkObjectNonNull(obj);
+    MarkObjectNonNull(obj, holder, offset);
   } else if (kCountMarkedObjects) {
     ++mark_null_count_;
   }
@@ -1209,7 +1221,7 @@
       Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
       Locks::heap_bitmap_lock_->AssertExclusiveHeld(Thread::Current());
     }
-    mark_sweep_->MarkObject(obj->GetFieldObject<mirror::Object>(offset));
+    mark_sweep_->MarkObject(obj->GetFieldObject<mirror::Object>(offset), obj, offset);
   }
 
  private:
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 7e1af7b..d29d87a 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -199,7 +199,8 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Marks an object.
-  void MarkObject(mirror::Object* obj)
+  void MarkObject(mirror::Object* obj, mirror::Object* holder = nullptr,
+                  MemberOffset offset = MemberOffset(0))
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -222,7 +223,8 @@
   static void VerifyImageRootVisitor(mirror::Object* root, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
-  void MarkObjectNonNull(mirror::Object* obj)
+  void MarkObjectNonNull(mirror::Object* obj, mirror::Object* holder = nullptr,
+                         MemberOffset offset = MemberOffset(0))
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 5dac985..f9740bb 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -244,5 +244,10 @@
   UNREACHABLE();
 }
 
+ArtField* Object::FindFieldByOffset(MemberOffset offset) {
+  return IsClass() ? ArtField::FindStaticFieldWithOffset(AsClass(), offset.Uint32Value())
+      : ArtField::FindInstanceFieldWithOffset(GetClass(), offset.Uint32Value());
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index f2d879f..5afe99f 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -439,6 +439,8 @@
   void VisitReferences(const Visitor& visitor, const JavaLangRefVisitor& ref_visitor)
       NO_THREAD_SAFETY_ANALYSIS;
 
+  ArtField* FindFieldByOffset(MemberOffset offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Used by object_test.
   static void SetHashCodeSeed(uint32_t new_seed);
   // Generate an identity hash code. Public for object test.