Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: runtime/vm/pages.cc

Issue 670973002: Avoid races in capacity accounting. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/pages.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/pages.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698