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 |