Use emergency memory in the case of out of memory during evacuation.
authorhpayer@chromium.org <hpayer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Jul 2014 08:55:25 +0000 (08:55 +0000)
committerhpayer@chromium.org <hpayer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Jul 2014 08:55:25 +0000 (08:55 +0000)
BUG=395314
LOG=y
R=jarin@chromium.org

Review URL: https://codereview.chromium.org/431563002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22695 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/mark-compact.cc
src/spaces.cc
src/spaces.h

index 81361f0..f75db47 100644 (file)
@@ -3106,6 +3106,12 @@ void MarkCompactCollector::EvacuateLiveObjectsFromPage(Page* p) {
       HeapObject* target_object;
       AllocationResult allocation = space->AllocateRaw(size);
       if (!allocation.To(&target_object)) {
+        // If allocation failed, use emergency memory and re-try allocation.
+        CHECK(space->HasEmergencyMemory());
+        space->UseEmergencyMemory();
+        allocation = space->AllocateRaw(size);
+      }
+      if (!allocation.To(&target_object)) {
         // OS refused to give us memory.
         V8::FatalProcessOutOfMemory("Evacuation");
         return;
@@ -3130,10 +3136,16 @@ void MarkCompactCollector::EvacuatePages() {
            p->IsFlagSet(Page::RESCAN_ON_EVACUATION));
     ASSERT(static_cast<int>(p->parallel_sweeping()) ==
            MemoryChunk::SWEEPING_DONE);
+    PagedSpace* space = static_cast<PagedSpace*>(p->owner());
+    // Allocate emergency memory for the case when compaction fails due to out
+    // of memory.
+    if (!space->HasEmergencyMemory()) {
+      space->CreateEmergencyMemory();
+    }
     if (p->IsEvacuationCandidate()) {
-      // During compaction we might have to request a new page.
-      // Check that space still have room for that.
-      if (static_cast<PagedSpace*>(p->owner())->CanExpand()) {
+      // During compaction we might have to request a new page. Check that we
+      // have an emergency page and the space still has room for that.
+      if (space->HasEmergencyMemory() && space->CanExpand()) {
         EvacuateLiveObjectsFromPage(p);
       } else {
         // Without room for expansion evacuation is not guaranteed to succeed.
@@ -3144,7 +3156,17 @@ void MarkCompactCollector::EvacuatePages() {
           page->ClearEvacuationCandidate();
           page->SetFlag(Page::RESCAN_ON_EVACUATION);
         }
-        return;
+        break;
+      }
+    }
+  }
+  if (npages > 0) {
+    // Release emergency memory.
+    PagedSpaces spaces(heap());
+    for (PagedSpace* space = spaces.next(); space != NULL;
+         space = spaces.next()) {
+      if (space->HasEmergencyMemory()) {
+        space->FreeEmergencyMemory();
       }
     }
   }
index 4826ef0..76b929d 100644 (file)
@@ -929,15 +929,14 @@ void MemoryChunk::IncrementLiveBytesFromMutator(Address address, int by) {
 // -----------------------------------------------------------------------------
 // PagedSpace implementation
 
-PagedSpace::PagedSpace(Heap* heap,
-                       intptr_t max_capacity,
-                       AllocationSpace id,
+PagedSpace::PagedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id,
                        Executability executable)
     : Space(heap, id, executable),
       free_list_(this),
       swept_precisely_(true),
       unswept_free_bytes_(0),
-      end_of_unswept_pages_(NULL) {
+      end_of_unswept_pages_(NULL),
+      emergency_memory_(NULL) {
   if (id == CODE_SPACE) {
     area_size_ = heap->isolate()->memory_allocator()->
         CodePageAreaSize();
@@ -1150,6 +1149,29 @@ void PagedSpace::ReleasePage(Page* page) {
 }
 
 
+void PagedSpace::CreateEmergencyMemory() {
+  emergency_memory_ = heap()->isolate()->memory_allocator()->AllocateChunk(
+      AreaSize(), AreaSize(), executable(), this);
+}
+
+
+void PagedSpace::FreeEmergencyMemory() {
+  Page* page = static_cast<Page*>(emergency_memory_);
+  ASSERT(page->LiveBytes() == 0);
+  ASSERT(AreaSize() == page->area_size());
+  ASSERT(!free_list_.ContainsPageFreeListItems(page));
+  heap()->isolate()->memory_allocator()->Free(page);
+  emergency_memory_ = NULL;
+}
+
+
+void PagedSpace::UseEmergencyMemory() {
+  Page* page = Page::Initialize(heap(), emergency_memory_, executable(), this);
+  page->InsertAfter(anchor_.prev_page());
+  emergency_memory_ = NULL;
+}
+
+
 #ifdef DEBUG
 void PagedSpace::Print() { }
 #endif
index 3fe71b2..b8fa8c7 100644 (file)
@@ -1980,6 +1980,12 @@ class PagedSpace : public Space {
     return area_size_;
   }
 
+  void CreateEmergencyMemory();
+  void FreeEmergencyMemory();
+  void UseEmergencyMemory();
+
+  bool HasEmergencyMemory() { return emergency_memory_ != NULL; }
+
  protected:
   FreeList* free_list() { return &free_list_; }
 
@@ -2015,6 +2021,12 @@ class PagedSpace : public Space {
   // end_of_unswept_pages_ page.
   Page* end_of_unswept_pages_;
 
+  // Emergency memory is the memory of a full page for a given space, allocated
+  // conservatively before evacuating a page. If compaction fails due to out
+  // of memory error the emergency memory can be used to complete compaction.
+  // If not used, the emergency memory is released after compaction.
+  MemoryChunk* emergency_memory_;
+
   // Expands the space by allocating a fixed number of pages. Returns false if
   // it cannot allocate requested number of pages from OS, or if the hard heap
   // size limit has been hit.