| 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 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 if (FLAG_write_protect_code) { | 193 if (FLAG_write_protect_code) { |
| 194 exec_pages_tail_->WriteProtect(false); | 194 exec_pages_tail_->WriteProtect(false); |
| 195 } | 195 } |
| 196 exec_pages_tail_->set_next(page); | 196 exec_pages_tail_->set_next(page); |
| 197 if (FLAG_write_protect_code) { | 197 if (FLAG_write_protect_code) { |
| 198 exec_pages_tail_->WriteProtect(true); | 198 exec_pages_tail_->WriteProtect(true); |
| 199 } | 199 } |
| 200 } | 200 } |
| 201 exec_pages_tail_ = page; | 201 exec_pages_tail_ = page; |
| 202 } | 202 } |
| 203 usage_.capacity_in_words += kPageSizeInWords; | 203 IncreaseCapacityInWordsLocked(kPageSizeInWords); |
| 204 page->set_object_end(page->memory_->end()); | 204 page->set_object_end(page->memory_->end()); |
| 205 return page; | 205 return page; |
| 206 } | 206 } |
| 207 | 207 |
| 208 | 208 |
| 209 HeapPage* PageSpace::AllocateLargePage(intptr_t size, HeapPage::PageType type) { | 209 HeapPage* PageSpace::AllocateLargePage(intptr_t size, HeapPage::PageType type) { |
| 210 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); | 210 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); |
| 211 HeapPage* page = HeapPage::Allocate(page_size_in_words, type); | 211 HeapPage* page = HeapPage::Allocate(page_size_in_words, type); |
| 212 page->set_next(large_pages_); | 212 page->set_next(large_pages_); |
| 213 large_pages_ = page; | 213 large_pages_ = page; |
| 214 usage_.capacity_in_words += page_size_in_words; | 214 IncreaseCapacityInWords(page_size_in_words); |
| 215 // Only one object in this page (at least until String::MakeExternal or | 215 // Only one object in this page (at least until String::MakeExternal or |
| 216 // Array::MakeArray is called). | 216 // Array::MakeArray is called). |
| 217 page->set_object_end(page->object_start() + size); | 217 page->set_object_end(page->object_start() + size); |
| 218 return page; | 218 return page; |
| 219 } | 219 } |
| 220 | 220 |
| 221 | 221 |
| 222 void PageSpace::TruncateLargePage(HeapPage* page, | 222 void PageSpace::TruncateLargePage(HeapPage* page, |
| 223 intptr_t new_object_size_in_bytes) { | 223 intptr_t new_object_size_in_bytes) { |
| 224 const intptr_t old_object_size_in_bytes = | 224 const intptr_t old_object_size_in_bytes = |
| 225 page->object_end() - page->object_start(); | 225 page->object_end() - page->object_start(); |
| 226 ASSERT(new_object_size_in_bytes <= old_object_size_in_bytes); | 226 ASSERT(new_object_size_in_bytes <= old_object_size_in_bytes); |
| 227 const intptr_t new_page_size_in_words = | 227 const intptr_t new_page_size_in_words = |
| 228 LargePageSizeInWordsFor(new_object_size_in_bytes); | 228 LargePageSizeInWordsFor(new_object_size_in_bytes); |
| 229 VirtualMemory* memory = page->memory_; | 229 VirtualMemory* memory = page->memory_; |
| 230 const intptr_t old_page_size_in_words = (memory->size() >> kWordSizeLog2); | 230 const intptr_t old_page_size_in_words = (memory->size() >> kWordSizeLog2); |
| 231 if (new_page_size_in_words < old_page_size_in_words) { | 231 if (new_page_size_in_words < old_page_size_in_words) { |
| 232 memory->Truncate(new_page_size_in_words << kWordSizeLog2); | 232 memory->Truncate(new_page_size_in_words << kWordSizeLog2); |
| 233 usage_.capacity_in_words -= old_page_size_in_words; | 233 IncreaseCapacityInWords(new_page_size_in_words - old_page_size_in_words); |
| 234 usage_.capacity_in_words += new_page_size_in_words; | |
| 235 page->set_object_end(page->object_start() + new_object_size_in_bytes); | 234 page->set_object_end(page->object_start() + new_object_size_in_bytes); |
| 236 } | 235 } |
| 237 } | 236 } |
| 238 | 237 |
| 239 | 238 |
| 240 void PageSpace::FreePage(HeapPage* page, HeapPage* previous_page) { | 239 void PageSpace::FreePage(HeapPage* page, HeapPage* previous_page) { |
| 241 bool is_exec = (page->type() == HeapPage::kExecutable); | 240 bool is_exec = (page->type() == HeapPage::kExecutable); |
| 242 { | 241 { |
| 243 MutexLocker ml(pages_lock_); | 242 MutexLocker ml(pages_lock_); |
| 244 usage_.capacity_in_words -= (page->memory_->size() >> kWordSizeLog2); | 243 IncreaseCapacityInWordsLocked(-(page->memory_->size() >> kWordSizeLog2)); |
| 245 if (!is_exec) { | 244 if (!is_exec) { |
| 246 // Remove the page from the list of data pages. | 245 // Remove the page from the list of data pages. |
| 247 if (previous_page != NULL) { | 246 if (previous_page != NULL) { |
| 248 previous_page->set_next(page->next()); | 247 previous_page->set_next(page->next()); |
| 249 } else { | 248 } else { |
| 250 pages_ = page->next(); | 249 pages_ = page->next(); |
| 251 } | 250 } |
| 252 if (page == pages_tail_) { | 251 if (page == pages_tail_) { |
| 253 pages_tail_ = previous_page; | 252 pages_tail_ = previous_page; |
| 254 } | 253 } |
| 255 } else { | 254 } else { |
| 256 // Remove the page from the list of executable pages. | 255 // Remove the page from the list of executable pages. |
| 257 if (previous_page != NULL) { | 256 if (previous_page != NULL) { |
| 258 previous_page->set_next(page->next()); | 257 previous_page->set_next(page->next()); |
| 259 } else { | 258 } else { |
| 260 exec_pages_ = page->next(); | 259 exec_pages_ = page->next(); |
| 261 } | 260 } |
| 262 if (page == exec_pages_tail_) { | 261 if (page == exec_pages_tail_) { |
| 263 exec_pages_tail_ = previous_page; | 262 exec_pages_tail_ = previous_page; |
| 264 } | 263 } |
| 265 } | 264 } |
| 266 } | 265 } |
| 267 // TODO(iposva): Consider adding to a pool of empty pages. | 266 // TODO(iposva): Consider adding to a pool of empty pages. |
| 268 page->Deallocate(); | 267 page->Deallocate(); |
| 269 } | 268 } |
| 270 | 269 |
| 271 | 270 |
| 272 void PageSpace::FreeLargePage(HeapPage* page, HeapPage* previous_page) { | 271 void PageSpace::FreeLargePage(HeapPage* page, HeapPage* previous_page) { |
| 273 usage_.capacity_in_words -= (page->memory_->size() >> kWordSizeLog2); | 272 IncreaseCapacityInWords(-(page->memory_->size() >> kWordSizeLog2)); |
| 274 // Remove the page from the list. | 273 // Remove the page from the list. |
| 275 if (previous_page != NULL) { | 274 if (previous_page != NULL) { |
| 276 previous_page->set_next(page->next()); | 275 previous_page->set_next(page->next()); |
| 277 } else { | 276 } else { |
| 278 large_pages_ = page->next(); | 277 large_pages_ = page->next(); |
| 279 } | 278 } |
| 280 page->Deallocate(); | 279 page->Deallocate(); |
| 281 } | 280 } |
| 282 | 281 |
| 283 | 282 |
| 284 void PageSpace::FreePages(HeapPage* pages) { | 283 void PageSpace::FreePages(HeapPage* pages) { |
| 285 HeapPage* page = pages; | 284 HeapPage* page = pages; |
| 286 while (page != NULL) { | 285 while (page != NULL) { |
| 287 HeapPage* next = page->next(); | 286 HeapPage* next = page->next(); |
| 288 page->Deallocate(); | 287 page->Deallocate(); |
| 289 page = next; | 288 page = next; |
| 290 } | 289 } |
| 291 } | 290 } |
| 292 | 291 |
| 293 | 292 |
| 294 uword PageSpace::TryAllocateInFreshPage(intptr_t size, | 293 uword PageSpace::TryAllocateInFreshPage(intptr_t size, |
| 295 HeapPage::PageType type, | 294 HeapPage::PageType type, |
| 296 GrowthPolicy growth_policy, | 295 GrowthPolicy growth_policy, |
| 297 bool is_locked) { | 296 bool is_locked) { |
| 298 ASSERT(size < kAllocatablePageSize); | 297 ASSERT(size < kAllocatablePageSize); |
| 299 uword result = 0; | 298 uword result = 0; |
| 300 SpaceUsage after_allocation = usage_; | 299 SpaceUsage after_allocation = GetCurrentUsage(); |
| 301 after_allocation.used_in_words += size >> kWordSizeLog2; | 300 after_allocation.used_in_words += size >> kWordSizeLog2; |
| 302 // Can we grow by one page? | 301 // Can we grow by one page? |
| 303 after_allocation.capacity_in_words += kPageSizeInWords; | 302 after_allocation.capacity_in_words += kPageSizeInWords; |
| 304 if ((growth_policy == kForceGrowth || | 303 if ((growth_policy == kForceGrowth || |
| 305 !page_space_controller_.NeedsGarbageCollection(after_allocation)) && | 304 !page_space_controller_.NeedsGarbageCollection(after_allocation)) && |
| 306 CanIncreaseCapacityInWords(kPageSizeInWords)) { | 305 CanIncreaseCapacityInWords(kPageSizeInWords)) { |
| 307 HeapPage* page = AllocatePage(type); | 306 HeapPage* page = AllocatePage(type); |
| 308 ASSERT(page != NULL); | 307 ASSERT(page != NULL); |
| 309 // Start of the newly allocated page is the allocated object. | 308 // Start of the newly allocated page is the allocated object. |
| 310 result = page->object_start(); | 309 result = page->object_start(); |
| 311 usage_ = after_allocation; | 310 // Note: usage_.capacity_in_words is increased by AllocatePage. |
| 311 usage_.used_in_words += size >> kWordSizeLog2; |
| 312 // Enqueue the remainder in the free list. | 312 // Enqueue the remainder in the free list. |
| 313 uword free_start = result + size; | 313 uword free_start = result + size; |
| 314 intptr_t free_size = page->object_end() - free_start; | 314 intptr_t free_size = page->object_end() - free_start; |
| 315 if (free_size > 0) { | 315 if (free_size > 0) { |
| 316 if (is_locked) { | 316 if (is_locked) { |
| 317 freelist_[type].FreeLocked(free_start, free_size); | 317 freelist_[type].FreeLocked(free_start, free_size); |
| 318 } else { | 318 } else { |
| 319 freelist_[type].Free(free_start, free_size); | 319 freelist_[type].Free(free_start, free_size); |
| 320 } | 320 } |
| 321 } | 321 } |
| 322 } | 322 } |
| 323 return result; | 323 return result; |
| 324 } | 324 } |
| 325 | 325 |
| 326 | 326 |
| 327 uword PageSpace::TryAllocateInternal(intptr_t size, | 327 uword PageSpace::TryAllocateInternal(intptr_t size, |
| 328 HeapPage::PageType type, | 328 HeapPage::PageType type, |
| 329 GrowthPolicy growth_policy, | 329 GrowthPolicy growth_policy, |
| 330 bool is_protected, | 330 bool is_protected, |
| 331 bool is_locked) { | 331 bool is_locked) { |
| 332 ASSERT(size >= kObjectAlignment); | 332 ASSERT(size >= kObjectAlignment); |
| 333 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 333 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
| 334 #ifdef DEBUG | 334 #ifdef DEBUG |
| 335 SpaceUsage usage_before = usage_; | 335 SpaceUsage usage_before = GetCurrentUsage(); |
| 336 #endif | 336 #endif |
| 337 uword result = 0; | 337 uword result = 0; |
| 338 if (size < kAllocatablePageSize) { | 338 if (size < kAllocatablePageSize) { |
| 339 if (is_locked) { | 339 if (is_locked) { |
| 340 result = freelist_[type].TryAllocateLocked(size, is_protected); | 340 result = freelist_[type].TryAllocateLocked(size, is_protected); |
| 341 } else { | 341 } else { |
| 342 result = freelist_[type].TryAllocate(size, is_protected); | 342 result = freelist_[type].TryAllocate(size, is_protected); |
| 343 } | 343 } |
| 344 if (result == 0) { | 344 if (result == 0) { |
| 345 result = TryAllocateInFreshPage(size, type, growth_policy, is_locked); | 345 result = TryAllocateInFreshPage(size, type, growth_policy, is_locked); |
| 346 // usage_ is updated by the call above. | 346 // usage_ is updated by the call above. |
| 347 } else { | 347 } else { |
| 348 usage_.used_in_words += size >> kWordSizeLog2; | 348 usage_.used_in_words += size >> kWordSizeLog2; |
| 349 } | 349 } |
| 350 } else { | 350 } else { |
| 351 // Large page allocation. | 351 // Large page allocation. |
| 352 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); | 352 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); |
| 353 if ((page_size_in_words << kWordSizeLog2) < size) { | 353 if ((page_size_in_words << kWordSizeLog2) < size) { |
| 354 // On overflow we fail to allocate. | 354 // On overflow we fail to allocate. |
| 355 return 0; | 355 return 0; |
| 356 } | 356 } |
| 357 SpaceUsage after_allocation = usage_; | 357 SpaceUsage after_allocation = GetCurrentUsage(); |
| 358 after_allocation.used_in_words += size >> kWordSizeLog2; | 358 after_allocation.used_in_words += size >> kWordSizeLog2; |
| 359 after_allocation.capacity_in_words += page_size_in_words; | 359 after_allocation.capacity_in_words += page_size_in_words; |
| 360 if ((growth_policy == kForceGrowth || | 360 if ((growth_policy == kForceGrowth || |
| 361 !page_space_controller_.NeedsGarbageCollection(after_allocation)) && | 361 !page_space_controller_.NeedsGarbageCollection(after_allocation)) && |
| 362 CanIncreaseCapacityInWords(page_size_in_words)) { | 362 CanIncreaseCapacityInWords(page_size_in_words)) { |
| 363 HeapPage* page = AllocateLargePage(size, type); | 363 HeapPage* page = AllocateLargePage(size, type); |
| 364 if (page != NULL) { | 364 if (page != NULL) { |
| 365 result = page->object_start(); | 365 result = page->object_start(); |
| 366 usage_ = after_allocation; | 366 // Note: usage_.capacity_in_words is increased by AllocateLargePage. |
| 367 usage_.used_in_words += size >> kWordSizeLog2; |
| 367 } | 368 } |
| 368 } | 369 } |
| 369 } | 370 } |
| 370 if (result != 0) { | 371 if (result != 0) { |
| 371 #ifdef DEBUG | 372 #ifdef DEBUG |
| 372 // A successful allocation should increase usage_. | 373 // A successful allocation should increase usage_. |
| 373 ASSERT(usage_before.used_in_words < usage_.used_in_words); | 374 ASSERT(usage_before.used_in_words < usage_.used_in_words); |
| 374 #endif | 375 #endif |
| 375 if (FLAG_compiler_stats && (type == HeapPage::kExecutable)) { | 376 if (FLAG_compiler_stats && (type == HeapPage::kExecutable)) { |
| 376 CompilerStats::code_allocated += size; | 377 CompilerStats::code_allocated += size; |
| 377 } | 378 } |
| 378 } else { | 379 } else { |
| 379 #ifdef DEBUG | 380 #ifdef DEBUG |
| 380 // A failed allocation should not change usage_. | 381 // A failed allocation should not change used_in_words. |
| 381 ASSERT(usage_before.used_in_words == usage_.used_in_words); | 382 ASSERT(usage_before.used_in_words == usage_.used_in_words); |
| 382 ASSERT(usage_before.capacity_in_words == usage_.capacity_in_words); | |
| 383 #endif | 383 #endif |
| 384 } | 384 } |
| 385 ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset); | 385 ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset); |
| 386 return result; | 386 return result; |
| 387 } | 387 } |
| 388 | 388 |
| 389 | 389 |
| 390 void PageSpace::AcquireDataLock() { | 390 void PageSpace::AcquireDataLock() { |
| 391 freelist_[HeapPage::kData].mutex()->Lock(); | 391 freelist_[HeapPage::kData].mutex()->Lock(); |
| 392 } | 392 } |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 heap_->Verify(); | 662 heap_->Verify(); |
| 663 OS::PrintErr(" done.\n"); | 663 OS::PrintErr(" done.\n"); |
| 664 } | 664 } |
| 665 | 665 |
| 666 const int64_t start = OS::GetCurrentTimeMicros(); | 666 const int64_t start = OS::GetCurrentTimeMicros(); |
| 667 | 667 |
| 668 // Make code pages writable. | 668 // Make code pages writable. |
| 669 WriteProtectCode(false); | 669 WriteProtectCode(false); |
| 670 | 670 |
| 671 // Save old value before GCMarker visits the weak persistent handles. | 671 // Save old value before GCMarker visits the weak persistent handles. |
| 672 SpaceUsage usage_before = usage_; | 672 SpaceUsage usage_before = GetCurrentUsage(); |
| 673 | 673 |
| 674 // Mark all reachable old-gen objects. | 674 // Mark all reachable old-gen objects. |
| 675 bool collect_code = FLAG_collect_code && ShouldCollectCode(); | 675 bool collect_code = FLAG_collect_code && ShouldCollectCode(); |
| 676 GCMarker marker(heap_); | 676 GCMarker marker(heap_); |
| 677 marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code); | 677 marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code); |
| 678 usage_.used_in_words = marker.marked_words(); | 678 usage_.used_in_words = marker.marked_words(); |
| 679 | 679 |
| 680 int64_t mid1 = OS::GetCurrentTimeMicros(); | 680 int64_t mid1 = OS::GetCurrentTimeMicros(); |
| 681 | 681 |
| 682 // Abandon the remainder of the bump allocation block. | 682 // Abandon the remainder of the bump allocation block. |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 763 isolate, pages_, pages_tail_, &freelist_[HeapPage::kData]); | 763 isolate, pages_, pages_tail_, &freelist_[HeapPage::kData]); |
| 764 } | 764 } |
| 765 } | 765 } |
| 766 | 766 |
| 767 // Make code pages read-only. | 767 // Make code pages read-only. |
| 768 WriteProtectCode(true); | 768 WriteProtectCode(true); |
| 769 | 769 |
| 770 int64_t end = OS::GetCurrentTimeMicros(); | 770 int64_t end = OS::GetCurrentTimeMicros(); |
| 771 | 771 |
| 772 // Record signals for growth control. Include size of external allocations. | 772 // Record signals for growth control. Include size of external allocations. |
| 773 page_space_controller_.EvaluateGarbageCollection(usage_before, usage_, | 773 page_space_controller_.EvaluateGarbageCollection(usage_before, |
| 774 GetCurrentUsage(), |
| 774 start, end); | 775 start, end); |
| 775 | 776 |
| 776 heap_->RecordTime(kMarkObjects, mid1 - start); | 777 heap_->RecordTime(kMarkObjects, mid1 - start); |
| 777 heap_->RecordTime(kResetFreeLists, mid2 - mid1); | 778 heap_->RecordTime(kResetFreeLists, mid2 - mid1); |
| 778 heap_->RecordTime(kSweepPages, mid3 - mid2); | 779 heap_->RecordTime(kSweepPages, mid3 - mid2); |
| 779 heap_->RecordTime(kSweepLargePages, end - mid3); | 780 heap_->RecordTime(kSweepLargePages, end - mid3); |
| 780 | 781 |
| 781 if (FLAG_print_free_list_after_gc) { | 782 if (FLAG_print_free_list_after_gc) { |
| 782 OS::Print("Data Freelist (after GC):\n"); | 783 OS::Print("Data Freelist (after GC):\n"); |
| 783 freelist_[HeapPage::kData].Print(); | 784 freelist_[HeapPage::kData].Print(); |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 999 return 0; | 1000 return 0; |
| 1000 } else { | 1001 } else { |
| 1001 ASSERT(total_time >= gc_time); | 1002 ASSERT(total_time >= gc_time); |
| 1002 int result= static_cast<int>((static_cast<double>(gc_time) / | 1003 int result= static_cast<int>((static_cast<double>(gc_time) / |
| 1003 static_cast<double>(total_time)) * 100); | 1004 static_cast<double>(total_time)) * 100); |
| 1004 return result; | 1005 return result; |
| 1005 } | 1006 } |
| 1006 } | 1007 } |
| 1007 | 1008 |
| 1008 } // namespace dart | 1009 } // namespace dart |
| OLD | NEW |