Index: runtime/vm/scavenger.cc |
=================================================================== |
--- runtime/vm/scavenger.cc (revision 37032) |
+++ runtime/vm/scavenger.cc (working copy) |
@@ -14,6 +14,7 @@ |
#include "vm/object.h" |
#include "vm/stack_frame.h" |
#include "vm/store_buffer.h" |
+#include "vm/thread.h" |
#include "vm/verifier.h" |
#include "vm/visitor.h" |
#include "vm/weak_table.h" |
@@ -285,7 +286,8 @@ |
// StoreBuffers. |
class VerifyStoreBufferPointerVisitor : public ObjectPointerVisitor { |
public: |
- VerifyStoreBufferPointerVisitor(Isolate* isolate, MemoryRegion* to) |
+ VerifyStoreBufferPointerVisitor(Isolate* isolate, |
+ const SemiSpace* to) |
: ObjectPointerVisitor(isolate), to_(to) {} |
void VisitPointers(RawObject** first, RawObject** last) { |
@@ -298,12 +300,87 @@ |
} |
private: |
- MemoryRegion* to_; |
+ const SemiSpace* to_; |
DISALLOW_COPY_AND_ASSIGN(VerifyStoreBufferPointerVisitor); |
}; |
+SemiSpace::SemiSpace(VirtualMemory* reserved) |
+ : reserved_(reserved), region_(NULL, 0) { |
+ if (reserved != NULL) { |
+ region_ = MemoryRegion(reserved_->address(), reserved_->size()); |
+ } |
+} |
+ |
+ |
+SemiSpace::~SemiSpace() { |
+ if (reserved_ != NULL) { |
+#if defined(DEBUG) |
+ memset(reserved_->address(), 0xf3, size()); |
+#endif // defined(DEBUG) |
+ delete reserved_; |
+ } |
+} |
+ |
+ |
+Mutex* SemiSpace::mutex_ = NULL; |
+SemiSpace* SemiSpace::cache_ = NULL; |
+ |
+ |
+void SemiSpace::InitOnce() { |
+ ASSERT(mutex_ == NULL); |
+ mutex_ = new Mutex(); |
+ ASSERT(mutex_ != NULL); |
+} |
+ |
+ |
+SemiSpace* SemiSpace::New(intptr_t size) { |
+ { |
+ MutexLocker locker(mutex_); |
+ if (cache_ != NULL && cache_->size() == size) { |
+ SemiSpace* result = cache_; |
+ cache_ = NULL; |
+ return result; |
+ } |
+ } |
+ if (size == 0) { |
+ return new SemiSpace(NULL); |
+ } else { |
+ VirtualMemory* reserved = VirtualMemory::Reserve(size); |
+ if ((reserved == NULL) || !reserved->Commit(VirtualMemory::kReadWrite)) { |
+ // TODO(koda): If cache_ is not empty, we could try to delete it. |
+ delete reserved; |
+ return NULL; |
+ } |
+#if defined(DEBUG) |
+ memset(reserved->address(), 0xf3, size); |
+#endif // defined(DEBUG) |
+ return new SemiSpace(reserved); |
+ } |
+} |
+ |
+ |
+void SemiSpace::Delete() { |
+ SemiSpace* old_cache = NULL; |
+ { |
+ MutexLocker locker(mutex_); |
+ old_cache = cache_; |
+ cache_ = this; |
+ } |
+ delete old_cache; |
+} |
+ |
+ |
+void SemiSpace::WriteProtect(bool read_only) { |
+ if (reserved_ != NULL) { |
+ bool success = reserved_->Protect( |
+ read_only ? VirtualMemory::kReadOnly : VirtualMemory::kReadWrite); |
+ ASSERT(success); |
+ } |
+} |
+ |
+ |
Scavenger::Scavenger(Heap* heap, |
intptr_t max_capacity_in_words, |
uword object_alignment) |
@@ -317,50 +394,26 @@ |
// going to use for forwarding pointers. |
ASSERT(Object::tags_offset() == 0); |
- if (max_capacity_in_words == 0) { |
- space_ = NULL; |
- to_ = new MemoryRegion(NULL, 0); |
- from_ = new MemoryRegion(NULL, 0); |
- } else { |
- // Allocate the virtual memory for this scavenge heap. |
- space_ = VirtualMemory::Reserve(max_capacity_in_words << kWordSizeLog2); |
- if (space_ == NULL) { |
- FATAL("Out of memory.\n"); |
- } |
- |
- // Allocate the entire space at the beginning. |
- space_->Commit(false); |
- |
- // Setup the semi spaces. |
- uword semi_space_size = space_->size() / 2; |
- ASSERT((semi_space_size & (VirtualMemory::PageSize() - 1)) == 0); |
- to_ = new MemoryRegion(space_->address(), semi_space_size); |
- uword middle = space_->start() + semi_space_size; |
- from_ = new MemoryRegion(reinterpret_cast<void*>(middle), semi_space_size); |
+ const intptr_t semi_space_size = (max_capacity_in_words / 2) * kWordSize; |
+ to_ = SemiSpace::New(semi_space_size); |
+ if (to_ == NULL) { |
+ FATAL("Out of memory.\n"); |
} |
+ from_ = NULL; |
- // Make sure that the two semi-spaces are aligned properly. |
- ASSERT(Utils::IsAligned(to_->start(), kObjectAlignment)); |
- ASSERT(Utils::IsAligned(from_->start(), kObjectAlignment)); |
- |
// Setup local fields. |
top_ = FirstObjectStart(); |
resolved_top_ = top_; |
end_ = to_->end(); |
survivor_end_ = FirstObjectStart(); |
- |
-#if defined(DEBUG) |
- memset(to_->pointer(), 0xf3, to_->size()); |
- memset(from_->pointer(), 0xf3, from_->size()); |
-#endif // defined(DEBUG) |
} |
Scavenger::~Scavenger() { |
- delete to_; |
- delete from_; |
- delete space_; |
+ ASSERT(!scavenging_); |
+ ASSERT(from_ == NULL); |
+ to_->Delete(); |
} |
@@ -370,9 +423,13 @@ |
} |
// Flip the two semi-spaces so that to_ is always the space for allocating |
// objects. |
- MemoryRegion* temp = from_; |
from_ = to_; |
- to_ = temp; |
+ to_ = SemiSpace::New(from_->size()); |
+ if (to_ == NULL) { |
+ // TODO(koda): We could try to recover (collect old space, wait for another |
+ // isolate to finish scavenge, etc.). |
+ FATAL("Out of memory.\n"); |
+ } |
top_ = FirstObjectStart(); |
resolved_top_ = top_; |
end_ = to_->end(); |
@@ -399,9 +456,9 @@ |
#if defined(DEBUG) |
VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_); |
heap_->IterateOldPointers(&verify_store_buffer_visitor); |
- |
- memset(from_->pointer(), 0xf3, from_->size()); |
#endif // defined(DEBUG) |
+ from_->Delete(); |
+ from_ = NULL; |
if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { |
(isolate->gc_epilogue_callback())(); |
} |
@@ -739,10 +796,9 @@ |
void Scavenger::WriteProtect(bool read_only) { |
- if (space_ != NULL) { |
- space_->Protect( |
- read_only ? VirtualMemory::kReadOnly : VirtualMemory::kReadWrite); |
- } |
+ ASSERT(!scavenging_); |
+ ASSERT(from_ == NULL); |
+ to_->WriteProtect(read_only); |
} |