Chromium Code Reviews| 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 = first_object_start(); |
| 54 uword end_addr = top(); | 53 uword end_addr = 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 = first_object_start(); |
| 66 uword end_addr = top(); | 65 uword end_addr = 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 = first_object_start(); |
| 77 uword end_addr = top(); | 76 uword end_addr = 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 return page; | |
| 138 } | 136 } |
| 139 | 137 |
| 140 | 138 |
| 141 HeapPage* PageSpace::AllocateLargePage(intptr_t size) { | 139 HeapPage* PageSpace::AllocateLargePage(intptr_t size) { |
| 142 intptr_t page_size = LargePageSizeFor(size); | 140 intptr_t page_size = LargePageSizeFor(size); |
| 143 HeapPage* page = HeapPage::Allocate(page_size, is_executable_); | 141 HeapPage* page = HeapPage::Allocate(page_size, is_executable_); |
| 144 page->set_next(large_pages_); | 142 page->set_next(large_pages_); |
| 145 large_pages_ = page; | 143 large_pages_ = page; |
| 146 capacity_ += page_size; | 144 capacity_ += page_size; |
| 147 return page; | 145 return page; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 179 void PageSpace::FreePages(HeapPage* pages) { | 177 void PageSpace::FreePages(HeapPage* pages) { |
| 180 HeapPage* page = pages; | 178 HeapPage* page = pages; |
| 181 while (page != NULL) { | 179 while (page != NULL) { |
| 182 HeapPage* next = page->next(); | 180 HeapPage* next = page->next(); |
| 183 page->Deallocate(); | 181 page->Deallocate(); |
| 184 page = next; | 182 page = next; |
| 185 } | 183 } |
| 186 } | 184 } |
| 187 | 185 |
| 188 | 186 |
| 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) { | 187 uword PageSpace::TryAllocate(intptr_t size) { |
| 216 return TryAllocate(size, kControlGrowth); | 188 return TryAllocate(size, kControlGrowth); |
| 217 } | 189 } |
| 218 | 190 |
| 219 | 191 |
| 220 uword PageSpace::TryAllocate(intptr_t size, GrowthPolicy growth_policy) { | 192 uword PageSpace::TryAllocate(intptr_t size, GrowthPolicy growth_policy) { |
| 221 ASSERT(size >= kObjectAlignment); | 193 ASSERT(size >= kObjectAlignment); |
| 222 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 194 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
| 223 uword result = 0; | 195 uword result = 0; |
| 224 if (size < kAllocatablePageSize) { | 196 if (size < kAllocatablePageSize) { |
| 225 result = freelist_.TryAllocate(size); | 197 result = freelist_.TryAllocate(size); |
| 226 if (result == 0) { | 198 if ((result == 0) && |
| 227 result = TryBumpAllocate(size); | 199 (page_space_controller_.CanGrowPageSpace(size) || |
| 228 if ((result == 0) && | 200 growth_policy == kForceGrowth) && |
| 229 (page_space_controller_.CanGrowPageSpace(size) || | 201 CanIncreaseCapacity(kPageSize)) { |
| 230 growth_policy == kForceGrowth) && | 202 HeapPage* page = AllocatePage(); |
| 231 CanIncreaseCapacity(kPageSize)) { | 203 ASSERT(page != NULL); |
| 232 AllocatePage(); | 204 // Start of the newly allocated page is the allocated object. |
| 233 result = TryBumpAllocate(size); | 205 result = page->first_object_start(); |
| 234 ASSERT(result != 0); | 206 // Enqueue the remainder in the free list. |
| 235 } | 207 uword free_start = result + size; |
| 208 freelist_.Free( | |
| 209 free_start, | |
| 210 Utils::RoundDown(page->end() - free_start, kObjectAlignment)); | |
| 236 } | 211 } |
| 237 } else { | 212 } else { |
| 238 // Large page allocation. | 213 // Large page allocation. |
| 239 intptr_t page_size = LargePageSizeFor(size); | 214 intptr_t page_size = LargePageSizeFor(size); |
| 240 if (page_size < size) { | 215 if (page_size < size) { |
| 241 // On overflow we fail to allocate. | 216 // On overflow we fail to allocate. |
| 242 return 0; | 217 return 0; |
| 243 } | 218 } |
| 244 if (CanIncreaseCapacity(page_size)) { | 219 if (CanIncreaseCapacity(page_size)) { |
| 245 HeapPage* page = AllocateLargePage(size); | 220 HeapPage* page = AllocateLargePage(size); |
| 246 if (page != NULL) { | 221 if (page != NULL) { |
| 247 result = page->top(); | 222 result = page->first_object_start(); |
| 248 page->set_top(result + size); | |
| 249 } | 223 } |
| 250 } | 224 } |
| 251 } | 225 } |
| 252 if (result != 0) { | 226 if (result != 0) { |
| 253 in_use_ += size; | 227 in_use_ += size; |
| 254 } | 228 } |
| 229 ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset); | |
| 255 return result; | 230 return result; |
| 256 } | 231 } |
| 257 | 232 |
| 258 | 233 |
| 259 bool PageSpace::Contains(uword addr) const { | 234 bool PageSpace::Contains(uword addr) const { |
| 260 HeapPage* page = pages_; | 235 HeapPage* page = pages_; |
| 261 while (page != NULL) { | 236 while (page != NULL) { |
| 262 if (page->Contains(addr)) { | 237 if (page->Contains(addr)) { |
| 263 return true; | 238 return true; |
| 264 } | 239 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 295 | 270 |
| 296 void PageSpace::VisitObjects(ObjectVisitor* visitor) const { | 271 void PageSpace::VisitObjects(ObjectVisitor* visitor) const { |
| 297 HeapPage* page = pages_; | 272 HeapPage* page = pages_; |
| 298 while (page != NULL) { | 273 while (page != NULL) { |
| 299 page->VisitObjects(visitor); | 274 page->VisitObjects(visitor); |
| 300 page = page->next(); | 275 page = page->next(); |
| 301 } | 276 } |
| 302 | 277 |
| 303 page = large_pages_; | 278 page = large_pages_; |
| 304 while (page != NULL) { | 279 while (page != NULL) { |
| 305 page->VisitObjects(visitor); | 280 uword obj_addr = page->first_object_start(); |
|
cshapiro
2012/10/17 02:53:22
Why did this code have to change? This was done i
Ivan Posva
2012/10/18 17:34:21
I did not like the expansion either. Now that I ha
| |
| 281 RawObject* raw_obj = RawObject::FromAddr(obj_addr); | |
| 282 visitor->VisitObject(raw_obj); | |
| 306 page = page->next(); | 283 page = page->next(); |
| 307 } | 284 } |
| 308 } | 285 } |
| 309 | 286 |
| 310 | 287 |
| 311 void PageSpace::SetPeer(RawObject* raw_obj, void* peer) { | 288 void PageSpace::SetPeer(RawObject* raw_obj, void* peer) { |
| 312 if (peer == NULL) { | 289 if (peer == NULL) { |
| 313 peer_table_.erase(raw_obj); | 290 peer_table_.erase(raw_obj); |
| 314 } else { | 291 } else { |
| 315 peer_table_[raw_obj] = peer; | 292 peer_table_[raw_obj] = peer; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 330 | 307 |
| 331 void PageSpace::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 308 void PageSpace::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
| 332 HeapPage* page = pages_; | 309 HeapPage* page = pages_; |
| 333 while (page != NULL) { | 310 while (page != NULL) { |
| 334 page->VisitObjectPointers(visitor); | 311 page->VisitObjectPointers(visitor); |
| 335 page = page->next(); | 312 page = page->next(); |
| 336 } | 313 } |
| 337 | 314 |
| 338 page = large_pages_; | 315 page = large_pages_; |
| 339 while (page != NULL) { | 316 while (page != NULL) { |
| 340 page->VisitObjectPointers(visitor); | 317 uword obj_addr = page->first_object_start(); |
|
cshapiro
2012/10/17 02:53:22
ditto
| |
| 318 RawObject* raw_obj = RawObject::FromAddr(obj_addr); | |
| 319 raw_obj->VisitPointers(visitor); | |
| 341 page = page->next(); | 320 page = page->next(); |
| 342 } | 321 } |
| 343 } | 322 } |
| 344 | 323 |
| 345 | 324 |
| 346 RawObject* PageSpace::FindObject(FindObjectVisitor* visitor) const { | 325 RawObject* PageSpace::FindObject(FindObjectVisitor* visitor) const { |
| 347 ASSERT(Isolate::Current()->no_gc_scope_depth() != 0); | 326 ASSERT(Isolate::Current()->no_gc_scope_depth() != 0); |
| 348 HeapPage* page = pages_; | 327 HeapPage* page = pages_; |
| 349 while (page != NULL) { | 328 while (page != NULL) { |
| 350 RawObject* obj = page->FindObject(visitor); | 329 RawObject* obj = page->FindObject(visitor); |
| 351 if (obj != Object::null()) { | 330 if (obj != Object::null()) { |
| 352 return obj; | 331 return obj; |
| 353 } | 332 } |
| 354 page = page->next(); | 333 page = page->next(); |
| 355 } | 334 } |
| 356 | 335 |
| 357 page = large_pages_; | 336 page = large_pages_; |
| 358 while (page != NULL) { | 337 while (page != NULL) { |
| 359 RawObject* obj = page->FindObject(visitor); | 338 uword obj_addr = page->first_object_start(); |
|
cshapiro
2012/10/17 02:53:22
ditto
| |
| 360 if (obj != Object::null()) { | 339 RawObject* raw_obj = RawObject::FromAddr(obj_addr); |
| 361 return obj; | 340 if (raw_obj->FindObject(visitor)) { |
| 341 return raw_obj; | |
| 362 } | 342 } |
| 363 page = page->next(); | 343 page = page->next(); |
| 364 } | 344 } |
| 365 return Object::null(); | 345 return Object::null(); |
| 366 } | 346 } |
| 367 | 347 |
| 368 | 348 |
| 369 void PageSpace::WriteProtect(bool read_only) { | 349 void PageSpace::WriteProtect(bool read_only) { |
| 370 HeapPage* page = pages_; | 350 HeapPage* page = pages_; |
| 371 while (page != NULL) { | 351 while (page != NULL) { |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 402 } | 382 } |
| 403 Timer timer(true, "MarkSweep"); | 383 Timer timer(true, "MarkSweep"); |
| 404 timer.Start(); | 384 timer.Start(); |
| 405 int64_t start = OS::GetCurrentTimeMillis(); | 385 int64_t start = OS::GetCurrentTimeMillis(); |
| 406 | 386 |
| 407 // Mark all reachable old-gen objects. | 387 // Mark all reachable old-gen objects. |
| 408 GCMarker marker(heap_); | 388 GCMarker marker(heap_); |
| 409 marker.MarkObjects(isolate, this, invoke_api_callbacks); | 389 marker.MarkObjects(isolate, this, invoke_api_callbacks); |
| 410 | 390 |
| 411 // Reset the bump allocation page to unused. | 391 // Reset the bump allocation page to unused. |
| 412 bump_page_ = NULL; | |
| 413 // Reset the freelists and setup sweeping. | 392 // Reset the freelists and setup sweeping. |
| 414 freelist_.Reset(); | 393 freelist_.Reset(); |
| 415 GCSweeper sweeper(heap_); | 394 GCSweeper sweeper(heap_); |
| 416 intptr_t in_use = 0; | 395 intptr_t in_use = 0; |
| 417 | 396 |
| 418 HeapPage* prev_page = NULL; | 397 HeapPage* prev_page = NULL; |
| 419 HeapPage* page = pages_; | 398 HeapPage* page = pages_; |
| 420 while (page != NULL) { | 399 while (page != NULL) { |
| 421 intptr_t page_in_use = sweeper.SweepPage(page, &freelist_); | 400 intptr_t page_in_use = sweeper.SweepPage(page, &freelist_); |
| 422 HeapPage* next_page = page->next(); | 401 HeapPage* next_page = page->next(); |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 601 return 0; | 580 return 0; |
| 602 } else { | 581 } else { |
| 603 ASSERT(total_time >= gc_time); | 582 ASSERT(total_time >= gc_time); |
| 604 int result= static_cast<int>((static_cast<double>(gc_time) / | 583 int result= static_cast<int>((static_cast<double>(gc_time) / |
| 605 static_cast<double>(total_time)) * 100); | 584 static_cast<double>(total_time)) * 100); |
| 606 return result; | 585 return result; |
| 607 } | 586 } |
| 608 } | 587 } |
| 609 | 588 |
| 610 } // namespace dart | 589 } // namespace dart |
| OLD | NEW |