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 15 matching lines...) Expand all Loading... | |
| 26 DEFINE_FLAG(bool, print_free_list_after_gc, false, | 26 DEFINE_FLAG(bool, print_free_list_after_gc, false, |
| 27 "Print free list statistics after a GC"); | 27 "Print free list statistics after a GC"); |
| 28 DEFINE_FLAG(bool, collect_code, true, | 28 DEFINE_FLAG(bool, collect_code, true, |
| 29 "Attempt to GC infrequently used code."); | 29 "Attempt to GC infrequently used code."); |
| 30 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000, | 30 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000, |
| 31 "Time between attempts to collect unused code."); | 31 "Time between attempts to collect unused code."); |
| 32 DEFINE_FLAG(bool, log_code_drop, false, | 32 DEFINE_FLAG(bool, log_code_drop, false, |
| 33 "Emit a log message when pointers to unused code are dropped."); | 33 "Emit a log message when pointers to unused code are dropped."); |
| 34 DEFINE_FLAG(bool, always_drop_code, false, | 34 DEFINE_FLAG(bool, always_drop_code, false, |
| 35 "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"); |
| 36 DEFINE_FLAG(bool, concurrent_sweep, true, | |
| 37 "Concurrent sweep for old generation."); | |
| 36 | 38 |
| 37 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) { | 39 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) { |
| 38 ASSERT(memory->size() > VirtualMemory::PageSize()); | 40 ASSERT(memory->size() > VirtualMemory::PageSize()); |
| 39 bool is_executable = (type == kExecutable); | 41 bool is_executable = (type == kExecutable); |
| 40 memory->Commit(is_executable); | 42 memory->Commit(is_executable); |
| 41 | 43 |
| 42 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); | 44 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); |
| 43 result->memory_ = memory; | 45 result->memory_ = memory; |
| 44 result->next_ = NULL; | 46 result->next_ = NULL; |
| 45 result->executable_ = is_executable; | 47 result->executable_ = is_executable; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 prot = VirtualMemory::kReadWrite; | 116 prot = VirtualMemory::kReadWrite; |
| 115 } | 117 } |
| 116 bool status = memory_->Protect(prot); | 118 bool status = memory_->Protect(prot); |
| 117 ASSERT(status); | 119 ASSERT(status); |
| 118 } | 120 } |
| 119 | 121 |
| 120 | 122 |
| 121 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity_in_words) | 123 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity_in_words) |
| 122 : freelist_(), | 124 : freelist_(), |
| 123 heap_(heap), | 125 heap_(heap), |
| 126 pages_lock_(new Mutex), | |
|
koda
2014/08/26 23:34:48
Mutex -> Mutex()
Ivan Posva
2014/08/27 01:00:22
Done.
| |
| 124 pages_(NULL), | 127 pages_(NULL), |
| 125 pages_tail_(NULL), | 128 pages_tail_(NULL), |
| 129 exec_pages_(NULL), | |
| 130 exec_pages_tail_(NULL), | |
| 126 large_pages_(NULL), | 131 large_pages_(NULL), |
| 127 max_capacity_in_words_(max_capacity_in_words), | 132 max_capacity_in_words_(max_capacity_in_words), |
| 128 tasks_lock_(new Monitor()), | 133 tasks_lock_(new Monitor()), |
| 129 tasks_(0), | 134 tasks_(0), |
| 130 page_space_controller_(heap, | 135 page_space_controller_(heap, |
| 131 FLAG_heap_growth_space_ratio, | 136 FLAG_heap_growth_space_ratio, |
| 132 FLAG_heap_growth_rate, | 137 FLAG_heap_growth_rate, |
| 133 FLAG_heap_growth_time_ratio), | 138 FLAG_heap_growth_time_ratio), |
| 134 gc_time_micros_(0), | 139 gc_time_micros_(0), |
| 135 collections_(0) { | 140 collections_(0) { |
| 136 } | 141 } |
| 137 | 142 |
| 138 | 143 |
| 139 PageSpace::~PageSpace() { | 144 PageSpace::~PageSpace() { |
| 140 { | 145 { |
| 141 MonitorLocker ml(tasks_lock()); | 146 MonitorLocker ml(tasks_lock()); |
| 142 while (tasks() > 0) { | 147 while (tasks() > 0) { |
| 143 ml.Wait(); | 148 ml.Wait(); |
| 144 } | 149 } |
| 145 } | 150 } |
| 146 FreePages(pages_); | 151 FreePages(pages_); |
| 152 FreePages(exec_pages_); | |
| 147 FreePages(large_pages_); | 153 FreePages(large_pages_); |
| 154 delete pages_lock_; | |
| 148 delete tasks_lock_; | 155 delete tasks_lock_; |
| 149 } | 156 } |
| 150 | 157 |
| 151 | 158 |
| 152 intptr_t PageSpace::LargePageSizeInWordsFor(intptr_t size) { | 159 intptr_t PageSpace::LargePageSizeInWordsFor(intptr_t size) { |
| 153 intptr_t page_size = Utils::RoundUp(size + HeapPage::ObjectStartOffset(), | 160 intptr_t page_size = Utils::RoundUp(size + HeapPage::ObjectStartOffset(), |
| 154 VirtualMemory::PageSize()); | 161 VirtualMemory::PageSize()); |
| 155 return page_size >> kWordSizeLog2; | 162 return page_size >> kWordSizeLog2; |
| 156 } | 163 } |
| 157 | 164 |
| 158 | 165 |
| 159 HeapPage* PageSpace::AllocatePage(HeapPage::PageType type) { | 166 HeapPage* PageSpace::AllocatePage(HeapPage::PageType type) { |
| 160 HeapPage* page = HeapPage::Allocate(kPageSizeInWords, type); | 167 HeapPage* page = HeapPage::Allocate(kPageSizeInWords, type); |
| 161 if (pages_ == NULL) { | 168 |
| 162 pages_ = page; | 169 bool is_exec = (type == HeapPage::kExecutable); |
| 170 | |
| 171 MutexLocker ml(pages_lock_); | |
| 172 if (!is_exec) { | |
| 173 if (pages_ == NULL) { | |
| 174 pages_ = page; | |
| 175 } else { | |
| 176 pages_tail_->set_next(page); | |
| 177 } | |
| 178 pages_tail_ = page; | |
| 163 } else { | 179 } else { |
| 164 const bool is_protected = (pages_tail_->type() == HeapPage::kExecutable) | 180 if (exec_pages_ == NULL) { |
| 165 && FLAG_write_protect_code; | 181 exec_pages_ = page; |
| 166 if (is_protected) { | 182 } else { |
| 167 pages_tail_->WriteProtect(false); | 183 const bool is_protected = is_exec && FLAG_write_protect_code; |
|
koda
2014/08/26 23:34:49
"is_protected" relates to exec_pages_tail_, which
Ivan Posva
2014/08/27 01:00:22
Done.
| |
| 184 if (is_protected) { | |
| 185 exec_pages_tail_->WriteProtect(false); | |
| 186 } | |
| 187 exec_pages_tail_->set_next(page); | |
| 188 if (is_protected) { | |
| 189 exec_pages_tail_->WriteProtect(true); | |
| 190 } | |
| 168 } | 191 } |
| 169 pages_tail_->set_next(page); | 192 exec_pages_tail_ = page; |
| 170 if (is_protected) { | |
| 171 pages_tail_->WriteProtect(true); | |
| 172 } | |
| 173 } | 193 } |
| 174 pages_tail_ = page; | |
| 175 usage_.capacity_in_words += kPageSizeInWords; | 194 usage_.capacity_in_words += kPageSizeInWords; |
| 176 page->set_object_end(page->memory_->end()); | 195 page->set_object_end(page->memory_->end()); |
| 177 return page; | 196 return page; |
| 178 } | 197 } |
| 179 | 198 |
| 180 | 199 |
| 181 HeapPage* PageSpace::AllocateLargePage(intptr_t size, HeapPage::PageType type) { | 200 HeapPage* PageSpace::AllocateLargePage(intptr_t size, HeapPage::PageType type) { |
| 182 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); | 201 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); |
| 183 HeapPage* page = HeapPage::Allocate(page_size_in_words, type); | 202 HeapPage* page = HeapPage::Allocate(page_size_in_words, type); |
| 184 page->set_next(large_pages_); | 203 page->set_next(large_pages_); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 203 if (new_page_size_in_words < old_page_size_in_words) { | 222 if (new_page_size_in_words < old_page_size_in_words) { |
| 204 memory->Truncate(memory->start(), new_page_size_in_words << kWordSizeLog2); | 223 memory->Truncate(memory->start(), new_page_size_in_words << kWordSizeLog2); |
| 205 usage_.capacity_in_words -= old_page_size_in_words; | 224 usage_.capacity_in_words -= old_page_size_in_words; |
| 206 usage_.capacity_in_words += new_page_size_in_words; | 225 usage_.capacity_in_words += new_page_size_in_words; |
| 207 page->set_object_end(page->object_start() + new_object_size_in_bytes); | 226 page->set_object_end(page->object_start() + new_object_size_in_bytes); |
| 208 } | 227 } |
| 209 } | 228 } |
| 210 | 229 |
| 211 | 230 |
| 212 void PageSpace::FreePage(HeapPage* page, HeapPage* previous_page) { | 231 void PageSpace::FreePage(HeapPage* page, HeapPage* previous_page) { |
| 213 usage_.capacity_in_words -= (page->memory_->size() >> kWordSizeLog2); | 232 bool is_exec = (page->type() == HeapPage::kExecutable); |
| 214 // Remove the page from the list. | 233 { |
| 215 if (previous_page != NULL) { | 234 MutexLocker ml(pages_lock_); |
| 216 previous_page->set_next(page->next()); | 235 usage_.capacity_in_words -= (page->memory_->size() >> kWordSizeLog2); |
| 217 } else { | 236 if (!is_exec) { |
| 218 pages_ = page->next(); | 237 // Remove the page from the list of data pages. |
| 219 } | 238 if (previous_page != NULL) { |
| 220 if (page == pages_tail_) { | 239 previous_page->set_next(page->next()); |
| 221 pages_tail_ = previous_page; | 240 } else { |
| 241 pages_ = page->next(); | |
| 242 } | |
| 243 if (page == pages_tail_) { | |
| 244 pages_tail_ = previous_page; | |
| 245 } | |
| 246 } else { | |
| 247 // Remove the page from the list of executable pages. | |
| 248 if (previous_page != NULL) { | |
| 249 previous_page->set_next(page->next()); | |
| 250 } else { | |
| 251 exec_pages_ = page->next(); | |
| 252 } | |
| 253 if (page == exec_pages_tail_) { | |
| 254 exec_pages_tail_ = previous_page; | |
| 255 } | |
| 256 } | |
| 222 } | 257 } |
| 223 // TODO(iposva): Consider adding to a pool of empty pages. | 258 // TODO(iposva): Consider adding to a pool of empty pages. |
| 224 page->Deallocate(); | 259 page->Deallocate(); |
| 225 } | 260 } |
| 226 | 261 |
| 227 | 262 |
| 228 void PageSpace::FreeLargePage(HeapPage* page, HeapPage* previous_page) { | 263 void PageSpace::FreeLargePage(HeapPage* page, HeapPage* previous_page) { |
| 229 usage_.capacity_in_words -= (page->memory_->size() >> kWordSizeLog2); | 264 usage_.capacity_in_words -= (page->memory_->size() >> kWordSizeLog2); |
| 230 // Remove the page from the list. | 265 // Remove the page from the list. |
| 231 if (previous_page != NULL) { | 266 if (previous_page != NULL) { |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 330 } | 365 } |
| 331 | 366 |
| 332 | 367 |
| 333 void PageSpace::FreeExternal(intptr_t size) { | 368 void PageSpace::FreeExternal(intptr_t size) { |
| 334 intptr_t size_in_words = size >> kWordSizeLog2; | 369 intptr_t size_in_words = size >> kWordSizeLog2; |
| 335 usage_.external_in_words -= size_in_words; | 370 usage_.external_in_words -= size_in_words; |
| 336 } | 371 } |
| 337 | 372 |
| 338 | 373 |
| 339 bool PageSpace::Contains(uword addr) const { | 374 bool PageSpace::Contains(uword addr) const { |
| 375 MutexLocker ml(pages_lock_); | |
| 376 NoGCScope no_gc; | |
| 340 HeapPage* page = pages_; | 377 HeapPage* page = pages_; |
| 341 while (page != NULL) { | 378 while (page != NULL) { |
| 342 if (page->Contains(addr)) { | 379 if (page->Contains(addr)) { |
| 343 return true; | 380 return true; |
| 344 } | 381 } |
| 345 page = NextPageAnySize(page); | 382 page = NextPageAnySize(page); |
| 346 } | 383 } |
| 347 return false; | 384 return false; |
| 348 } | 385 } |
| 349 | 386 |
| 350 | 387 |
| 351 bool PageSpace::Contains(uword addr, HeapPage::PageType type) const { | 388 bool PageSpace::Contains(uword addr, HeapPage::PageType type) const { |
| 389 MutexLocker ml(pages_lock_); | |
| 390 NoGCScope no_gc; | |
| 352 HeapPage* page = pages_; | 391 HeapPage* page = pages_; |
| 353 while (page != NULL) { | 392 while (page != NULL) { |
| 354 if ((page->type() == type) && page->Contains(addr)) { | 393 if ((page->type() == type) && page->Contains(addr)) { |
| 355 return true; | 394 return true; |
| 356 } | 395 } |
| 357 page = NextPageAnySize(page); | 396 page = NextPageAnySize(page); |
| 358 } | 397 } |
| 359 return false; | 398 return false; |
| 360 } | 399 } |
| 361 | 400 |
| 362 | 401 |
| 363 void PageSpace::StartEndAddress(uword* start, uword* end) const { | 402 void PageSpace::StartEndAddress(uword* start, uword* end) const { |
| 364 ASSERT(pages_ != NULL || large_pages_ != NULL); | 403 MutexLocker ml(pages_lock_); |
| 404 NoGCScope no_gc; | |
| 405 ASSERT((pages_ != NULL) || (exec_pages_ != NULL) || (large_pages_ != NULL)); | |
| 365 *start = static_cast<uword>(~0); | 406 *start = static_cast<uword>(~0); |
| 366 *end = 0; | 407 *end = 0; |
| 367 for (HeapPage* page = pages_; page != NULL; page = NextPageAnySize(page)) { | 408 for (HeapPage* page = pages_; page != NULL; page = NextPageAnySize(page)) { |
| 368 *start = Utils::Minimum(*start, page->object_start()); | 409 *start = Utils::Minimum(*start, page->object_start()); |
| 369 *end = Utils::Maximum(*end, page->object_end()); | 410 *end = Utils::Maximum(*end, page->object_end()); |
| 370 } | 411 } |
| 371 ASSERT(*start != static_cast<uword>(~0)); | 412 ASSERT(*start != static_cast<uword>(~0)); |
| 372 ASSERT(*end != 0); | 413 ASSERT(*end != 0); |
| 373 } | 414 } |
| 374 | 415 |
| 375 | 416 |
| 376 void PageSpace::VisitObjects(ObjectVisitor* visitor) const { | 417 void PageSpace::VisitObjects(ObjectVisitor* visitor) const { |
| 418 MutexLocker ml(pages_lock_); | |
| 419 NoGCScope no_gc; | |
| 377 HeapPage* page = pages_; | 420 HeapPage* page = pages_; |
| 378 while (page != NULL) { | 421 while (page != NULL) { |
| 379 page->VisitObjects(visitor); | 422 page->VisitObjects(visitor); |
| 380 page = NextPageAnySize(page); | 423 page = NextPageAnySize(page); |
| 381 } | 424 } |
| 382 } | 425 } |
| 383 | 426 |
| 384 | 427 |
| 385 void PageSpace::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 428 void PageSpace::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
| 429 MutexLocker ml(pages_lock_); | |
| 430 NoGCScope no_gc; | |
| 386 HeapPage* page = pages_; | 431 HeapPage* page = pages_; |
| 387 while (page != NULL) { | 432 while (page != NULL) { |
| 388 page->VisitObjectPointers(visitor); | 433 page->VisitObjectPointers(visitor); |
| 389 page = NextPageAnySize(page); | 434 page = NextPageAnySize(page); |
| 390 } | 435 } |
| 391 } | 436 } |
| 392 | 437 |
| 393 | 438 |
| 394 RawObject* PageSpace::FindObject(FindObjectVisitor* visitor, | 439 RawObject* PageSpace::FindObject(FindObjectVisitor* visitor, |
| 395 HeapPage::PageType type) const { | 440 HeapPage::PageType type) const { |
| 396 ASSERT(Isolate::Current()->no_gc_scope_depth() != 0); | 441 ASSERT(Isolate::Current()->no_gc_scope_depth() != 0); |
| 442 MutexLocker ml(pages_lock_); | |
| 443 NoGCScope no_gc; | |
| 397 HeapPage* page = pages_; | 444 HeapPage* page = pages_; |
| 398 while (page != NULL) { | 445 while (page != NULL) { |
| 399 if (page->type() == type) { | 446 if (page->type() == type) { |
| 400 RawObject* obj = page->FindObject(visitor); | 447 RawObject* obj = page->FindObject(visitor); |
| 401 if (obj != Object::null()) { | 448 if (obj != Object::null()) { |
| 402 return obj; | 449 return obj; |
| 403 } | 450 } |
| 404 } | 451 } |
| 405 page = NextPageAnySize(page); | 452 page = NextPageAnySize(page); |
| 406 } | 453 } |
| 407 return Object::null(); | 454 return Object::null(); |
| 408 } | 455 } |
| 409 | 456 |
| 410 | 457 |
| 411 void PageSpace::WriteProtect(bool read_only) { | 458 void PageSpace::WriteProtect(bool read_only) { |
| 459 MutexLocker ml(pages_lock_); | |
| 460 NoGCScope no_gc; | |
| 412 HeapPage* page = pages_; | 461 HeapPage* page = pages_; |
| 413 while (page != NULL) { | 462 while (page != NULL) { |
| 414 page->WriteProtect(read_only); | 463 page->WriteProtect(read_only); |
| 415 page = NextPageAnySize(page); | 464 page = NextPageAnySize(page); |
| 416 } | 465 } |
| 417 } | 466 } |
| 418 | 467 |
| 419 | 468 |
| 420 void PageSpace::PrintToJSONObject(JSONObject* object) { | 469 void PageSpace::PrintToJSONObject(JSONObject* object) { |
| 421 Isolate* isolate = Isolate::Current(); | 470 Isolate* isolate = Isolate::Current(); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 466 heap_map.AddProperty("unit_size_bytes", | 515 heap_map.AddProperty("unit_size_bytes", |
| 467 static_cast<intptr_t>(kObjectAlignment)); | 516 static_cast<intptr_t>(kObjectAlignment)); |
| 468 heap_map.AddProperty("page_size_bytes", kPageSizeInWords * kWordSize); | 517 heap_map.AddProperty("page_size_bytes", kPageSizeInWords * kWordSize); |
| 469 { | 518 { |
| 470 JSONObject class_list(&heap_map, "class_list"); | 519 JSONObject class_list(&heap_map, "class_list"); |
| 471 isolate->class_table()->PrintToJSONObject(&class_list); | 520 isolate->class_table()->PrintToJSONObject(&class_list); |
| 472 } | 521 } |
| 473 { | 522 { |
| 474 // "pages" is an array [page0, page1, ..., pageN], each page of the form | 523 // "pages" is an array [page0, page1, ..., pageN], each page of the form |
| 475 // {"object_start": "0x...", "objects": [size, class id, size, ...]} | 524 // {"object_start": "0x...", "objects": [size, class id, size, ...]} |
| 525 MutexLocker ml(pages_lock_); | |
| 526 NoGCScope no_gc; | |
| 476 JSONArray all_pages(&heap_map, "pages"); | 527 JSONArray all_pages(&heap_map, "pages"); |
| 477 for (HeapPage* page = pages_; page != NULL; page = page->next()) { | 528 for (HeapPage* page = pages_; page != NULL; page = page->next()) { |
| 478 JSONObject page_container(&all_pages); | 529 JSONObject page_container(&all_pages); |
| 479 page_container.AddPropertyF("object_start", | 530 page_container.AddPropertyF("object_start", |
| 480 "0x%" Px "", page->object_start()); | 531 "0x%" Px "", page->object_start()); |
| 481 JSONArray page_map(&page_container, "objects"); | 532 JSONArray page_map(&page_container, "objects"); |
| 482 HeapMapAsJSONVisitor printer(&page_map); | 533 HeapMapAsJSONVisitor printer(&page_map); |
| 483 page->VisitObjects(&printer); | 534 page->VisitObjects(&printer); |
| 484 } | 535 } |
| 536 for (HeapPage* page = exec_pages_; page != NULL; page = page->next()) { | |
| 537 JSONObject page_container(&all_pages); | |
| 538 page_container.AddPropertyF("object_start", | |
| 539 "0x%" Px "", page->object_start()); | |
| 540 JSONArray page_map(&page_container, "objects"); | |
| 541 HeapMapAsJSONVisitor printer(&page_map); | |
| 542 page->VisitObjects(&printer); | |
| 543 } | |
| 485 } | 544 } |
| 486 } | 545 } |
| 487 | 546 |
| 488 | 547 |
| 489 bool PageSpace::ShouldCollectCode() { | 548 bool PageSpace::ShouldCollectCode() { |
| 490 // Try to collect code if enough time has passed since the last attempt. | 549 // Try to collect code if enough time has passed since the last attempt. |
| 491 const int64_t start = OS::GetCurrentTimeMicros(); | 550 const int64_t start = OS::GetCurrentTimeMicros(); |
| 492 const int64_t last_code_collection_in_us = | 551 const int64_t last_code_collection_in_us = |
| 493 page_space_controller_.last_code_collection_in_us(); | 552 page_space_controller_.last_code_collection_in_us(); |
| 494 | 553 |
| 495 if ((start - last_code_collection_in_us) > | 554 if ((start - last_code_collection_in_us) > |
| 496 FLAG_code_collection_interval_in_us) { | 555 FLAG_code_collection_interval_in_us) { |
| 497 if (FLAG_log_code_drop) { | 556 if (FLAG_log_code_drop) { |
| 498 OS::Print("Trying to detach code.\n"); | 557 OS::Print("Trying to detach code.\n"); |
| 499 } | 558 } |
| 500 page_space_controller_.set_last_code_collection_in_us(start); | 559 page_space_controller_.set_last_code_collection_in_us(start); |
| 501 return true; | 560 return true; |
| 502 } | 561 } |
| 503 return false; | 562 return false; |
| 504 } | 563 } |
| 505 | 564 |
| 506 | 565 |
| 507 void PageSpace::WriteProtectCode(bool read_only) { | 566 void PageSpace::WriteProtectCode(bool read_only) { |
| 508 if (FLAG_write_protect_code) { | 567 if (FLAG_write_protect_code) { |
| 509 HeapPage* current_page = pages_; | 568 MutexLocker ml(pages_lock_); |
| 510 while (current_page != NULL) { | 569 NoGCScope no_gc; |
| 511 if (current_page->type() == HeapPage::kExecutable) { | 570 // No need to go through all of the data pages first. |
| 512 current_page->WriteProtect(read_only); | 571 HeapPage* page = exec_pages_; |
| 572 while (page != NULL) { | |
| 573 ASSERT(page->type() == HeapPage::kExecutable); | |
| 574 page->WriteProtect(read_only); | |
| 575 page = page->next(); | |
| 576 } | |
| 577 page = large_pages_; | |
| 578 while (page != NULL) { | |
| 579 if (page->type() == HeapPage::kExecutable) { | |
| 580 page->WriteProtect(read_only); | |
| 513 } | 581 } |
| 514 current_page = NextPageAnySize(current_page); | 582 page = page->next(); |
| 515 } | 583 } |
| 516 } | 584 } |
| 517 } | 585 } |
| 518 | 586 |
| 519 | 587 |
| 520 void PageSpace::MarkSweep(bool invoke_api_callbacks) { | 588 void PageSpace::MarkSweep(bool invoke_api_callbacks) { |
| 521 Isolate* isolate = heap_->isolate(); | 589 Isolate* isolate = heap_->isolate(); |
| 522 ASSERT(isolate == Isolate::Current()); | 590 ASSERT(isolate == Isolate::Current()); |
| 523 | 591 |
| 524 // Wait for pending tasks to complete and then account for the driver task. | 592 // Wait for pending tasks to complete and then account for the driver task. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 562 int64_t mid1 = OS::GetCurrentTimeMicros(); | 630 int64_t mid1 = OS::GetCurrentTimeMicros(); |
| 563 | 631 |
| 564 // Reset the bump allocation page to unused. | 632 // Reset the bump allocation page to unused. |
| 565 // Reset the freelists and setup sweeping. | 633 // Reset the freelists and setup sweeping. |
| 566 freelist_[HeapPage::kData].Reset(); | 634 freelist_[HeapPage::kData].Reset(); |
| 567 freelist_[HeapPage::kExecutable].Reset(); | 635 freelist_[HeapPage::kExecutable].Reset(); |
| 568 | 636 |
| 569 int64_t mid2 = OS::GetCurrentTimeMicros(); | 637 int64_t mid2 = OS::GetCurrentTimeMicros(); |
| 570 int64_t mid3 = 0; | 638 int64_t mid3 = 0; |
| 571 | 639 |
| 572 GCSweeper sweeper(heap_); | 640 { |
| 641 GCSweeper sweeper(heap_); | |
| 573 | 642 |
| 574 // During stop-the-world phases we should use bulk lock when adding elements | 643 // During stop-the-world phases we should use bulk lock when adding elements |
| 575 // to the free list. | 644 // to the free list. |
| 576 { | |
| 577 MutexLocker mld(freelist_[HeapPage::kData].mutex()); | 645 MutexLocker mld(freelist_[HeapPage::kData].mutex()); |
| 578 MutexLocker mle(freelist_[HeapPage::kExecutable].mutex()); | 646 MutexLocker mle(freelist_[HeapPage::kExecutable].mutex()); |
| 579 | 647 |
| 648 // Large and executable pages are always swept immediately. | |
| 580 HeapPage* prev_page = NULL; | 649 HeapPage* prev_page = NULL; |
| 581 HeapPage* page = pages_; | 650 HeapPage* page = large_pages_; |
| 582 while (page != NULL) { | |
| 583 HeapPage* next_page = page->next(); | |
| 584 bool page_in_use = sweeper.SweepPage(page, &freelist_[page->type()]); | |
| 585 if (page_in_use) { | |
| 586 prev_page = page; | |
| 587 } else { | |
| 588 FreePage(page, prev_page); | |
| 589 } | |
| 590 // Advance to the next page. | |
| 591 page = next_page; | |
| 592 } | |
| 593 | |
| 594 mid3 = OS::GetCurrentTimeMicros(); | |
| 595 | |
| 596 prev_page = NULL; | |
| 597 page = large_pages_; | |
| 598 while (page != NULL) { | 651 while (page != NULL) { |
| 599 HeapPage* next_page = page->next(); | 652 HeapPage* next_page = page->next(); |
| 600 const intptr_t words_to_end = sweeper.SweepLargePage(page); | 653 const intptr_t words_to_end = sweeper.SweepLargePage(page); |
| 601 if (words_to_end == 0) { | 654 if (words_to_end == 0) { |
| 602 FreeLargePage(page, prev_page); | 655 FreeLargePage(page, prev_page); |
| 603 } else { | 656 } else { |
| 604 TruncateLargePage(page, words_to_end << kWordSizeLog2); | 657 TruncateLargePage(page, words_to_end << kWordSizeLog2); |
| 605 prev_page = page; | 658 prev_page = page; |
| 606 } | 659 } |
| 607 // Advance to the next page. | 660 // Advance to the next page. |
| 608 page = next_page; | 661 page = next_page; |
| 609 } | 662 } |
| 663 | |
| 664 prev_page = NULL; | |
| 665 page = exec_pages_; | |
| 666 FreeList* freelist = &freelist_[HeapPage::kExecutable]; | |
| 667 while (page != NULL) { | |
| 668 HeapPage* next_page = page->next(); | |
| 669 bool page_in_use = sweeper.SweepPage(page, freelist); | |
| 670 if (page_in_use) { | |
| 671 prev_page = page; | |
| 672 } else { | |
| 673 FreePage(page, prev_page); | |
| 674 } | |
| 675 // Advance to the next page. | |
| 676 page = next_page; | |
| 677 } | |
| 678 | |
| 679 mid3 = OS::GetCurrentTimeMicros(); | |
| 680 | |
| 681 if (!FLAG_concurrent_sweep) { | |
| 682 // Sweep all regular sized pages now. | |
| 683 prev_page = NULL; | |
| 684 page = pages_; | |
| 685 while (page != NULL) { | |
| 686 HeapPage* next_page = page->next(); | |
| 687 bool page_in_use = sweeper.SweepPage(page, &freelist_[page->type()]); | |
| 688 if (page_in_use) { | |
| 689 prev_page = page; | |
| 690 } else { | |
| 691 FreePage(page, prev_page); | |
| 692 } | |
| 693 // Advance to the next page. | |
| 694 page = next_page; | |
| 695 } | |
| 696 } else { | |
| 697 // Start the concurrent sweeper task now. | |
| 698 GCSweeper::SweepConcurrent( | |
| 699 isolate, this, pages_, pages_tail_, &freelist_[HeapPage::kData]); | |
| 700 } | |
| 610 } | 701 } |
| 611 | 702 |
| 612 // Make code pages read-only. | 703 // Make code pages read-only. |
| 613 WriteProtectCode(true); | 704 WriteProtectCode(true); |
| 614 | 705 |
| 615 int64_t end = OS::GetCurrentTimeMicros(); | 706 int64_t end = OS::GetCurrentTimeMicros(); |
| 616 | 707 |
| 617 // Record signals for growth control. Include size of external allocations. | 708 // Record signals for growth control. Include size of external allocations. |
| 618 page_space_controller_.EvaluateGarbageCollection(usage_before, usage_, | 709 page_space_controller_.EvaluateGarbageCollection(usage_before, usage_, |
| 619 start, end); | 710 start, end); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 632 | 723 |
| 633 if (FLAG_verify_after_gc) { | 724 if (FLAG_verify_after_gc) { |
| 634 OS::PrintErr("Verifying after MarkSweep..."); | 725 OS::PrintErr("Verifying after MarkSweep..."); |
| 635 heap_->Verify(); | 726 heap_->Verify(); |
| 636 OS::PrintErr(" done.\n"); | 727 OS::PrintErr(" done.\n"); |
| 637 } | 728 } |
| 638 | 729 |
| 639 // Done, reset the task count. | 730 // Done, reset the task count. |
| 640 { | 731 { |
| 641 MonitorLocker ml(tasks_lock()); | 732 MonitorLocker ml(tasks_lock()); |
| 642 ASSERT(tasks() == 1); | |
| 643 set_tasks(tasks() - 1); | 733 set_tasks(tasks() - 1); |
| 644 ml.Notify(); | 734 ml.Notify(); |
| 645 } | 735 } |
| 646 } | 736 } |
| 647 | 737 |
| 648 | 738 |
| 649 PageSpaceController::PageSpaceController(Heap* heap, | 739 PageSpaceController::PageSpaceController(Heap* heap, |
| 650 int heap_growth_ratio, | 740 int heap_growth_ratio, |
| 651 int heap_growth_max, | 741 int heap_growth_max, |
| 652 int garbage_collection_time_ratio) | 742 int garbage_collection_time_ratio) |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 665 | 755 |
| 666 | 756 |
| 667 bool PageSpaceController::NeedsGarbageCollection(SpaceUsage after) const { | 757 bool PageSpaceController::NeedsGarbageCollection(SpaceUsage after) const { |
| 668 if (!is_enabled_) { | 758 if (!is_enabled_) { |
| 669 return false; | 759 return false; |
| 670 } | 760 } |
| 671 if (heap_growth_ratio_ == 100) { | 761 if (heap_growth_ratio_ == 100) { |
| 672 return false; | 762 return false; |
| 673 } | 763 } |
| 674 intptr_t capacity_increase_in_words = | 764 intptr_t capacity_increase_in_words = |
| 675 after.capacity_in_words - last_usage_.capacity_in_words; | 765 after.capacity_in_words - last_usage_.capacity_in_words; |
| 676 ASSERT(capacity_increase_in_words >= 0); | 766 // The concurrent sweeper might have freed more capacity than was allocated. |
| 767 capacity_increase_in_words = | |
| 768 Utils::Maximum<intptr_t>(0, capacity_increase_in_words); | |
| 677 capacity_increase_in_words = | 769 capacity_increase_in_words = |
| 678 Utils::RoundUp(capacity_increase_in_words, PageSpace::kPageSizeInWords); | 770 Utils::RoundUp(capacity_increase_in_words, PageSpace::kPageSizeInWords); |
| 679 intptr_t capacity_increase_in_pages = | 771 intptr_t capacity_increase_in_pages = |
| 680 capacity_increase_in_words / PageSpace::kPageSizeInWords; | 772 capacity_increase_in_words / PageSpace::kPageSizeInWords; |
| 681 double multiplier = 1.0; | 773 double multiplier = 1.0; |
| 682 // To avoid waste, the first GC should be triggered before too long. After | 774 // To avoid waste, the first GC should be triggered before too long. After |
| 683 // kInitialTimeoutSeconds, gradually lower the capacity limit. | 775 // kInitialTimeoutSeconds, gradually lower the capacity limit. |
| 684 static const double kInitialTimeoutSeconds = 1.00; | 776 static const double kInitialTimeoutSeconds = 1.00; |
| 685 if (history_.IsEmpty()) { | 777 if (history_.IsEmpty()) { |
| 686 double seconds_since_init = MicrosecondsToSeconds( | 778 double seconds_since_init = MicrosecondsToSeconds( |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 760 return 0; | 852 return 0; |
| 761 } else { | 853 } else { |
| 762 ASSERT(total_time >= gc_time); | 854 ASSERT(total_time >= gc_time); |
| 763 int result= static_cast<int>((static_cast<double>(gc_time) / | 855 int result= static_cast<int>((static_cast<double>(gc_time) / |
| 764 static_cast<double>(total_time)) * 100); | 856 static_cast<double>(total_time)) * 100); |
| 765 return result; | 857 return result; |
| 766 } | 858 } |
| 767 } | 859 } |
| 768 | 860 |
| 769 } // namespace dart | 861 } // namespace dart |
| OLD | NEW |