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/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" |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 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, false, |
| 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 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 377 page = page->next(); | 379 page = page->next(); |
| 378 } | 380 } |
| 379 page = large_pages_; | 381 page = large_pages_; |
| 380 while (page != NULL) { | 382 while (page != NULL) { |
| 381 page->WriteProtect(read_only); | 383 page->WriteProtect(read_only); |
| 382 page = page->next(); | 384 page = page->next(); |
| 383 } | 385 } |
| 384 } | 386 } |
| 385 | 387 |
| 386 | 388 |
| 387 class CodeDetacherVisitor : public ObjectVisitor { | 389 bool PageSpace::ShouldTryCollectingCode() { |
| 388 public: | |
| 389 explicit CodeDetacherVisitor(Isolate* isolate) : ObjectVisitor(isolate) { } | |
| 390 | |
| 391 virtual void VisitObject(RawObject* obj); | |
| 392 | |
| 393 private: | |
| 394 static bool MayDetachCode(const Function& fn); | |
| 395 DISALLOW_COPY_AND_ASSIGN(CodeDetacherVisitor); | |
| 396 }; | |
| 397 | |
| 398 | |
| 399 bool CodeDetacherVisitor::MayDetachCode(const Function& fn) { | |
| 400 return fn.HasCode() && // Not already detached. | |
| 401 !fn.HasOptimizedCode() && | |
| 402 !fn.HasBreakpoint() && | |
| 403 (fn.usage_counter() > 0); | |
| 404 } | |
| 405 | |
| 406 | |
| 407 void CodeDetacherVisitor::VisitObject(RawObject* raw_obj) { | |
| 408 Isolate* isolate = Isolate::Current(); | |
| 409 HANDLESCOPE(isolate); | |
| 410 const Object& obj = Object::Handle(raw_obj); | |
| 411 if (obj.GetClassId() == kFunctionCid) { | |
| 412 const Function& fn = Function::Cast(obj); | |
| 413 if (CodeDetacherVisitor::MayDetachCode(fn)) { | |
| 414 fn.set_usage_counter(fn.usage_counter() / 2); | |
| 415 if (fn.usage_counter() == 0) { | |
| 416 if (FLAG_log_code_drop) { | |
| 417 const String& name = String::Handle(fn.name()); | |
| 418 OS::Print("Detaching code for function %s\n", name.ToCString()); | |
| 419 } | |
| 420 fn.DetachCode(); | |
| 421 } | |
| 422 } | |
| 423 } | |
| 424 } | |
| 425 | |
| 426 | |
| 427 void PageSpace::TryDetachingCode() { | |
| 428 // Try to collect code if enough time has passed since the last attempt. | 390 // Try to collect code if enough time has passed since the last attempt. |
| 429 const int64_t start = OS::GetCurrentTimeMicros(); | 391 const int64_t start = OS::GetCurrentTimeMicros(); |
| 430 const int64_t last_code_collection_in_us = | 392 const int64_t last_code_collection_in_us = |
| 431 page_space_controller_.last_code_collection_in_us(); | 393 page_space_controller_.last_code_collection_in_us(); |
| 394 | |
| 432 if ((start - last_code_collection_in_us) > | 395 if ((start - last_code_collection_in_us) > |
| 433 FLAG_code_collection_interval_in_us) { | 396 FLAG_code_collection_interval_in_us) { |
| 434 if (FLAG_log_code_drop) { | 397 if (FLAG_log_code_drop) { |
| 435 OS::Print("Trying to detach code.\n"); | 398 OS::Print("Trying to detach code.\n"); |
| 436 } | 399 } |
| 437 Isolate* isolate = Isolate::Current(); | |
| 438 CodeDetacherVisitor code_detacher(isolate); | |
| 439 heap_->IterateObjects(&code_detacher); | |
| 440 page_space_controller_.set_last_code_collection_in_us(start); | 400 page_space_controller_.set_last_code_collection_in_us(start); |
| 401 return true; | |
| 441 } | 402 } |
| 403 return false; | |
| 442 } | 404 } |
| 443 | 405 |
| 444 | 406 |
| 445 void PageSpace::MarkSweep(bool invoke_api_callbacks) { | 407 void PageSpace::MarkSweep(bool invoke_api_callbacks) { |
| 446 // MarkSweep is not reentrant. Make sure that is the case. | 408 // MarkSweep is not reentrant. Make sure that is the case. |
| 447 ASSERT(!sweeping_); | 409 ASSERT(!sweeping_); |
| 448 sweeping_ = true; | 410 sweeping_ = true; |
| 449 Isolate* isolate = Isolate::Current(); | 411 Isolate* isolate = Isolate::Current(); |
| 450 if (FLAG_collect_code) { | |
| 451 TryDetachingCode(); | |
| 452 } | |
| 453 | 412 |
| 454 NoHandleScope no_handles(isolate); | 413 NoHandleScope no_handles(isolate); |
| 455 | 414 |
| 456 if (FLAG_print_free_list_before_gc) { | 415 if (FLAG_print_free_list_before_gc) { |
| 457 OS::Print("Data Freelist (before GC):\n"); | 416 OS::Print("Data Freelist (before GC):\n"); |
| 458 freelist_[HeapPage::kData].Print(); | 417 freelist_[HeapPage::kData].Print(); |
| 459 OS::Print("Executable Freelist (before GC):\n"); | 418 OS::Print("Executable Freelist (before GC):\n"); |
| 460 freelist_[HeapPage::kExecutable].Print(); | 419 freelist_[HeapPage::kExecutable].Print(); |
| 461 } | 420 } |
| 462 | 421 |
| 463 if (FLAG_verify_before_gc) { | 422 if (FLAG_verify_before_gc) { |
| 464 OS::PrintErr("Verifying before MarkSweep..."); | 423 OS::PrintErr("Verifying before MarkSweep..."); |
| 465 heap_->Verify(); | 424 heap_->Verify(); |
| 466 OS::PrintErr(" done.\n"); | 425 OS::PrintErr(" done.\n"); |
| 467 } | 426 } |
| 468 | 427 |
| 469 const int64_t start = OS::GetCurrentTimeMicros(); | 428 const int64_t start = OS::GetCurrentTimeMicros(); |
| 470 | 429 |
| 471 // Mark all reachable old-gen objects. | 430 // Mark all reachable old-gen objects. |
| 431 bool try_collecting_code = FLAG_collect_code && ShouldTryCollectingCode(); | |
|
Ivan Posva
2013/11/19 19:24:48
collect_code and ShouldCollectCode() please.
zra
2013/11/22 17:18:54
Done.
| |
| 472 GCMarker marker(heap_); | 432 GCMarker marker(heap_); |
| 473 marker.MarkObjects(isolate, this, invoke_api_callbacks); | 433 marker.MarkObjects(isolate, this, invoke_api_callbacks, try_collecting_code); |
| 474 | 434 |
| 475 int64_t mid1 = OS::GetCurrentTimeMicros(); | 435 int64_t mid1 = OS::GetCurrentTimeMicros(); |
| 476 | 436 |
| 477 // Reset the bump allocation page to unused. | 437 // Reset the bump allocation page to unused. |
| 478 // Reset the freelists and setup sweeping. | 438 // Reset the freelists and setup sweeping. |
| 479 freelist_[HeapPage::kData].Reset(); | 439 freelist_[HeapPage::kData].Reset(); |
| 480 freelist_[HeapPage::kExecutable].Reset(); | 440 freelist_[HeapPage::kExecutable].Reset(); |
| 481 | 441 |
| 482 int64_t mid2 = OS::GetCurrentTimeMicros(); | 442 int64_t mid2 = OS::GetCurrentTimeMicros(); |
| 483 | 443 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 655 return 0; | 615 return 0; |
| 656 } else { | 616 } else { |
| 657 ASSERT(total_time >= gc_time); | 617 ASSERT(total_time >= gc_time); |
| 658 int result= static_cast<int>((static_cast<double>(gc_time) / | 618 int result= static_cast<int>((static_cast<double>(gc_time) / |
| 659 static_cast<double>(total_time)) * 100); | 619 static_cast<double>(total_time)) * 100); |
| 660 return result; | 620 return result; |
| 661 } | 621 } |
| 662 } | 622 } |
| 663 | 623 |
| 664 } // namespace dart | 624 } // namespace dart |
| OLD | NEW |