Refactor and improve GC root handling
Changed GcRoot to use compressed references. Changed root visiting to
use virtual functions instead of function pointers. Changed root visting
interface to be an array of roots instead of a single root at a time.
Added buffered root marking helper to avoid dispatch overhead.
Root marking seems a bit faster on EvaluateAndApplyChanges due to batch
marking. Pause times unaffected.
Mips64 is untested but might work, maybe.
Before:
MarkConcurrentRoots: Sum: 67.678ms 99% C.I. 2us-664.999us Avg: 161.138us Max: 671us
After:
MarkConcurrentRoots: Sum: 54.806ms 99% C.I. 2us-499.986us Avg: 136.333us Max: 602us
Bug: 19264997
Change-Id: I0a71ebb5928f205b9b3f7945b25db6489d5657ca
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index d1ce0bc..8902df8 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -309,19 +309,57 @@
reinterpret_cast<MarkCompact*>(arg)->DelayReferenceReferent(klass, ref);
}
-void MarkCompact::MarkRootCallback(Object** root, void* arg, const RootInfo& /*root_info*/) {
- reinterpret_cast<MarkCompact*>(arg)->MarkObject(*root);
-}
-
-void MarkCompact::UpdateRootCallback(Object** root, void* arg, const RootInfo& /*root_info*/) {
- mirror::Object* obj = *root;
- mirror::Object* new_obj = reinterpret_cast<MarkCompact*>(arg)->GetMarkedForwardAddress(obj);
- if (obj != new_obj) {
- *root = new_obj;
- DCHECK(new_obj != nullptr);
+void MarkCompact::VisitRoots(
+ mirror::Object*** roots, size_t count, const RootInfo& info ATTRIBUTE_UNUSED) {
+ for (size_t i = 0; i < count; ++i) {
+ MarkObject(*roots[i]);
}
}
+void MarkCompact::VisitRoots(
+ mirror::CompressedReference<mirror::Object>** roots, size_t count,
+ const RootInfo& info ATTRIBUTE_UNUSED) {
+ for (size_t i = 0; i < count; ++i) {
+ MarkObject(roots[i]->AsMirrorPtr());
+ }
+}
+
+class UpdateRootVisitor : public RootVisitor {
+ public:
+ explicit UpdateRootVisitor(MarkCompact* collector) : collector_(collector) {
+ }
+
+ void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info ATTRIBUTE_UNUSED)
+ OVERRIDE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+ for (size_t i = 0; i < count; ++i) {
+ mirror::Object* obj = *roots[i];
+ mirror::Object* new_obj = collector_->GetMarkedForwardAddress(obj);
+ if (obj != new_obj) {
+ *roots[i] = new_obj;
+ DCHECK(new_obj != nullptr);
+ }
+ }
+ }
+
+ void VisitRoots(mirror::CompressedReference<mirror::Object>** roots, size_t count,
+ const RootInfo& info ATTRIBUTE_UNUSED)
+ OVERRIDE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+ for (size_t i = 0; i < count; ++i) {
+ mirror::Object* obj = roots[i]->AsMirrorPtr();
+ mirror::Object* new_obj = collector_->GetMarkedForwardAddress(obj);
+ if (obj != new_obj) {
+ roots[i]->Assign(new_obj);
+ DCHECK(new_obj != nullptr);
+ }
+ }
+ }
+
+ private:
+ MarkCompact* const collector_;
+};
+
class UpdateObjectReferencesVisitor {
public:
explicit UpdateObjectReferencesVisitor(MarkCompact* collector) : collector_(collector) {
@@ -339,7 +377,8 @@
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
Runtime* runtime = Runtime::Current();
// Update roots.
- runtime->VisitRoots(UpdateRootCallback, this);
+ UpdateRootVisitor update_root_visitor(this);
+ runtime->VisitRoots(&update_root_visitor);
// Update object references in mod union tables and spaces.
for (const auto& space : heap_->GetContinuousSpaces()) {
// If the space is immune then we need to mark the references to other spaces.
@@ -396,7 +435,7 @@
// Marks all objects in the root set.
void MarkCompact::MarkRoots() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
- Runtime::Current()->VisitRoots(MarkRootCallback, this);
+ Runtime::Current()->VisitRoots(this);
}
mirror::Object* MarkCompact::MarkedForwardingAddressCallback(mirror::Object* obj, void* arg) {