| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/pages.h" | 5 #include "vm/pages.h" |
| 6 | 6 |
| 7 #include "platform/assert.h" | 7 #include "platform/assert.h" |
| 8 #include "vm/gc_marker.h" | 8 #include "vm/gc_marker.h" |
| 9 #include "vm/gc_sweeper.h" | 9 #include "vm/gc_sweeper.h" |
| 10 #include "vm/object.h" | 10 #include "vm/object.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 "Print free list statistics after a GC"); | 24 "Print free list statistics after a GC"); |
| 25 | 25 |
| 26 HeapPage* HeapPage::Initialize(VirtualMemory* memory, bool is_executable) { | 26 HeapPage* HeapPage::Initialize(VirtualMemory* memory, bool is_executable) { |
| 27 ASSERT(memory->size() > VirtualMemory::PageSize()); | 27 ASSERT(memory->size() > VirtualMemory::PageSize()); |
| 28 memory->Commit(is_executable); | 28 memory->Commit(is_executable); |
| 29 | 29 |
| 30 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); | 30 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); |
| 31 result->memory_ = memory; | 31 result->memory_ = memory; |
| 32 result->next_ = NULL; | 32 result->next_ = NULL; |
| 33 result->used_ = 0; | 33 result->used_ = 0; |
| 34 result->top_ = result->first_object_start(); | |
| 35 return result; | 34 return result; |
| 36 } | 35 } |
| 37 | 36 |
| 38 | 37 |
| 39 HeapPage* HeapPage::Allocate(intptr_t size, bool is_executable) { | 38 HeapPage* HeapPage::Allocate(intptr_t size, bool is_executable) { |
| 40 VirtualMemory* memory = | 39 VirtualMemory* memory = |
| 41 VirtualMemory::ReserveAligned(size, PageSpace::kPageAlignment); | 40 VirtualMemory::ReserveAligned(size, PageSpace::kPageAlignment); |
| 42 return Initialize(memory, is_executable); | 41 return Initialize(memory, is_executable); |
| 43 } | 42 } |
| 44 | 43 |
| 45 | 44 |
| 46 void HeapPage::Deallocate() { | 45 void HeapPage::Deallocate() { |
| 47 // The memory for this object will become unavailable after the delete below. | 46 // The memory for this object will become unavailable after the delete below. |
| 48 delete memory_; | 47 delete memory_; |
| 49 } | 48 } |
| 50 | 49 |
| 51 | 50 |
| 52 void HeapPage::VisitObjects(ObjectVisitor* visitor) const { | 51 void HeapPage::VisitObjects(ObjectVisitor* visitor) const { |
| 53 uword obj_addr = first_object_start(); | 52 uword obj_addr = object_start(); |
| 54 uword end_addr = top(); | 53 uword end_addr = object_end(); |
| 55 while (obj_addr < end_addr) { | 54 while (obj_addr < end_addr) { |
| 56 RawObject* raw_obj = RawObject::FromAddr(obj_addr); | 55 RawObject* raw_obj = RawObject::FromAddr(obj_addr); |
| 57 visitor->VisitObject(raw_obj); | 56 visitor->VisitObject(raw_obj); |
| 58 obj_addr += raw_obj->Size(); | 57 obj_addr += raw_obj->Size(); |
| 59 } | 58 } |
| 60 ASSERT(obj_addr == end_addr); | 59 ASSERT(obj_addr == end_addr); |
| 61 } | 60 } |
| 62 | 61 |
| 63 | 62 |
| 64 void HeapPage::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 63 void HeapPage::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
| 65 uword obj_addr = first_object_start(); | 64 uword obj_addr = object_start(); |
| 66 uword end_addr = top(); | 65 uword end_addr = object_end(); |
| 67 while (obj_addr < end_addr) { | 66 while (obj_addr < end_addr) { |
| 68 RawObject* raw_obj = RawObject::FromAddr(obj_addr); | 67 RawObject* raw_obj = RawObject::FromAddr(obj_addr); |
| 69 obj_addr += raw_obj->VisitPointers(visitor); | 68 obj_addr += raw_obj->VisitPointers(visitor); |
| 70 } | 69 } |
| 71 ASSERT(obj_addr == end_addr); | 70 ASSERT(obj_addr == end_addr); |
| 72 } | 71 } |
| 73 | 72 |
| 74 | 73 |
| 75 RawObject* HeapPage::FindObject(FindObjectVisitor* visitor) const { | 74 RawObject* HeapPage::FindObject(FindObjectVisitor* visitor) const { |
| 76 uword obj_addr = first_object_start(); | 75 uword obj_addr = object_start(); |
| 77 uword end_addr = top(); | 76 uword end_addr = object_end(); |
| 78 while (obj_addr < end_addr) { | 77 while (obj_addr < end_addr) { |
| 79 RawObject* raw_obj = RawObject::FromAddr(obj_addr); | 78 RawObject* raw_obj = RawObject::FromAddr(obj_addr); |
| 80 if (raw_obj->FindObject(visitor)) { | 79 if (raw_obj->FindObject(visitor)) { |
| 81 return raw_obj; // Found object, return it. | 80 return raw_obj; // Found object, return it. |
| 82 } | 81 } |
| 83 obj_addr += raw_obj->Size(); | 82 obj_addr += raw_obj->Size(); |
| 84 } | 83 } |
| 85 ASSERT(obj_addr == end_addr); | 84 ASSERT(obj_addr == end_addr); |
| 86 return Object::null(); | 85 return Object::null(); |
| 87 } | 86 } |
| 88 | 87 |
| 89 | 88 |
| 90 void HeapPage::WriteProtect(bool read_only) { | 89 void HeapPage::WriteProtect(bool read_only) { |
| 91 memory_->Protect( | 90 memory_->Protect( |
| 92 read_only ? VirtualMemory::kReadOnly : VirtualMemory::kReadWrite); | 91 read_only ? VirtualMemory::kReadOnly : VirtualMemory::kReadWrite); |
| 93 } | 92 } |
| 94 | 93 |
| 95 | 94 |
| 96 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity, bool is_executable) | 95 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity, bool is_executable) |
| 97 : freelist_(), | 96 : freelist_(), |
| 98 heap_(heap), | 97 heap_(heap), |
| 99 pages_(NULL), | 98 pages_(NULL), |
| 100 pages_tail_(NULL), | 99 pages_tail_(NULL), |
| 101 large_pages_(NULL), | 100 large_pages_(NULL), |
| 102 bump_page_(NULL), | |
| 103 max_capacity_(max_capacity), | 101 max_capacity_(max_capacity), |
| 104 capacity_(0), | 102 capacity_(0), |
| 105 in_use_(0), | 103 in_use_(0), |
| 106 count_(0), | 104 count_(0), |
| 107 is_executable_(is_executable), | 105 is_executable_(is_executable), |
| 108 sweeping_(false), | 106 sweeping_(false), |
| 109 page_space_controller_(FLAG_heap_growth_space_ratio, | 107 page_space_controller_(FLAG_heap_growth_space_ratio, |
| 110 FLAG_heap_growth_rate, | 108 FLAG_heap_growth_rate, |
| 111 FLAG_heap_growth_time_ratio) { | 109 FLAG_heap_growth_time_ratio) { |
| 112 } | 110 } |
| 113 | 111 |
| 114 | 112 |
| 115 PageSpace::~PageSpace() { | 113 PageSpace::~PageSpace() { |
| 116 FreePages(pages_); | 114 FreePages(pages_); |
| 117 FreePages(large_pages_); | 115 FreePages(large_pages_); |
| 118 } | 116 } |
| 119 | 117 |
| 120 | 118 |
| 121 intptr_t PageSpace::LargePageSizeFor(intptr_t size) { | 119 intptr_t PageSpace::LargePageSizeFor(intptr_t size) { |
| 122 intptr_t page_size = Utils::RoundUp(size + sizeof(HeapPage), | 120 intptr_t page_size = Utils::RoundUp(size + sizeof(HeapPage), |
| 123 VirtualMemory::PageSize()); | 121 VirtualMemory::PageSize()); |
| 124 return page_size; | 122 return page_size; |
| 125 } | 123 } |
| 126 | 124 |
| 127 | 125 |
| 128 void PageSpace::AllocatePage() { | 126 HeapPage* PageSpace::AllocatePage() { |
| 129 HeapPage* page = HeapPage::Allocate(kPageSize, is_executable_); | 127 HeapPage* page = HeapPage::Allocate(kPageSize, is_executable_); |
| 130 if (pages_ == NULL) { | 128 if (pages_ == NULL) { |
| 131 pages_ = page; | 129 pages_ = page; |
| 132 } else { | 130 } else { |
| 133 pages_tail_->set_next(page); | 131 pages_tail_->set_next(page); |
| 134 } | 132 } |
| 135 pages_tail_ = page; | 133 pages_tail_ = page; |
| 136 bump_page_ = NULL; // Reenable scanning of pages for bump allocation. | |
| 137 capacity_ += kPageSize; | 134 capacity_ += kPageSize; |
| 135 page->set_object_end(page->memory_->end()); |
| 136 return page; |
| 138 } | 137 } |
| 139 | 138 |
| 140 | 139 |
| 141 HeapPage* PageSpace::AllocateLargePage(intptr_t size) { | 140 HeapPage* PageSpace::AllocateLargePage(intptr_t size) { |
| 142 intptr_t page_size = LargePageSizeFor(size); | 141 intptr_t page_size = LargePageSizeFor(size); |
| 143 HeapPage* page = HeapPage::Allocate(page_size, is_executable_); | 142 HeapPage* page = HeapPage::Allocate(page_size, is_executable_); |
| 144 page->set_next(large_pages_); | 143 page->set_next(large_pages_); |
| 145 large_pages_ = page; | 144 large_pages_ = page; |
| 146 capacity_ += page_size; | 145 capacity_ += page_size; |
| 146 // Only one object in this page. |
| 147 page->set_object_end(page->object_start() + size); |
| 147 return page; | 148 return page; |
| 148 } | 149 } |
| 149 | 150 |
| 150 | 151 |
| 151 void PageSpace::FreePage(HeapPage* page, HeapPage* previous_page) { | 152 void PageSpace::FreePage(HeapPage* page, HeapPage* previous_page) { |
| 152 capacity_ -= page->memory_->size(); | 153 capacity_ -= page->memory_->size(); |
| 153 // Remove the page from the list. | 154 // Remove the page from the list. |
| 154 if (previous_page != NULL) { | 155 if (previous_page != NULL) { |
| 155 previous_page->set_next(page->next()); | 156 previous_page->set_next(page->next()); |
| 156 } else { | 157 } else { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 179 void PageSpace::FreePages(HeapPage* pages) { | 180 void PageSpace::FreePages(HeapPage* pages) { |
| 180 HeapPage* page = pages; | 181 HeapPage* page = pages; |
| 181 while (page != NULL) { | 182 while (page != NULL) { |
| 182 HeapPage* next = page->next(); | 183 HeapPage* next = page->next(); |
| 183 page->Deallocate(); | 184 page->Deallocate(); |
| 184 page = next; | 185 page = next; |
| 185 } | 186 } |
| 186 } | 187 } |
| 187 | 188 |
| 188 | 189 |
| 189 uword PageSpace::TryBumpAllocate(intptr_t size) { | |
| 190 if (pages_tail_ == NULL) { | |
| 191 return 0; | |
| 192 } | |
| 193 uword result = pages_tail_->TryBumpAllocate(size); | |
| 194 if (result != 0) { | |
| 195 return result; | |
| 196 } | |
| 197 if (bump_page_ == NULL) { | |
| 198 // The bump page has not yet been used: Start at the beginning of the list. | |
| 199 bump_page_ = pages_; | |
| 200 } | |
| 201 // The last page has already been attempted above. | |
| 202 while (bump_page_ != pages_tail_) { | |
| 203 ASSERT(bump_page_->next() != NULL); | |
| 204 result = bump_page_->TryBumpAllocate(size); | |
| 205 if (result != 0) { | |
| 206 return result; | |
| 207 } | |
| 208 bump_page_ = bump_page_->next(); | |
| 209 } | |
| 210 // Ran through all of the pages trying to bump allocate: Give up. | |
| 211 return 0; | |
| 212 } | |
| 213 | |
| 214 | |
| 215 uword PageSpace::TryAllocate(intptr_t size) { | 190 uword PageSpace::TryAllocate(intptr_t size) { |
| 216 return TryAllocate(size, kControlGrowth); | 191 return TryAllocate(size, kControlGrowth); |
| 217 } | 192 } |
| 218 | 193 |
| 219 | 194 |
| 220 uword PageSpace::TryAllocate(intptr_t size, GrowthPolicy growth_policy) { | 195 uword PageSpace::TryAllocate(intptr_t size, GrowthPolicy growth_policy) { |
| 221 ASSERT(size >= kObjectAlignment); | 196 ASSERT(size >= kObjectAlignment); |
| 222 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 197 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
| 223 uword result = 0; | 198 uword result = 0; |
| 224 if (size < kAllocatablePageSize) { | 199 if (size < kAllocatablePageSize) { |
| 225 result = freelist_.TryAllocate(size); | 200 result = freelist_.TryAllocate(size); |
| 226 if (result == 0) { | 201 if ((result == 0) && |
| 227 result = TryBumpAllocate(size); | 202 (page_space_controller_.CanGrowPageSpace(size) || |
| 228 if ((result == 0) && | 203 growth_policy == kForceGrowth) && |
| 229 (page_space_controller_.CanGrowPageSpace(size) || | 204 CanIncreaseCapacity(kPageSize)) { |
| 230 growth_policy == kForceGrowth) && | 205 HeapPage* page = AllocatePage(); |
| 231 CanIncreaseCapacity(kPageSize)) { | 206 ASSERT(page != NULL); |
| 232 AllocatePage(); | 207 // Start of the newly allocated page is the allocated object. |
| 233 result = TryBumpAllocate(size); | 208 result = page->object_start(); |
| 234 ASSERT(result != 0); | 209 // Enqueue the remainder in the free list. |
| 235 } | 210 uword free_start = result + size; |
| 211 freelist_.Free(free_start, page->object_end() - free_start); |
| 236 } | 212 } |
| 237 } else { | 213 } else { |
| 238 // Large page allocation. | 214 // Large page allocation. |
| 239 intptr_t page_size = LargePageSizeFor(size); | 215 intptr_t page_size = LargePageSizeFor(size); |
| 240 if (page_size < size) { | 216 if (page_size < size) { |
| 241 // On overflow we fail to allocate. | 217 // On overflow we fail to allocate. |
| 242 return 0; | 218 return 0; |
| 243 } | 219 } |
| 244 if (CanIncreaseCapacity(page_size)) { | 220 if (CanIncreaseCapacity(page_size)) { |
| 245 HeapPage* page = AllocateLargePage(size); | 221 HeapPage* page = AllocateLargePage(size); |
| 246 if (page != NULL) { | 222 if (page != NULL) { |
| 247 result = page->top(); | 223 result = page->object_start(); |
| 248 page->set_top(result + size); | |
| 249 } | 224 } |
| 250 } | 225 } |
| 251 } | 226 } |
| 252 if (result != 0) { | 227 if (result != 0) { |
| 253 in_use_ += size; | 228 in_use_ += size; |
| 254 } | 229 } |
| 230 ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset); |
| 255 return result; | 231 return result; |
| 256 } | 232 } |
| 257 | 233 |
| 258 | 234 |
| 259 bool PageSpace::Contains(uword addr) const { | 235 bool PageSpace::Contains(uword addr) const { |
| 260 HeapPage* page = pages_; | 236 HeapPage* page = pages_; |
| 261 while (page != NULL) { | 237 while (page != NULL) { |
| 262 if (page->Contains(addr)) { | 238 if (page->Contains(addr)) { |
| 263 return true; | 239 return true; |
| 264 } | 240 } |
| 265 page = page->next(); | 241 page = page->next(); |
| 266 } | 242 } |
| 267 | 243 |
| 268 page = large_pages_; | 244 page = large_pages_; |
| 269 while (page != NULL) { | 245 while (page != NULL) { |
| 270 if (page->Contains(addr)) { | 246 if (page->Contains(addr)) { |
| 271 return true; | 247 return true; |
| 272 } | 248 } |
| 273 page = page->next(); | 249 page = page->next(); |
| 274 } | 250 } |
| 275 return false; | 251 return false; |
| 276 } | 252 } |
| 277 | 253 |
| 278 | 254 |
| 279 void PageSpace::StartEndAddress(uword* start, uword* end) const { | 255 void PageSpace::StartEndAddress(uword* start, uword* end) const { |
| 280 ASSERT(pages_ != NULL || large_pages_ != NULL); | 256 ASSERT(pages_ != NULL || large_pages_ != NULL); |
| 281 *start = static_cast<uword>(~0); | 257 *start = static_cast<uword>(~0); |
| 282 *end = 0; | 258 *end = 0; |
| 283 for (HeapPage* page = pages_; page != NULL; page = page->next()) { | 259 for (HeapPage* page = pages_; page != NULL; page = page->next()) { |
| 284 *start = Utils::Minimum(*start, page->start()); | 260 *start = Utils::Minimum(*start, page->object_start()); |
| 285 *end = Utils::Maximum(*end, page->end()); | 261 *end = Utils::Maximum(*end, page->object_end()); |
| 286 } | 262 } |
| 287 for (HeapPage* page = large_pages_; page != NULL; page = page->next()) { | 263 for (HeapPage* page = large_pages_; page != NULL; page = page->next()) { |
| 288 *start = Utils::Minimum(*start, page->start()); | 264 *start = Utils::Minimum(*start, page->object_start()); |
| 289 *end = Utils::Maximum(*end, page->end()); | 265 *end = Utils::Maximum(*end, page->object_end()); |
| 290 } | 266 } |
| 291 ASSERT(*start != static_cast<uword>(~0)); | 267 ASSERT(*start != static_cast<uword>(~0)); |
| 292 ASSERT(*end != 0); | 268 ASSERT(*end != 0); |
| 293 } | 269 } |
| 294 | 270 |
| 295 | 271 |
| 296 void PageSpace::VisitObjects(ObjectVisitor* visitor) const { | 272 void PageSpace::VisitObjects(ObjectVisitor* visitor) const { |
| 297 HeapPage* page = pages_; | 273 HeapPage* page = pages_; |
| 298 while (page != NULL) { | 274 while (page != NULL) { |
| 299 page->VisitObjects(visitor); | 275 page->VisitObjects(visitor); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 } | 378 } |
| 403 Timer timer(true, "MarkSweep"); | 379 Timer timer(true, "MarkSweep"); |
| 404 timer.Start(); | 380 timer.Start(); |
| 405 int64_t start = OS::GetCurrentTimeMillis(); | 381 int64_t start = OS::GetCurrentTimeMillis(); |
| 406 | 382 |
| 407 // Mark all reachable old-gen objects. | 383 // Mark all reachable old-gen objects. |
| 408 GCMarker marker(heap_); | 384 GCMarker marker(heap_); |
| 409 marker.MarkObjects(isolate, this, invoke_api_callbacks); | 385 marker.MarkObjects(isolate, this, invoke_api_callbacks); |
| 410 | 386 |
| 411 // Reset the bump allocation page to unused. | 387 // Reset the bump allocation page to unused. |
| 412 bump_page_ = NULL; | |
| 413 // Reset the freelists and setup sweeping. | 388 // Reset the freelists and setup sweeping. |
| 414 freelist_.Reset(); | 389 freelist_.Reset(); |
| 415 GCSweeper sweeper(heap_); | 390 GCSweeper sweeper(heap_); |
| 416 intptr_t in_use = 0; | 391 intptr_t in_use = 0; |
| 417 | 392 |
| 418 HeapPage* prev_page = NULL; | 393 HeapPage* prev_page = NULL; |
| 419 HeapPage* page = pages_; | 394 HeapPage* page = pages_; |
| 420 while (page != NULL) { | 395 while (page != NULL) { |
| 421 intptr_t page_in_use = sweeper.SweepPage(page, &freelist_); | 396 intptr_t page_in_use = sweeper.SweepPage(page, &freelist_); |
| 422 HeapPage* next_page = page->next(); | 397 HeapPage* next_page = page->next(); |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 return 0; | 576 return 0; |
| 602 } else { | 577 } else { |
| 603 ASSERT(total_time >= gc_time); | 578 ASSERT(total_time >= gc_time); |
| 604 int result= static_cast<int>((static_cast<double>(gc_time) / | 579 int result= static_cast<int>((static_cast<double>(gc_time) / |
| 605 static_cast<double>(total_time)) * 100); | 580 static_cast<double>(total_time)) * 100); |
| 606 return result; | 581 return result; |
| 607 } | 582 } |
| 608 } | 583 } |
| 609 | 584 |
| 610 } // namespace dart | 585 } // namespace dart |
| OLD | NEW |