Visit image roots for hprof

Bug: 19995360
Change-Id: I1f2989c8bccf508b1d47dfd0d7aee4c7bb275b56
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index b822613..656569c 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -507,6 +507,7 @@
 
     Env env = { this, output };
     runtime->VisitRoots(RootVisitor, &env);
+    runtime->VisitImageRoots(RootVisitor, &env);
     runtime->GetHeap()->VisitObjectsPaused(VisitObjectCallback, &env);
 
     output->StartNewRecord(HPROF_TAG_HEAP_DUMP_END, kHprofTime);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 23a7db6..b5d2e15 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -62,7 +62,7 @@
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
-#include "gc/space/space.h"
+#include "gc/space/space-inl.h"
 #include "handle_scope-inl.h"
 #include "image.h"
 #include "instrumentation.h"
@@ -1355,6 +1355,23 @@
   VisitConcurrentRoots(callback, arg, flags);
 }
 
+void Runtime::VisitImageRoots(RootCallback* callback, void* arg) {
+  for (auto* space : GetHeap()->GetContinuousSpaces()) {
+    if (space->IsImageSpace()) {
+      auto* image_space = space->AsImageSpace();
+      const auto& image_header = image_space->GetImageHeader();
+      for (size_t i = 0; i < ImageHeader::kImageRootsMax; ++i) {
+        auto* obj = image_header.GetImageRoot(static_cast<ImageHeader::ImageRoot>(i));
+        if (obj != nullptr) {
+          auto* after_obj = obj;
+          callback(&after_obj, arg, RootInfo(kRootStickyClass));
+          CHECK_EQ(after_obj, obj);
+        }
+      }
+    }
+  }
+}
+
 mirror::ObjectArray<mirror::ArtMethod>* Runtime::CreateDefaultImt(ClassLinker* cl) {
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 085335f..64b7183 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -298,6 +298,10 @@
   void VisitRoots(RootCallback* visitor, void* arg, VisitRootFlags flags = kVisitRootFlagAllRoots)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Visit image roots, only used for hprof since the GC uses the image space mod union table
+  // instead.
+  void VisitImageRoots(RootCallback* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Visit all of the roots we can do safely do concurrently.
   void VisitConcurrentRoots(RootCallback* visitor, void* arg,
                             VisitRootFlags flags = kVisitRootFlagAllRoots)