- 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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user