| 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/compiler_stats.h" | 8 #include "vm/compiler_stats.h" |
| 9 #include "vm/gc_marker.h" | 9 #include "vm/gc_marker.h" |
| 10 #include "vm/gc_sweeper.h" | 10 #include "vm/gc_sweeper.h" |
| 11 #include "vm/lockers.h" |
| 11 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 #include "vm/thread.h" |
| 12 #include "vm/virtual_memory.h" | 14 #include "vm/virtual_memory.h" |
| 13 | 15 |
| 14 namespace dart { | 16 namespace dart { |
| 15 | 17 |
| 16 DEFINE_FLAG(int, heap_growth_space_ratio, 20, | 18 DEFINE_FLAG(int, heap_growth_space_ratio, 20, |
| 17 "The desired maximum percentage of free space after GC"); | 19 "The desired maximum percentage of free space after GC"); |
| 18 DEFINE_FLAG(int, heap_growth_time_ratio, 3, | 20 DEFINE_FLAG(int, heap_growth_time_ratio, 3, |
| 19 "The desired maximum percentage of time spent in GC"); | 21 "The desired maximum percentage of time spent in GC"); |
| 20 DEFINE_FLAG(int, heap_growth_rate, 256, | 22 DEFINE_FLAG(int, heap_growth_rate, 256, |
| 21 "The max number of pages the heap can grow at a time"); | 23 "The max number of pages the heap can grow at a time"); |
| 22 DEFINE_FLAG(bool, print_free_list_before_gc, false, | 24 DEFINE_FLAG(bool, print_free_list_before_gc, false, |
| 23 "Print free list statistics before a GC"); | 25 "Print free list statistics before a GC"); |
| 24 DEFINE_FLAG(bool, print_free_list_after_gc, false, | 26 DEFINE_FLAG(bool, print_free_list_after_gc, false, |
| 25 "Print free list statistics after a GC"); | 27 "Print free list statistics after a GC"); |
| 26 DEFINE_FLAG(bool, collect_code, true, | 28 DEFINE_FLAG(bool, collect_code, true, |
| 27 "Attempt to GC infrequently used code."); | 29 "Attempt to GC infrequently used code."); |
| 28 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000, | 30 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000, |
| 29 "Time between attempts to collect unused code."); | 31 "Time between attempts to collect unused code."); |
| 30 DEFINE_FLAG(bool, log_code_drop, false, | 32 DEFINE_FLAG(bool, log_code_drop, false, |
| 31 "Emit a log message when pointers to unused code are dropped."); | 33 "Emit a log message when pointers to unused code are dropped."); |
| 32 DEFINE_FLAG(bool, always_drop_code, false, | 34 DEFINE_FLAG(bool, always_drop_code, false, |
| 33 "Always try to drop code if the function's usage counter is >= 0"); | 35 "Always try to drop code if the function's usage counter is >= 0"); |
| 34 DECLARE_FLAG(bool, write_protect_code); | |
| 35 | 36 |
| 36 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) { | 37 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) { |
| 37 ASSERT(memory->size() > VirtualMemory::PageSize()); | 38 ASSERT(memory->size() > VirtualMemory::PageSize()); |
| 38 bool is_executable = (type == kExecutable); | 39 bool is_executable = (type == kExecutable); |
| 39 memory->Commit(is_executable); | 40 memory->Commit(is_executable); |
| 40 | 41 |
| 41 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); | 42 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); |
| 42 result->memory_ = memory; | 43 result->memory_ = memory; |
| 43 result->next_ = NULL; | 44 result->next_ = NULL; |
| 44 result->executable_ = is_executable; | 45 result->executable_ = is_executable; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 } | 118 } |
| 118 | 119 |
| 119 | 120 |
| 120 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity_in_words) | 121 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity_in_words) |
| 121 : freelist_(), | 122 : freelist_(), |
| 122 heap_(heap), | 123 heap_(heap), |
| 123 pages_(NULL), | 124 pages_(NULL), |
| 124 pages_tail_(NULL), | 125 pages_tail_(NULL), |
| 125 large_pages_(NULL), | 126 large_pages_(NULL), |
| 126 max_capacity_in_words_(max_capacity_in_words), | 127 max_capacity_in_words_(max_capacity_in_words), |
| 127 sweeping_(false), | 128 tasks_lock_(new Monitor()), |
| 129 tasks_(0), |
| 128 page_space_controller_(heap, | 130 page_space_controller_(heap, |
| 129 FLAG_heap_growth_space_ratio, | 131 FLAG_heap_growth_space_ratio, |
| 130 FLAG_heap_growth_rate, | 132 FLAG_heap_growth_rate, |
| 131 FLAG_heap_growth_time_ratio), | 133 FLAG_heap_growth_time_ratio), |
| 132 gc_time_micros_(0), | 134 gc_time_micros_(0), |
| 133 collections_(0) { | 135 collections_(0) { |
| 134 } | 136 } |
| 135 | 137 |
| 136 | 138 |
| 137 PageSpace::~PageSpace() { | 139 PageSpace::~PageSpace() { |
| 140 { |
| 141 MonitorLocker ml(tasks_lock()); |
| 142 ASSERT(tasks() == 0); |
| 143 } |
| 138 FreePages(pages_); | 144 FreePages(pages_); |
| 139 FreePages(large_pages_); | 145 FreePages(large_pages_); |
| 146 delete tasks_lock_; |
| 140 } | 147 } |
| 141 | 148 |
| 142 | 149 |
| 143 intptr_t PageSpace::LargePageSizeInWordsFor(intptr_t size) { | 150 intptr_t PageSpace::LargePageSizeInWordsFor(intptr_t size) { |
| 144 intptr_t page_size = Utils::RoundUp(size + HeapPage::ObjectStartOffset(), | 151 intptr_t page_size = Utils::RoundUp(size + HeapPage::ObjectStartOffset(), |
| 145 VirtualMemory::PageSize()); | 152 VirtualMemory::PageSize()); |
| 146 return page_size >> kWordSizeLog2; | 153 return page_size >> kWordSizeLog2; |
| 147 } | 154 } |
| 148 | 155 |
| 149 | 156 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 void PageSpace::FreePages(HeapPage* pages) { | 238 void PageSpace::FreePages(HeapPage* pages) { |
| 232 HeapPage* page = pages; | 239 HeapPage* page = pages; |
| 233 while (page != NULL) { | 240 while (page != NULL) { |
| 234 HeapPage* next = page->next(); | 241 HeapPage* next = page->next(); |
| 235 page->Deallocate(); | 242 page->Deallocate(); |
| 236 page = next; | 243 page = next; |
| 237 } | 244 } |
| 238 } | 245 } |
| 239 | 246 |
| 240 | 247 |
| 241 uword PageSpace::TryAllocate(intptr_t size, | 248 uword PageSpace::TryAllocateInternal(intptr_t size, |
| 242 HeapPage::PageType type, | 249 HeapPage::PageType type, |
| 243 GrowthPolicy growth_policy) { | 250 GrowthPolicy growth_policy, |
| 251 bool is_protected, |
| 252 bool is_locked) { |
| 244 ASSERT(size >= kObjectAlignment); | 253 ASSERT(size >= kObjectAlignment); |
| 245 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 254 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
| 246 uword result = 0; | 255 uword result = 0; |
| 247 SpaceUsage after_allocation = usage_; | 256 SpaceUsage after_allocation = usage_; |
| 248 after_allocation.used_in_words += size >> kWordSizeLog2; | 257 after_allocation.used_in_words += size >> kWordSizeLog2; |
| 249 if (size < kAllocatablePageSize) { | 258 if (size < kAllocatablePageSize) { |
| 250 const bool is_protected = (type == HeapPage::kExecutable) | 259 if (is_locked) { |
| 251 && FLAG_write_protect_code; | 260 result = freelist_[type].TryAllocateLocked(size, is_protected); |
| 252 result = freelist_[type].TryAllocate(size, is_protected); | 261 } else { |
| 262 result = freelist_[type].TryAllocate(size, is_protected); |
| 263 } |
| 253 if (result == 0) { | 264 if (result == 0) { |
| 254 // Can we grow by one page? | 265 // Can we grow by one page? |
| 255 after_allocation.capacity_in_words += kPageSizeInWords; | 266 after_allocation.capacity_in_words += kPageSizeInWords; |
| 256 if ((!page_space_controller_.NeedsGarbageCollection(after_allocation) || | 267 if ((!page_space_controller_.NeedsGarbageCollection(after_allocation) || |
| 257 growth_policy == kForceGrowth) && | 268 growth_policy == kForceGrowth) && |
| 258 CanIncreaseCapacityInWords(kPageSizeInWords)) { | 269 CanIncreaseCapacityInWords(kPageSizeInWords)) { |
| 259 HeapPage* page = AllocatePage(type); | 270 HeapPage* page = AllocatePage(type); |
| 260 ASSERT(page != NULL); | 271 ASSERT(page != NULL); |
| 261 // Start of the newly allocated page is the allocated object. | 272 // Start of the newly allocated page is the allocated object. |
| 262 result = page->object_start(); | 273 result = page->object_start(); |
| 263 // Enqueue the remainder in the free list. | 274 // Enqueue the remainder in the free list. |
| 264 uword free_start = result + size; | 275 uword free_start = result + size; |
| 265 intptr_t free_size = page->object_end() - free_start; | 276 intptr_t free_size = page->object_end() - free_start; |
| 266 if (free_size > 0) { | 277 if (free_size > 0) { |
| 267 freelist_[type].Free(free_start, free_size); | 278 if (is_locked) { |
| 279 freelist_[type].FreeLocked(free_start, free_size); |
| 280 } else { |
| 281 freelist_[type].Free(free_start, free_size); |
| 282 } |
| 268 } | 283 } |
| 269 } | 284 } |
| 270 } | 285 } |
| 271 } else { | 286 } else { |
| 272 // Large page allocation. | 287 // Large page allocation. |
| 273 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); | 288 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); |
| 274 if ((page_size_in_words << kWordSizeLog2) < size) { | 289 if ((page_size_in_words << kWordSizeLog2) < size) { |
| 275 // On overflow we fail to allocate. | 290 // On overflow we fail to allocate. |
| 276 return 0; | 291 return 0; |
| 277 } | 292 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 289 usage_ = after_allocation; | 304 usage_ = after_allocation; |
| 290 if (FLAG_compiler_stats && (type == HeapPage::kExecutable)) { | 305 if (FLAG_compiler_stats && (type == HeapPage::kExecutable)) { |
| 291 CompilerStats::code_allocated += size; | 306 CompilerStats::code_allocated += size; |
| 292 } | 307 } |
| 293 } | 308 } |
| 294 ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset); | 309 ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset); |
| 295 return result; | 310 return result; |
| 296 } | 311 } |
| 297 | 312 |
| 298 | 313 |
| 314 void PageSpace::AcquireDataLock() { |
| 315 freelist_[HeapPage::kData].mutex()->Lock(); |
| 316 } |
| 317 |
| 318 |
| 319 void PageSpace::ReleaseDataLock() { |
| 320 freelist_[HeapPage::kData].mutex()->Unlock(); |
| 321 } |
| 322 |
| 323 |
| 299 void PageSpace::AllocateExternal(intptr_t size) { | 324 void PageSpace::AllocateExternal(intptr_t size) { |
| 300 intptr_t size_in_words = size >> kWordSizeLog2; | 325 intptr_t size_in_words = size >> kWordSizeLog2; |
| 301 usage_.external_in_words += size_in_words; | 326 usage_.external_in_words += size_in_words; |
| 302 // TODO(koda): Control growth. | 327 // TODO(koda): Control growth. |
| 303 } | 328 } |
| 304 | 329 |
| 305 | 330 |
| 306 void PageSpace::FreeExternal(intptr_t size) { | 331 void PageSpace::FreeExternal(intptr_t size) { |
| 307 intptr_t size_in_words = size >> kWordSizeLog2; | 332 intptr_t size_in_words = size >> kWordSizeLog2; |
| 308 usage_.external_in_words -= size_in_words; | 333 usage_.external_in_words -= size_in_words; |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 if (current_page->type() == HeapPage::kExecutable) { | 509 if (current_page->type() == HeapPage::kExecutable) { |
| 485 current_page->WriteProtect(read_only); | 510 current_page->WriteProtect(read_only); |
| 486 } | 511 } |
| 487 current_page = NextPageAnySize(current_page); | 512 current_page = NextPageAnySize(current_page); |
| 488 } | 513 } |
| 489 } | 514 } |
| 490 } | 515 } |
| 491 | 516 |
| 492 | 517 |
| 493 void PageSpace::MarkSweep(bool invoke_api_callbacks) { | 518 void PageSpace::MarkSweep(bool invoke_api_callbacks) { |
| 494 // MarkSweep is not reentrant. Make sure that is the case. | 519 Isolate* isolate = heap_->isolate(); |
| 495 ASSERT(!sweeping_); | 520 ASSERT(isolate == Isolate::Current()); |
| 496 sweeping_ = true; | 521 |
| 497 Isolate* isolate = Isolate::Current(); | 522 // Wait for pending tasks to complete and then account for the driver task. |
| 523 { |
| 524 MonitorLocker locker(tasks_lock()); |
| 525 while (tasks() != 0) { |
| 526 locker.Wait(); |
| 527 } |
| 528 set_tasks(1); |
| 529 } |
| 498 | 530 |
| 499 NoHandleScope no_handles(isolate); | 531 NoHandleScope no_handles(isolate); |
| 500 | 532 |
| 501 if (FLAG_print_free_list_before_gc) { | 533 if (FLAG_print_free_list_before_gc) { |
| 502 OS::Print("Data Freelist (before GC):\n"); | 534 OS::Print("Data Freelist (before GC):\n"); |
| 503 freelist_[HeapPage::kData].Print(); | 535 freelist_[HeapPage::kData].Print(); |
| 504 OS::Print("Executable Freelist (before GC):\n"); | 536 OS::Print("Executable Freelist (before GC):\n"); |
| 505 freelist_[HeapPage::kExecutable].Print(); | 537 freelist_[HeapPage::kExecutable].Print(); |
| 506 } | 538 } |
| 507 | 539 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 OS::Print("Executable Freelist (after GC):\n"); | 619 OS::Print("Executable Freelist (after GC):\n"); |
| 588 freelist_[HeapPage::kExecutable].Print(); | 620 freelist_[HeapPage::kExecutable].Print(); |
| 589 } | 621 } |
| 590 | 622 |
| 591 if (FLAG_verify_after_gc) { | 623 if (FLAG_verify_after_gc) { |
| 592 OS::PrintErr("Verifying after MarkSweep..."); | 624 OS::PrintErr("Verifying after MarkSweep..."); |
| 593 heap_->Verify(); | 625 heap_->Verify(); |
| 594 OS::PrintErr(" done.\n"); | 626 OS::PrintErr(" done.\n"); |
| 595 } | 627 } |
| 596 | 628 |
| 597 // Done, reset the marker. | 629 // Done, reset the task count. |
| 598 ASSERT(sweeping_); | 630 { |
| 599 sweeping_ = false; | 631 MonitorLocker locker(tasks_lock()); |
| 632 ASSERT(tasks() == 1); |
| 633 set_tasks(tasks() - 1); |
| 634 } |
| 600 } | 635 } |
| 601 | 636 |
| 602 | 637 |
| 603 PageSpaceController::PageSpaceController(Heap* heap, | 638 PageSpaceController::PageSpaceController(Heap* heap, |
| 604 int heap_growth_ratio, | 639 int heap_growth_ratio, |
| 605 int heap_growth_max, | 640 int heap_growth_max, |
| 606 int garbage_collection_time_ratio) | 641 int garbage_collection_time_ratio) |
| 607 : heap_(heap), | 642 : heap_(heap), |
| 608 is_enabled_(false), | 643 is_enabled_(false), |
| 609 grow_heap_(heap_growth_max / 2), | 644 grow_heap_(heap_growth_max / 2), |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 return 0; | 749 return 0; |
| 715 } else { | 750 } else { |
| 716 ASSERT(total_time >= gc_time); | 751 ASSERT(total_time >= gc_time); |
| 717 int result= static_cast<int>((static_cast<double>(gc_time) / | 752 int result= static_cast<int>((static_cast<double>(gc_time) / |
| 718 static_cast<double>(total_time)) * 100); | 753 static_cast<double>(total_time)) * 100); |
| 719 return result; | 754 return result; |
| 720 } | 755 } |
| 721 } | 756 } |
| 722 | 757 |
| 723 } // namespace dart | 758 } // namespace dart |
| OLD | NEW |