| 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/object.h" | 11 #include "vm/object.h" |
| 12 #include "vm/virtual_memory.h" | 12 #include "vm/virtual_memory.h" |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 | 15 |
| 16 DEFINE_FLAG(int, heap_growth_space_ratio, 10, | 16 DEFINE_FLAG(int, heap_growth_space_ratio, 10, |
| 17 "The desired maximum percentage of free space after GC"); | 17 "The desired maximum percentage of free space after GC"); |
| 18 DEFINE_FLAG(int, heap_growth_time_ratio, 3, | 18 DEFINE_FLAG(int, heap_growth_time_ratio, 3, |
| 19 "The desired maximum percentage of time spent in GC"); | 19 "The desired maximum percentage of time spent in GC"); |
| 20 DEFINE_FLAG(int, heap_growth_rate, 4, | 20 DEFINE_FLAG(int, heap_growth_rate, 4, |
| 21 "The size the heap is grown, in heap pages"); | 21 "The size the heap is grown, in heap pages"); |
| 22 DEFINE_FLAG(bool, print_free_list_before_gc, false, | 22 DEFINE_FLAG(bool, print_free_list_before_gc, false, |
| 23 "Print free list statistics before a GC"); | 23 "Print free list statistics before a GC"); |
| 24 DEFINE_FLAG(bool, print_free_list_after_gc, false, | 24 DEFINE_FLAG(bool, print_free_list_after_gc, false, |
| 25 "Print free list statistics after a GC"); | 25 "Print free list statistics after a GC"); |
| 26 DEFINE_FLAG(bool, collect_code, false, | 26 DEFINE_FLAG(bool, collect_code, true, |
| 27 "Attempt to GC infrequently used code."); | 27 "Attempt to GC infrequently used code."); |
| 28 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000, | 28 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000, |
| 29 "Time between attempts to collect unused code."); | 29 "Time between attempts to collect unused code."); |
| 30 DEFINE_FLAG(bool, log_code_drop, false, | 30 DEFINE_FLAG(bool, log_code_drop, false, |
| 31 "Emit a log message when pointers to unused code are dropped."); | 31 "Emit a log message when pointers to unused code are dropped."); |
| 32 DEFINE_FLAG(bool, always_drop_code, false, |
| 33 "Always try to drop code if the function's usage counter is >= 0"); |
| 32 | 34 |
| 33 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) { | 35 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) { |
| 34 ASSERT(memory->size() > VirtualMemory::PageSize()); | 36 ASSERT(memory->size() > VirtualMemory::PageSize()); |
| 35 bool is_executable = (type == kExecutable); | 37 bool is_executable = (type == kExecutable); |
| 36 memory->Commit(is_executable); | 38 memory->Commit(is_executable); |
| 37 | 39 |
| 38 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); | 40 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); |
| 39 result->memory_ = memory; | 41 result->memory_ = memory; |
| 40 result->next_ = NULL; | 42 result->next_ = NULL; |
| 41 result->executable_ = is_executable; | 43 result->executable_ = is_executable; |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 page = page->next(); | 380 page = page->next(); |
| 379 } | 381 } |
| 380 page = large_pages_; | 382 page = large_pages_; |
| 381 while (page != NULL) { | 383 while (page != NULL) { |
| 382 page->WriteProtect(read_only); | 384 page->WriteProtect(read_only); |
| 383 page = page->next(); | 385 page = page->next(); |
| 384 } | 386 } |
| 385 } | 387 } |
| 386 | 388 |
| 387 | 389 |
| 388 class CodeDetacherVisitor : public ObjectVisitor { | 390 bool PageSpace::ShouldCollectCode() { |
| 389 public: | |
| 390 explicit CodeDetacherVisitor(Isolate* isolate) : ObjectVisitor(isolate) { } | |
| 391 | |
| 392 virtual void VisitObject(RawObject* obj); | |
| 393 | |
| 394 private: | |
| 395 static bool MayDetachCode(const Function& fn); | |
| 396 DISALLOW_COPY_AND_ASSIGN(CodeDetacherVisitor); | |
| 397 }; | |
| 398 | |
| 399 | |
| 400 bool CodeDetacherVisitor::MayDetachCode(const Function& fn) { | |
| 401 return fn.HasCode() && // Not already detached. | |
| 402 !fn.HasOptimizedCode() && | |
| 403 !fn.HasBreakpoint() && | |
| 404 (fn.usage_counter() > 0); | |
| 405 } | |
| 406 | |
| 407 | |
| 408 void CodeDetacherVisitor::VisitObject(RawObject* raw_obj) { | |
| 409 Isolate* isolate = Isolate::Current(); | |
| 410 HANDLESCOPE(isolate); | |
| 411 const Object& obj = Object::Handle(raw_obj); | |
| 412 if (obj.GetClassId() == kFunctionCid) { | |
| 413 const Function& fn = Function::Cast(obj); | |
| 414 if (CodeDetacherVisitor::MayDetachCode(fn)) { | |
| 415 fn.set_usage_counter(fn.usage_counter() / 2); | |
| 416 if (fn.usage_counter() == 0) { | |
| 417 if (FLAG_log_code_drop) { | |
| 418 const String& name = String::Handle(fn.name()); | |
| 419 OS::Print("Detaching code for function %s\n", name.ToCString()); | |
| 420 } | |
| 421 fn.DetachCode(); | |
| 422 } | |
| 423 } | |
| 424 } | |
| 425 } | |
| 426 | |
| 427 | |
| 428 void PageSpace::TryDetachingCode() { | |
| 429 // Try to collect code if enough time has passed since the last attempt. | 391 // Try to collect code if enough time has passed since the last attempt. |
| 430 const int64_t start = OS::GetCurrentTimeMicros(); | 392 const int64_t start = OS::GetCurrentTimeMicros(); |
| 431 const int64_t last_code_collection_in_us = | 393 const int64_t last_code_collection_in_us = |
| 432 page_space_controller_.last_code_collection_in_us(); | 394 page_space_controller_.last_code_collection_in_us(); |
| 395 |
| 433 if ((start - last_code_collection_in_us) > | 396 if ((start - last_code_collection_in_us) > |
| 434 FLAG_code_collection_interval_in_us) { | 397 FLAG_code_collection_interval_in_us) { |
| 435 if (FLAG_log_code_drop) { | 398 if (FLAG_log_code_drop) { |
| 436 OS::Print("Trying to detach code.\n"); | 399 OS::Print("Trying to detach code.\n"); |
| 437 } | 400 } |
| 438 Isolate* isolate = Isolate::Current(); | |
| 439 CodeDetacherVisitor code_detacher(isolate); | |
| 440 heap_->IterateObjects(&code_detacher); | |
| 441 page_space_controller_.set_last_code_collection_in_us(start); | 401 page_space_controller_.set_last_code_collection_in_us(start); |
| 402 return true; |
| 442 } | 403 } |
| 404 return false; |
| 443 } | 405 } |
| 444 | 406 |
| 445 | 407 |
| 446 void PageSpace::MarkSweep(bool invoke_api_callbacks) { | 408 void PageSpace::MarkSweep(bool invoke_api_callbacks) { |
| 447 // MarkSweep is not reentrant. Make sure that is the case. | 409 // MarkSweep is not reentrant. Make sure that is the case. |
| 448 ASSERT(!sweeping_); | 410 ASSERT(!sweeping_); |
| 449 sweeping_ = true; | 411 sweeping_ = true; |
| 450 Isolate* isolate = Isolate::Current(); | 412 Isolate* isolate = Isolate::Current(); |
| 451 if (FLAG_collect_code) { | |
| 452 TryDetachingCode(); | |
| 453 } | |
| 454 | 413 |
| 455 NoHandleScope no_handles(isolate); | 414 NoHandleScope no_handles(isolate); |
| 456 | 415 |
| 457 if (FLAG_print_free_list_before_gc) { | 416 if (FLAG_print_free_list_before_gc) { |
| 458 OS::Print("Data Freelist (before GC):\n"); | 417 OS::Print("Data Freelist (before GC):\n"); |
| 459 freelist_[HeapPage::kData].Print(); | 418 freelist_[HeapPage::kData].Print(); |
| 460 OS::Print("Executable Freelist (before GC):\n"); | 419 OS::Print("Executable Freelist (before GC):\n"); |
| 461 freelist_[HeapPage::kExecutable].Print(); | 420 freelist_[HeapPage::kExecutable].Print(); |
| 462 } | 421 } |
| 463 | 422 |
| 464 if (FLAG_verify_before_gc) { | 423 if (FLAG_verify_before_gc) { |
| 465 OS::PrintErr("Verifying before MarkSweep..."); | 424 OS::PrintErr("Verifying before MarkSweep..."); |
| 466 heap_->Verify(); | 425 heap_->Verify(); |
| 467 OS::PrintErr(" done.\n"); | 426 OS::PrintErr(" done.\n"); |
| 468 } | 427 } |
| 469 | 428 |
| 470 const int64_t start = OS::GetCurrentTimeMicros(); | 429 const int64_t start = OS::GetCurrentTimeMicros(); |
| 471 | 430 |
| 472 // Mark all reachable old-gen objects. | 431 // Mark all reachable old-gen objects. |
| 432 bool collect_code = FLAG_collect_code && ShouldCollectCode(); |
| 473 GCMarker marker(heap_); | 433 GCMarker marker(heap_); |
| 474 marker.MarkObjects(isolate, this, invoke_api_callbacks); | 434 marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code); |
| 475 | 435 |
| 476 int64_t mid1 = OS::GetCurrentTimeMicros(); | 436 int64_t mid1 = OS::GetCurrentTimeMicros(); |
| 477 | 437 |
| 478 // Reset the bump allocation page to unused. | 438 // Reset the bump allocation page to unused. |
| 479 // Reset the freelists and setup sweeping. | 439 // Reset the freelists and setup sweeping. |
| 480 freelist_[HeapPage::kData].Reset(); | 440 freelist_[HeapPage::kData].Reset(); |
| 481 freelist_[HeapPage::kExecutable].Reset(); | 441 freelist_[HeapPage::kExecutable].Reset(); |
| 482 | 442 |
| 483 int64_t mid2 = OS::GetCurrentTimeMicros(); | 443 int64_t mid2 = OS::GetCurrentTimeMicros(); |
| 484 | 444 |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 return 0; | 622 return 0; |
| 663 } else { | 623 } else { |
| 664 ASSERT(total_time >= gc_time); | 624 ASSERT(total_time >= gc_time); |
| 665 int result= static_cast<int>((static_cast<double>(gc_time) / | 625 int result= static_cast<int>((static_cast<double>(gc_time) / |
| 666 static_cast<double>(total_time)) * 100); | 626 static_cast<double>(total_time)) * 100); |
| 667 return result; | 627 return result; |
| 668 } | 628 } |
| 669 } | 629 } |
| 670 | 630 |
| 671 } // namespace dart | 631 } // namespace dart |
| OLD | NEW |