- Implement a simple old-generation marker.

Review URL: http://codereview.chromium.org//8761006

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@1962 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
iposva@google.com
2011-12-01 02:11:40 +00:00
parent e36306f19e
commit 3117f4cbfc
9 changed files with 377 additions and 24 deletions
+3
View File
@@ -6,3 +6,6 @@ prefix vm
# When a spawned isolate throws an uncaught exception, we terminate the vm.
RunLoop_Exception: Fail
# Partially implemented old generation GC.
OldGC: CRASH
+207
View File
@@ -0,0 +1,207 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/gc_marker.h"
#include "vm/allocation.h"
#include "vm/isolate.h"
#include "vm/pages.h"
#include "vm/raw_object.h"
#include "vm/stack_frame.h"
#include "vm/visitor.h"
namespace dart {
// A simple chunked marking stack.
class MarkingStack : public ValueObject {
public:
MarkingStack()
: head_(new MarkingStackChunk()),
empty_chunks_(NULL),
marking_stack_(NULL),
top_(0) {
marking_stack_ = head_->MarkingStackChunkMemory();
}
~MarkingStack() {
// TODO(iposva): Consider caching a couple emtpy marking stack chunks.
ASSERT(IsEmpty());
delete head_;
MarkingStackChunk* next;
while (empty_chunks_ != NULL) {
next = empty_chunks_->next();
delete empty_chunks_;
empty_chunks_ = next;
}
}
bool IsEmpty() const {
return IsMarkingStackChunkEmpty() && (head_->next() == NULL);
}
void Push(RawObject* value) {
ASSERT(!IsMarkingStackChunkFull());
marking_stack_[top_] = value;
top_++;
if (IsMarkingStackChunkFull()) {
MarkingStackChunk* new_chunk;
if (empty_chunks_ == NULL) {
new_chunk = new MarkingStackChunk();
} else {
new_chunk = empty_chunks_;
empty_chunks_ = new_chunk->next();
}
new_chunk->set_next(head_);
head_ = new_chunk;
marking_stack_ = head_->MarkingStackChunkMemory();
top_ = 0;
}
}
RawObject* Pop() {
ASSERT(head_ != NULL);
ASSERT(!IsEmpty());
if (IsMarkingStackChunkEmpty()) {
MarkingStackChunk* empty_chunk = head_;
head_ = head_->next();
empty_chunk->set_next(empty_chunks_);
empty_chunks_ = empty_chunk;
marking_stack_ = head_->MarkingStackChunkMemory();
top_ = MarkingStackChunk::kMarkingStackChunkSize;
}
top_--;
return marking_stack_[top_];
}
private:
class MarkingStackChunk {
public:
MarkingStackChunk() : next_(NULL) {}
~MarkingStackChunk() {}
RawObject** MarkingStackChunkMemory() {
return &memory_[0];
}
MarkingStackChunk* next() const { return next_; }
void set_next(MarkingStackChunk* value) { next_ = value; }
static const uint32_t kMarkingStackChunkSize = 1024;
private:
RawObject* memory_[kMarkingStackChunkSize];
MarkingStackChunk* next_;
DISALLOW_COPY_AND_ASSIGN(MarkingStackChunk);
};
bool IsMarkingStackChunkFull() const {
return top_ == MarkingStackChunk::kMarkingStackChunkSize;
}
bool IsMarkingStackChunkEmpty() const {
return top_ == 0;
}
MarkingStackChunk* head_;
MarkingStackChunk* empty_chunks_;
RawObject** marking_stack_;
uint32_t top_;
DISALLOW_COPY_AND_ASSIGN(MarkingStack);
};
class MarkingVisitor : public ObjectPointerVisitor {
public:
MarkingVisitor(Heap* heap, PageSpace* page_space, MarkingStack* marking_stack)
: heap_(heap),
vm_heap_(Dart::vm_isolate()->heap()),
page_space_(page_space),
marking_stack_(marking_stack) {}
MarkingStack* marking_stack() const { return marking_stack_; }
void VisitPointers(RawObject** first, RawObject** last) {
for (RawObject** current = first; current <= last; current++) {
MarkObject(*current);
}
}
private:
void MarkAndPush(RawObject* raw_obj) {
ASSERT(raw_obj->IsHeapObject());
// Mark the object and push it on the marking stack.
ASSERT(!raw_obj->IsMarked());
RawClass* raw_class = raw_obj->ptr()->class_;
raw_obj->SetMarkBit();
marking_stack_->Push(raw_obj);
// TODO(iposva): Should we mark the classes early?
MarkObject(raw_class);
}
void MarkObject(RawObject* raw_obj) {
// Fast exit if the raw object is a Smi.
if (!raw_obj->IsHeapObject()) return;
// Fast exit if the raw object is marked.
if (raw_obj->IsMarked()) return;
// Skip over new objects, but verify consistency of heap while at it.
if (raw_obj->IsNewObject()) {
// TODO(iposva): Add consistency check.
return;
}
uword raw_addr = RawObject::ToAddr(raw_obj);
// TODO(iposva): Premark vm_isolate objects, to avoid this extra check here.
if (vm_heap_->Contains(raw_addr)) {
return;
}
// TODO(iposva): merge old and code spaces.
// ASSERT(page_space_->Contains(raw_addr));
MarkAndPush(raw_obj);
}
Heap* heap_;
Heap* vm_heap_;
PageSpace* page_space_;
MarkingStack* marking_stack_;
DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitor);
};
void GCMarker::Prologue(Isolate* isolate) {
// Nothing to do at the moment.
}
void GCMarker::IterateRoots(Isolate* isolate, MarkingVisitor* visitor) {
isolate->VisitObjectPointers(visitor,
StackFrameIterator::kDontValidateFrames);
heap_->IterateNewPointers(visitor);
}
void GCMarker::DrainMarkingStack(Isolate* isolate, MarkingVisitor* visitor) {
while (!visitor->marking_stack()->IsEmpty()) {
RawObject* raw_obj = visitor->marking_stack()->Pop();
raw_obj->VisitPointers(visitor);
}
}
void GCMarker::MarkObjects(Isolate* isolate, PageSpace* page_space) {
MarkingStack marking_stack;
Prologue(isolate);
MarkingVisitor mark(heap_, page_space, &marking_stack);
IterateRoots(isolate, &mark);
DrainMarkingStack(isolate, &mark);
}
} // namespace dart
+39
View File
@@ -0,0 +1,39 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef VM_GC_MARKER_H_
#define VM_GC_MARKER_H_
#include "vm/allocation.h"
namespace dart {
// Forward declarations.
class Heap;
class Isolate;
class MarkingVisitor;
class PageSpace;
// The class GCMarker is used to mark reachable old generation objects as part
// of the mark-sweep collection. The marking bit used is defined in RawObject.
class GCMarker : public ValueObject {
public:
explicit GCMarker(Heap* heap) : heap_(heap) { }
~GCMarker() { }
void MarkObjects(Isolate* isolate, PageSpace* page_space);
private:
void Prologue(Isolate* isolate);
void IterateRoots(Isolate* isolate, MarkingVisitor* visitor);
void DrainMarkingStack(Isolate* isolate, MarkingVisitor* visitor);
Heap* heap_;
DISALLOW_IMPLICIT_CONSTRUCTORS(GCMarker);
};
} // namespace dart
#endif // VM_GC_MARKER_H_
+47 -16
View File
@@ -103,6 +103,53 @@ bool Heap::CodeContains(uword addr) const {
}
void Heap::IterateNewPointers(ObjectPointerVisitor* visitor) {
new_space_->VisitObjectPointers(visitor);
}
void Heap::IterateOldPointers(ObjectPointerVisitor* visitor) {
old_space_->VisitObjectPointers(visitor);
code_space_->VisitObjectPointers(visitor);
}
void Heap::CollectGarbage(Space space) {
switch (space) {
case kNew:
new_space_->Scavenge();
break;
case kOld:
old_space_->MarkSweep();
break;
case kExecutable:
UNIMPLEMENTED();
code_space_->MarkSweep();
break;
default:
UNREACHABLE();
}
}
void Heap::CollectAllGarbage() {
new_space_->Scavenge();
old_space_->MarkSweep();
// TODO(iposva): Merge old and code space.
// code_space_->MarkSweep();
}
uword Heap::TopAddress() {
return reinterpret_cast<uword>(new_space_->TopAddress());
}
uword Heap::EndAddress() {
return reinterpret_cast<uword>(new_space_->EndAddress());
}
void Heap::Init(Isolate* isolate) {
ASSERT(isolate->heap() == NULL);
Heap* heap = new Heap();
@@ -120,22 +167,6 @@ bool Heap::Verify() const {
}
void Heap::IterateOldPointers(ObjectPointerVisitor* visitor) {
old_space_->VisitObjectPointers(visitor);
code_space_->VisitObjectPointers(visitor);
}
uword Heap::TopAddress() {
return reinterpret_cast<uword>(new_space_->TopAddress());
}
uword Heap::EndAddress() {
return reinterpret_cast<uword>(new_space_->EndAddress());
}
#if defined(DEBUG)
NoGCScope::NoGCScope() : StackResource(Isolate::Current()) {
isolate()->IncrementNoGCScopeDepth();
+11 -6
View File
@@ -53,19 +53,24 @@ class Heap {
bool Contains(uword addr) const;
bool CodeContains(uword addr) const;
// Initialize the heap and register it with the isolate.
static void Init(Isolate* isolate);
// Verify that all pointers in the heap point to the heap.
bool Verify() const;
// Visit all pointers in the space.
void IterateNewPointers(ObjectPointerVisitor* visitor);
void IterateOldPointers(ObjectPointerVisitor* visitor);
void CollectGarbage(Space space);
void CollectAllGarbage();
// Accessors for inlined allocation in generated code.
uword TopAddress();
uword EndAddress();
static intptr_t new_space_offset() { return OFFSET_OF(Heap, new_space_); }
// Initialize the heap and register it with the isolate.
static void Init(Isolate* isolate);
// Verify that all pointers in the heap point to the heap.
bool Verify() const;
private:
Heap();
+28 -1
View File
@@ -2,4 +2,31 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// TODO(iposva): Intentionally left blank for now.
#include "vm/assert.h"
#include "vm/globals.h"
#include "vm/heap.h"
#include "vm/unit_test.h"
namespace dart {
#if defined(TARGET_ARCH_IA32)
TEST_CASE(OldGC) {
const char* kScriptChars =
"class HeapTester {\n"
" static void main() {\n"
" return [1, 2, 3];\n"
" }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle result = Dart_InvokeStatic(lib,
Dart_NewString("HeapTester"),
Dart_NewString("main"),
0, NULL);
EXPECT_VALID(result);
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
heap->CollectGarbage(Heap::kOld);
}
#endif // TARGET_ARCH_IA32
}
+31 -1
View File
@@ -5,6 +5,7 @@
#include "vm/pages.h"
#include "vm/assert.h"
#include "vm/gc_marker.h"
#include "vm/object.h"
#include "vm/virtual_memory.h"
@@ -55,7 +56,9 @@ PageSpace::PageSpace(Heap* heap, intptr_t max_capacity, bool is_executable)
max_capacity_(max_capacity),
capacity_(0),
in_use_(0),
is_executable_(is_executable) { }
count_(0),
is_executable_(is_executable),
sweeping_(false) { }
PageSpace::~PageSpace() {
@@ -174,4 +177,31 @@ void PageSpace::VisitObjectPointers(ObjectPointerVisitor* visitor) const {
}
}
void PageSpace::MarkSweep() {
// MarkSweep is not reentrant. Make sure that is the case.
ASSERT(!sweeping_);
sweeping_ = true;
Isolate* isolate = Isolate::Current();
NoHandleScope no_handles(isolate);
Timer timer(FLAG_verbose_gc, "MarkSweep");
timer.Start();
// Mark all reachable old-gen objects.
GCMarker marker(heap_);
marker.MarkObjects(isolate, this);
UNIMPLEMENTED();
timer.Stop();
if (FLAG_verbose_gc) {
OS::PrintErr("Mark-Sweep[%d]: %dus\n", count_, timer.TotalElapsedTime());
}
count_++;
// Done, reset the marker.
ASSERT(sweeping_);
sweeping_ = false;
}
} // namespace dart
+9
View File
@@ -85,6 +85,9 @@ class PageSpace {
void VisitObjectPointers(ObjectPointerVisitor* visitor) const;
// Collect the garbage in the page space using mark-sweep.
void MarkSweep();
private:
static const intptr_t kAllocatablePageSize = kPageSize - sizeof(HeapPage);
@@ -105,8 +108,14 @@ class PageSpace {
intptr_t capacity_;
intptr_t in_use_;
// Old-gen GC cycle count.
int count_;
bool is_executable_;
// Keep track whether a MarkSweep is currently running.
bool sweeping_;
DISALLOW_IMPLICIT_CONSTRUCTORS(PageSpace);
};
+2
View File
@@ -103,6 +103,8 @@
'flags.cc',
'flags.h',
'flags_test.cc',
'gc_marker.cc',
'gc_marker.h',
'gdbjit_linux.cc',
'gdbjit_linux.h',
'globals.h',