summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/card_table.cc18
-rw-r--r--src/card_table.h12
-rw-r--r--src/class_linker.cc4
-rw-r--r--src/heap.cc48
-rw-r--r--src/heap.h2
-rw-r--r--src/mark_sweep.cc98
-rw-r--r--src/mark_sweep.h15
-rw-r--r--src/object.h3
8 files changed, 150 insertions, 50 deletions
diff --git a/src/card_table.cc b/src/card_table.cc
index d442306b04..0eac91f44d 100644
--- a/src/card_table.cc
+++ b/src/card_table.cc
@@ -22,6 +22,7 @@
#include "heap_bitmap.h"
#include "logging.h"
#include "runtime.h"
+#include "space.h"
#include "utils.h"
namespace art {
@@ -80,6 +81,18 @@ CardTable* CardTable::Create(const byte* heap_begin, size_t heap_capacity) {
return new CardTable(mem_map.release(), biased_begin, offset);
}
+void CardTable::ClearNonImageSpaceCards(Heap* heap) {
+ // TODO: clear just the range of the table that has been modified
+ const std::vector<Space*>& spaces = heap->GetSpaces();
+ for (size_t i = 0; i < spaces.size(); ++i) {
+ if (!spaces[i]->IsImageSpace()) {
+ byte* card_start = CardFromAddr(spaces[i]->Begin());
+ byte* card_end = CardFromAddr(spaces[i]->End());
+ memset(reinterpret_cast<void*>(card_start), GC_CARD_CLEAN, card_end - card_start);
+ }
+ }
+}
+
void CardTable::ClearCardTable() {
// TODO: clear just the range of the table that has been modified
memset(mem_map_->Begin(), GC_CARD_CLEAN, mem_map_->Size());
@@ -97,8 +110,7 @@ void CardTable::CheckAddrIsInCardTable(const byte* addr) const {
}
}
-void CardTable::Scan(byte* heap_begin, byte* heap_end, Callback* visitor, void* arg) const {
- Heap* heap = Runtime::Current()->GetHeap();
+void CardTable::Scan(HeapBitmap* bitmap, byte* heap_begin, byte* heap_end, Callback* visitor, void* arg) const {
byte* card_cur = CardFromAddr(heap_begin);
byte* card_end = CardFromAddr(heap_end);
while (card_cur < card_end) {
@@ -113,7 +125,7 @@ void CardTable::Scan(byte* heap_begin, byte* heap_end, Callback* visitor, void*
}
if (run > 0) {
byte* run_end = &card_cur[run];
- heap->GetLiveBits()->VisitRange(reinterpret_cast<uintptr_t>(AddrFromCard(run_start)),
+ bitmap->VisitRange(reinterpret_cast<uintptr_t>(AddrFromCard(run_start)),
reinterpret_cast<uintptr_t>(AddrFromCard(run_end)),
visitor, arg);
}
diff --git a/src/card_table.h b/src/card_table.h
index 70d033e0bd..9cfa70b905 100644
--- a/src/card_table.h
+++ b/src/card_table.h
@@ -24,6 +24,8 @@
namespace art {
+class Heap;
+class HeapBitmap;
class Object;
#define GC_CARD_SHIFT 7
@@ -58,20 +60,22 @@ class CardTable {
// For every dirty card between begin and end invoke the visitor with the specified argument
typedef void Callback(Object* obj, void* arg);
- void Scan(byte* begin, byte* end, Callback* visitor, void* arg) const;
+ void Scan(HeapBitmap* bitmap, byte* begin, byte* end, Callback* visitor, void* arg) const;
// Assertion used to check the given address is covered by the card table
void CheckAddrIsInCardTable(const byte* addr) const;
+ // Resets all of the bytes in the card table to clean.
+ void ClearCardTable();
+
+ // Resets all of the bytes in the card table to clean.
+ void ClearNonImageSpaceCards(Heap* heap);
private:
CardTable(MemMap* begin, byte* biased_begin, size_t offset) :
mem_map_(begin), biased_begin_(biased_begin), offset_(offset) {}
- // Resets all of the bytes in the card table to clean.
- void ClearCardTable();
-
// Returns the address of the relevant byte in the card table, given an address on the heap.
byte* CardFromAddr(const void *addr) const {
byte *cardAddr = biased_begin_ + ((uintptr_t)addr >> GC_CARD_SHIFT);
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 000e2a5280..98d5fe0c9d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -939,7 +939,9 @@ void ClassLinker::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
visitor(it->second, arg);
}
- // Note. we deliberately ignore the class roots in the image (held in image_classes_)
+
+ // We deliberately ignore the class roots in the image since we
+ // handle image roots by using the MS/CMS rescanning of dirty cards.
}
visitor(array_iftable_, arg);
diff --git a/src/heap.cc b/src/heap.cc
index 75b11ea4b3..eb4f3e8cef 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -459,7 +459,7 @@ Object* Heap::AllocateLocked(AllocSpace* space, size_t alloc_size) {
// Fail impossible allocations
if (alloc_size > space->Capacity()) {
// On failure collect soft references
- CollectGarbageInternal(true);
+ CollectGarbageInternal(false, true);
return NULL;
}
@@ -486,7 +486,7 @@ Object* Heap::AllocateLocked(AllocSpace* space, size_t alloc_size) {
++Runtime::Current()->GetStats()->gc_for_alloc_count;
++Thread::Current()->GetStats()->gc_for_alloc_count;
}
- CollectGarbageInternal(false);
+ CollectGarbageInternal(false, false);
ptr = space->AllocWithoutGrowth(alloc_size);
if (ptr != NULL) {
return ptr;
@@ -512,7 +512,7 @@ Object* Heap::AllocateLocked(AllocSpace* space, size_t alloc_size) {
// OLD-TODO: wait for the finalizers from the previous GC to finish
VLOG(gc) << "Forcing collection of SoftReferences for " << PrettySize(alloc_size) << " allocation";
- CollectGarbageInternal(true);
+ CollectGarbageInternal(false, true);
ptr = space->AllocWithGrowth(alloc_size);
if (ptr != NULL) {
return ptr;
@@ -575,10 +575,10 @@ int64_t Heap::CountInstances(Class* c, bool count_assignable) {
void Heap::CollectGarbage(bool clear_soft_references) {
ScopedHeapLock heap_lock;
- CollectGarbageInternal(clear_soft_references);
+ CollectGarbageInternal(false, clear_soft_references);
}
-void Heap::CollectGarbageInternal(bool clear_soft_references) {
+void Heap::CollectGarbageInternal(bool concurrent, bool clear_soft_references) {
lock_->AssertHeld();
ThreadList* thread_list = Runtime::Current()->GetThreadList();
@@ -598,31 +598,43 @@ void Heap::CollectGarbageInternal(bool clear_soft_references) {
mark_sweep.MarkRoots();
timings.AddSplit("MarkRoots");
- mark_sweep.ScanDirtyImageRoots();
- timings.AddSplit("DirtyImageRoots");
-
// Roots are marked on the bitmap and the mark_stack is empty
DCHECK(mark_sweep.IsMarkStackEmpty());
- // TODO: if concurrent
- // unlock heap
- // thread_list->ResumeAll();
+ if (concurrent) {
+ Unlock();
+ thread_list->ResumeAll();
+ }
// Recursively mark all bits set in the non-image mark bitmap
mark_sweep.RecursiveMark();
timings.AddSplit("RecursiveMark");
- // TODO: if concurrent
- // lock heap
- // thread_list->SuspendAll();
- // re-mark root set
- // scan dirty objects
+ if (concurrent) {
+ Lock();
+ thread_list->SuspendAll();
+
+ // Re-mark root set.
+ mark_sweep.ReMarkRoots();
+ timings.AddSplit("ReMarkRoots");
+ }
+
+ // Scan dirty objects, this is required even if we are not doing a
+ // concurrent GC since we use the card table to locate image roots.
+ mark_sweep.RecursiveMarkDirtyObjects();
+ timings.AddSplit("RecursiveMarkDirtyObjects");
mark_sweep.ProcessReferences(clear_soft_references);
timings.AddSplit("ProcessReferences");
- // TODO: if concurrent
- // swap bitmaps
+ // TODO: swap live and marked bitmaps
+ // Note: Need to be careful about image spaces if we do this since not
+ // everything image space will be marked, resulting in things not being
+ // marked as live anymore.
+
+ // Verify that we only reach marked objects from the image space
+ mark_sweep.VerifyImageRoots();
+ timings.AddSplit("VerifyImageRoots");
mark_sweep.Sweep();
timings.AddSplit("Sweep");
diff --git a/src/heap.h b/src/heap.h
index d368158575..de3caa2d7b 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -233,7 +233,7 @@ class Heap {
void RecordAllocationLocked(AllocSpace* space, const Object* object);
void RecordImageAllocations(Space* space);
- void CollectGarbageInternal(bool clear_soft_references);
+ void CollectGarbageInternal(bool concurrent, bool clear_soft_references);
// Given the current contents of the alloc space, increase the allowed heap footprint to match
// the target utilization ratio. This should only be called immediately after a full garbage
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index 72b9ddb14e..d070a575f2 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -59,6 +59,7 @@ void MarkSweep::Init() {
mark_stack_->Reset();
// TODO: if concurrent, clear the card table.
+ heap_->GetCardTable()->ClearNonImageSpaceCards(heap_);
// TODO: if concurrent, enable card marking in compiler
@@ -101,6 +102,13 @@ void MarkSweep::MarkObjectVisitor(const Object* root, void* arg) {
mark_sweep->MarkObject0(root, false);
}
+void MarkSweep::ReMarkObjectVisitor(const Object* root, void* arg) {
+ DCHECK(root != NULL);
+ DCHECK(arg != NULL);
+ MarkSweep* mark_sweep = reinterpret_cast<MarkSweep*>(arg);
+ mark_sweep->MarkObject0(root, true);
+}
+
// Marks all objects in the root set.
void MarkSweep::MarkRoots() {
Runtime::Current()->VisitRoots(MarkObjectVisitor, this);
@@ -110,7 +118,7 @@ void MarkSweep::ScanImageRootVisitor(Object* root, void* arg) {
DCHECK(root != NULL);
DCHECK(arg != NULL);
MarkSweep* mark_sweep = reinterpret_cast<MarkSweep*>(arg);
- DCHECK(mark_sweep->finger_ == NULL); // no point to check finger if it is NULL
+ //DCHECK(mark_sweep->finger_ == NULL); // no point to check finger if it is NULL
mark_sweep->MarkObject0(root, false);
mark_sweep->ScanObject(root);
}
@@ -123,7 +131,7 @@ void MarkSweep::ScanDirtyImageRoots() {
if (spaces[i]->IsImageSpace()) {
byte* begin = spaces[i]->Begin();
byte* end = spaces[i]->End();
- card_table->Scan(begin, end, ScanImageRootVisitor, this);
+ card_table->Scan(heap_->GetLiveBits(), begin, end, ScanImageRootVisitor, this);
}
}
}
@@ -140,6 +148,48 @@ void MarkSweep::ScanBitmapCallback(Object* obj, void* finger, void* arg) {
mark_sweep->ScanObject(obj);
}
+void MarkSweep::ScanDirtyCardCallback(Object* obj, void* arg) {
+ MarkSweep* mark_sweep = reinterpret_cast<MarkSweep*>(arg);
+ mark_sweep->ScanObject(obj);
+}
+
+void MarkSweep::ScanGrayObjects() {
+ const std::vector<Space*>& spaces = heap_->GetSpaces();
+ CardTable* card_table = heap_->GetCardTable();
+ for (size_t i = 0; i < spaces.size(); ++i) {
+ byte* begin = spaces[i]->Begin();
+ byte* end = spaces[i]->End();
+ // Normally, we only need to scan the black dirty objects
+ // But for image spaces, the roots will not be black objects.
+ // To address this we just scan the live bits instead of the mark bits.
+ if (UNLIKELY(spaces[i]->IsImageSpace())) {
+ // Image roots may not be marked so we may need to mark them.
+ // TODO: optimize this by offsetting some of the work to init.
+ card_table->Scan(heap_->GetLiveBits(), begin, end, ScanImageRootVisitor, this);
+ } else {
+ card_table->Scan(heap_->GetMarkBits(), begin, end, ScanDirtyCardCallback, this);
+ }
+ }
+}
+
+void MarkSweep::VerifyImageRoots() {
+ // Verify roots ensures that all the references inside the image space point
+ // objects which are either in the image space or marked objects in the alloc
+ // space
+#ifndef NDEBUG
+ void* arg = reinterpret_cast<void*>(this);
+ const std::vector<Space*>& spaces = heap_->GetSpaces();
+ for (size_t i = 0; i < spaces.size(); ++i) {
+ if (spaces[i]->IsImageSpace()) {
+ uintptr_t begin = reinterpret_cast<uintptr_t>(spaces[i]->Begin());
+ uintptr_t end = reinterpret_cast<uintptr_t>(spaces[i]->End());
+ mark_bitmap_->ScanWalk(begin, end, &MarkSweep::CheckBitmapCallback, arg);
+ }
+ }
+ finger_ = reinterpret_cast<Object*>(~0);
+#endif
+}
+
// Populates the mark stack based on the set of marked objects and
// recursively marks until the mark stack is emptied.
void MarkSweep::RecursiveMark() {
@@ -154,29 +204,22 @@ void MarkSweep::RecursiveMark() {
void* arg = reinterpret_cast<void*>(this);
const std::vector<Space*>& spaces = heap_->GetSpaces();
for (size_t i = 0; i < spaces.size(); ++i) {
-#ifndef NDEBUG
uintptr_t begin = reinterpret_cast<uintptr_t>(spaces[i]->Begin());
uintptr_t end = reinterpret_cast<uintptr_t>(spaces[i]->End());
- if (!spaces[i]->IsImageSpace()) {
- mark_bitmap_->ScanWalk(begin, end, &MarkSweep::ScanBitmapCallback, arg);
- } else {
- mark_bitmap_->ScanWalk(begin, end, &MarkSweep::CheckBitmapCallback, arg);
- }
-#else
- if (!spaces[i]->IsImageSpace()) {
- uintptr_t begin = reinterpret_cast<uintptr_t>(spaces[i]->Begin());
- uintptr_t end = reinterpret_cast<uintptr_t>(spaces[i]->End());
- mark_bitmap_->ScanWalk(begin, end, &MarkSweep::ScanBitmapCallback, arg);
- }
-#endif
+ mark_bitmap_->ScanWalk(begin, end, &MarkSweep::ScanBitmapCallback, arg);
}
finger_ = reinterpret_cast<Object*>(~0);
// TODO: tune the frequency of emptying the mark stack
ProcessMarkStack();
}
+void MarkSweep::RecursiveMarkDirtyObjects() {
+ ScanGrayObjects();
+ ProcessMarkStack();
+}
+
void MarkSweep::ReMarkRoots() {
- UNIMPLEMENTED(FATAL);
+ Runtime::Current()->VisitRoots(ReMarkObjectVisitor, this);
}
void MarkSweep::SweepJniWeakGlobals() {
@@ -312,12 +355,31 @@ inline void MarkSweep::CheckReference(const Object* obj, const Object* ref, Memb
AllocSpace* alloc_space = heap_->GetAllocSpace();
if (alloc_space->Contains(ref)) {
bool is_marked = mark_bitmap_->Test(ref);
+
if (!is_marked) {
LOG(INFO) << *alloc_space;
LOG(WARNING) << (is_static ? "Static ref'" : "Instance ref'") << PrettyTypeOf(ref)
<< "' (" << reinterpret_cast<const void*>(ref) << ") in '" << PrettyTypeOf(obj)
<< "' (" << reinterpret_cast<const void*>(obj) << ") at offset "
<< reinterpret_cast<void*>(offset.Int32Value()) << " wasn't marked";
+
+ const Class* klass = is_static ? obj->AsClass() : obj->GetClass();
+ DCHECK(klass != NULL);
+ const ObjectArray<Field>* fields = is_static ? klass->GetSFields() : klass->GetIFields();
+ DCHECK(fields != NULL);
+ bool found = false;
+ for (int32_t i = 0; i < fields->GetLength(); ++i) {
+ const Field* cur = fields->Get(i);
+ if (cur->GetOffset().Int32Value() == offset.Int32Value()) {
+ LOG(WARNING) << "Field referencing the alloc space was " << PrettyField(cur);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ LOG(WARNING) << "Could not find field in object alloc space with offset " << offset.Int32Value();
+ }
+
bool obj_marked = heap_->GetCardTable()->IsDirty(obj);
if (!obj_marked) {
LOG(WARNING) << "Object '" << PrettyTypeOf(obj) << "' "
@@ -488,10 +550,6 @@ void MarkSweep::ProcessMarkStack() {
}
}
-void MarkSweep::ScanDirtyObjects() {
- ProcessMarkStack();
-}
-
// Walks the reference list marking any references subject to the
// reference clearing policy. References with a black referent are
// removed from the list. References with white referents biased
diff --git a/src/mark_sweep.h b/src/mark_sweep.h
index 7fda6eae60..43ed9b6b2d 100644
--- a/src/mark_sweep.h
+++ b/src/mark_sweep.h
@@ -40,9 +40,12 @@ class MarkSweep {
// Marks the root set at the start of a garbage collection.
void MarkRoots();
- // Marks the roots in the image space on dirty cards
+ // Marks the roots in the image space on dirty cards.
void ScanDirtyImageRoots();
+ // Verify that image roots point to only marked objects within the alloc space.
+ void VerifyImageRoots();
+
bool IsMarkStackEmpty() const {
return mark_stack_->IsEmpty();
}
@@ -50,6 +53,10 @@ class MarkSweep {
// Builds a mark stack and recursively mark until it empties.
void RecursiveMark();
+ // Builds a mark stack with objects on dirty cards and recursively mark
+ // until it empties.
+ void RecursiveMarkDirtyObjects();
+
// Remarks the root set after completing the concurrent mark.
void ReMarkRoots();
@@ -79,8 +86,12 @@ class MarkSweep {
static void MarkObjectVisitor(const Object* root, void* arg);
+ static void ReMarkObjectVisitor(const Object* root, void* arg);
+
static void ScanImageRootVisitor(Object* root, void* arg);
+ static void ScanDirtyCardCallback(Object* obj, void* arg);
+
// Marks an object.
void MarkObject(const Object* obj);
@@ -130,7 +141,7 @@ class MarkSweep {
void CheckOther(const Object* obj);
// Blackens objects grayed during a garbage collection.
- void ScanDirtyObjects();
+ void ScanGrayObjects();
// Schedules an unmarked object for reference processing.
void DelayReferenceReferent(Object* reference);
diff --git a/src/object.h b/src/object.h
index e787933744..9ad02a852d 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1676,7 +1676,7 @@ class MANAGED Class : public StaticStorageBase {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable, false);
}
- // Get instance fields
+ // Get instance fields of the class (See also GetSFields).
ObjectArray<Field>* GetIFields() const {
DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Field>*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
@@ -1751,6 +1751,7 @@ class MANAGED Class : public StaticStorageBase {
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), new_num, false);
}
+ // Gets the static fields of the class.
ObjectArray<Field>* GetSFields() const {
DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Field>*>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);