OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_HEAP_SPACES_H_ | 5 #ifndef V8_HEAP_SPACES_H_ |
6 #define V8_HEAP_SPACES_H_ | 6 #define V8_HEAP_SPACES_H_ |
7 | 7 |
8 #include <list> | 8 #include <list> |
9 #include <memory> | 9 #include <memory> |
10 #include <unordered_set> | 10 #include <unordered_set> |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 // |top_|: Points to the top FreeSpace* in the free list category. | 217 // |top_|: Points to the top FreeSpace* in the free list category. |
218 FreeSpace* top_; | 218 FreeSpace* top_; |
219 | 219 |
220 FreeListCategory* prev_; | 220 FreeListCategory* prev_; |
221 FreeListCategory* next_; | 221 FreeListCategory* next_; |
222 | 222 |
223 friend class FreeList; | 223 friend class FreeList; |
224 friend class PagedSpace; | 224 friend class PagedSpace; |
225 }; | 225 }; |
226 | 226 |
227 // MarkingMode determines which bitmaps and counters should be used when | |
228 // accessing marking information on MemoryChunk. | |
229 enum class MarkingMode { FULL, YOUNG_GENERATION }; | |
230 | |
231 // MemoryChunk represents a memory region owned by a specific space. | 227 // MemoryChunk represents a memory region owned by a specific space. |
232 // It is divided into the header and the body. Chunk start is always | 228 // It is divided into the header and the body. Chunk start is always |
233 // 1MB aligned. Start of the body is aligned so it can accommodate | 229 // 1MB aligned. Start of the body is aligned so it can accommodate |
234 // any heap object. | 230 // any heap object. |
235 class MemoryChunk { | 231 class MemoryChunk { |
236 public: | 232 public: |
237 enum Flag { | 233 enum Flag { |
238 NO_FLAGS = 0u, | 234 NO_FLAGS = 0u, |
239 IS_EXECUTABLE = 1u << 0, | 235 IS_EXECUTABLE = 1u << 0, |
240 POINTERS_TO_HERE_ARE_INTERESTING = 1u << 1, | 236 POINTERS_TO_HERE_ARE_INTERESTING = 1u << 1, |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 static const int kObjectStartOffset = | 366 static const int kObjectStartOffset = |
371 kBodyOffset - 1 + | 367 kBodyOffset - 1 + |
372 (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment); | 368 (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment); |
373 | 369 |
374 // Page size in bytes. This must be a multiple of the OS page size. | 370 // Page size in bytes. This must be a multiple of the OS page size. |
375 static const int kPageSize = 1 << kPageSizeBits; | 371 static const int kPageSize = 1 << kPageSizeBits; |
376 static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1; | 372 static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1; |
377 | 373 |
378 static const int kAllocatableMemory = kPageSize - kObjectStartOffset; | 374 static const int kAllocatableMemory = kPageSize - kObjectStartOffset; |
379 | 375 |
380 template <MarkingMode mode = MarkingMode::FULL> | |
381 static inline void IncrementLiveBytes(HeapObject* object, int by); | |
382 | |
383 // Only works if the pointer is in the first kPageSize of the MemoryChunk. | 376 // Only works if the pointer is in the first kPageSize of the MemoryChunk. |
384 static MemoryChunk* FromAddress(Address a) { | 377 static MemoryChunk* FromAddress(Address a) { |
385 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask); | 378 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask); |
386 } | 379 } |
387 | 380 |
388 static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr); | 381 static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr); |
389 | 382 |
390 static inline void UpdateHighWaterMark(Address mark) { | 383 static inline void UpdateHighWaterMark(Address mark) { |
391 if (mark == nullptr) return; | 384 if (mark == nullptr) return; |
392 // Need to subtract one from the mark because when a chunk is full the | 385 // Need to subtract one from the mark because when a chunk is full the |
(...skipping 27 matching lines...) Expand all Loading... |
420 } | 413 } |
421 | 414 |
422 base::AtomicValue<ConcurrentSweepingState>& concurrent_sweeping_state() { | 415 base::AtomicValue<ConcurrentSweepingState>& concurrent_sweeping_state() { |
423 return concurrent_sweeping_; | 416 return concurrent_sweeping_; |
424 } | 417 } |
425 | 418 |
426 bool SweepingDone() { | 419 bool SweepingDone() { |
427 return concurrent_sweeping_state().Value() == kSweepingDone; | 420 return concurrent_sweeping_state().Value() == kSweepingDone; |
428 } | 421 } |
429 | 422 |
430 // Manage live byte count, i.e., count of bytes in black objects. | |
431 template <MarkingMode mode = MarkingMode::FULL> | |
432 inline void ResetLiveBytes(); | |
433 template <MarkingMode mode = MarkingMode::FULL> | |
434 inline void IncrementLiveBytes(int by); | |
435 | |
436 template <MarkingMode mode = MarkingMode::FULL> | |
437 int LiveBytes() { | |
438 switch (mode) { | |
439 case MarkingMode::FULL: | |
440 DCHECK_LE(static_cast<unsigned>(live_byte_count_), size_); | |
441 return static_cast<int>(live_byte_count_); | |
442 case MarkingMode::YOUNG_GENERATION: | |
443 DCHECK_LE(static_cast<unsigned>(young_generation_live_byte_count_), | |
444 size_); | |
445 return static_cast<int>(young_generation_live_byte_count_); | |
446 } | |
447 UNREACHABLE(); | |
448 return 0; | |
449 } | |
450 | |
451 void SetLiveBytes(int live_bytes) { | |
452 DCHECK_GE(live_bytes, 0); | |
453 DCHECK_LE(static_cast<size_t>(live_bytes), size_); | |
454 live_byte_count_ = live_bytes; | |
455 } | |
456 | |
457 size_t size() const { return size_; } | 423 size_t size() const { return size_; } |
458 void set_size(size_t size) { size_ = size; } | 424 void set_size(size_t size) { size_ = size; } |
459 | 425 |
460 inline Heap* heap() const { return heap_; } | 426 inline Heap* heap() const { return heap_; } |
461 | 427 |
462 inline SkipList* skip_list() { return skip_list_; } | 428 inline SkipList* skip_list() { return skip_list_; } |
463 | 429 |
464 inline void set_skip_list(SkipList* skip_list) { skip_list_ = skip_list; } | 430 inline void set_skip_list(SkipList* skip_list) { skip_list_ = skip_list; } |
465 | 431 |
466 inline SlotSet* old_to_new_slots() { return old_to_new_slots_.Value(); } | 432 inline SlotSet* old_to_new_slots() { return old_to_new_slots_.Value(); } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 DCHECK(IsFlagSet(HAS_PROGRESS_BAR)); | 472 DCHECK(IsFlagSet(HAS_PROGRESS_BAR)); |
507 progress_bar_ = progress_bar; | 473 progress_bar_ = progress_bar; |
508 } | 474 } |
509 | 475 |
510 void ResetProgressBar() { | 476 void ResetProgressBar() { |
511 if (IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) { | 477 if (IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) { |
512 set_progress_bar(0); | 478 set_progress_bar(0); |
513 } | 479 } |
514 } | 480 } |
515 | 481 |
516 template <MarkingMode mode = MarkingMode::FULL> | |
517 inline Bitmap* markbits() const { | |
518 return mode == MarkingMode::FULL | |
519 ? Bitmap::FromAddress(address() + kHeaderSize) | |
520 : young_generation_bitmap_; | |
521 } | |
522 | |
523 template <MarkingMode mode = MarkingMode::FULL> | |
524 inline intptr_t* live_bytes_address() { | |
525 return mode == MarkingMode::FULL ? &live_byte_count_ | |
526 : &young_generation_live_byte_count_; | |
527 } | |
528 | |
529 inline uint32_t AddressToMarkbitIndex(Address addr) const { | 482 inline uint32_t AddressToMarkbitIndex(Address addr) const { |
530 return static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2; | 483 return static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2; |
531 } | 484 } |
532 | 485 |
533 inline Address MarkbitIndexToAddress(uint32_t index) const { | 486 inline Address MarkbitIndexToAddress(uint32_t index) const { |
534 return this->address() + (index << kPointerSizeLog2); | 487 return this->address() + (index << kPointerSizeLog2); |
535 } | 488 } |
536 | 489 |
537 template <MarkingMode mode = MarkingMode::FULL> | |
538 void ClearLiveness(); | |
539 | |
540 void PrintMarkbits() { markbits()->Print(); } | |
541 | |
542 void SetFlag(Flag flag) { flags_ |= flag; } | 490 void SetFlag(Flag flag) { flags_ |= flag; } |
543 void ClearFlag(Flag flag) { flags_ &= ~Flags(flag); } | 491 void ClearFlag(Flag flag) { flags_ &= ~Flags(flag); } |
544 bool IsFlagSet(Flag flag) { return (flags_ & flag) != 0; } | 492 bool IsFlagSet(Flag flag) { return (flags_ & flag) != 0; } |
545 | 493 |
546 // Set or clear multiple flags at a time. The flags in the mask are set to | 494 // Set or clear multiple flags at a time. The flags in the mask are set to |
547 // the value in "flags", the rest retain the current value in |flags_|. | 495 // the value in "flags", the rest retain the current value in |flags_|. |
548 void SetFlags(uintptr_t flags, uintptr_t mask) { | 496 void SetFlags(uintptr_t flags, uintptr_t mask) { |
549 flags_ = (flags_ & ~Flags(mask)) | (Flags(flags) & Flags(mask)); | 497 flags_ = (flags_ & ~Flags(mask)) | (Flags(flags) & Flags(mask)); |
550 } | 498 } |
551 | 499 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 static MemoryChunk* Initialize(Heap* heap, Address base, size_t size, | 563 static MemoryChunk* Initialize(Heap* heap, Address base, size_t size, |
616 Address area_start, Address area_end, | 564 Address area_start, Address area_end, |
617 Executability executable, Space* owner, | 565 Executability executable, Space* owner, |
618 base::VirtualMemory* reservation); | 566 base::VirtualMemory* reservation); |
619 | 567 |
620 // Should be called when memory chunk is about to be freed. | 568 // Should be called when memory chunk is about to be freed. |
621 void ReleaseAllocatedMemory(); | 569 void ReleaseAllocatedMemory(); |
622 | 570 |
623 base::VirtualMemory* reserved_memory() { return &reservation_; } | 571 base::VirtualMemory* reserved_memory() { return &reservation_; } |
624 | 572 |
625 template <MarkingMode mode = MarkingMode::FULL> | |
626 inline void TraceLiveBytes(intptr_t old_value, intptr_t new_value); | |
627 | |
628 size_t size_; | 573 size_t size_; |
629 Flags flags_; | 574 Flags flags_; |
630 | 575 |
631 // Start and end of allocatable memory on this chunk. | 576 // Start and end of allocatable memory on this chunk. |
632 Address area_start_; | 577 Address area_start_; |
633 Address area_end_; | 578 Address area_end_; |
634 | 579 |
635 // If the chunk needs to remember its memory reservation, it is stored here. | 580 // If the chunk needs to remember its memory reservation, it is stored here. |
636 base::VirtualMemory reservation_; | 581 base::VirtualMemory reservation_; |
637 | 582 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 FreeListCategory categories_[kNumberOfCategories]; | 624 FreeListCategory categories_[kNumberOfCategories]; |
680 | 625 |
681 LocalArrayBufferTracker* local_tracker_; | 626 LocalArrayBufferTracker* local_tracker_; |
682 | 627 |
683 intptr_t young_generation_live_byte_count_; | 628 intptr_t young_generation_live_byte_count_; |
684 Bitmap* young_generation_bitmap_; | 629 Bitmap* young_generation_bitmap_; |
685 | 630 |
686 private: | 631 private: |
687 void InitializeReservedMemory() { reservation_.Reset(); } | 632 void InitializeReservedMemory() { reservation_.Reset(); } |
688 | 633 |
| 634 friend class MarkingState; |
689 friend class MemoryAllocator; | 635 friend class MemoryAllocator; |
690 friend class MemoryChunkValidator; | 636 friend class MemoryChunkValidator; |
691 }; | 637 }; |
692 | 638 |
693 DEFINE_OPERATORS_FOR_FLAGS(MemoryChunk::Flags) | 639 DEFINE_OPERATORS_FOR_FLAGS(MemoryChunk::Flags) |
694 | 640 |
695 static_assert(kMaxRegularHeapObjectSize <= MemoryChunk::kAllocatableMemory, | 641 static_assert(kMaxRegularHeapObjectSize <= MemoryChunk::kAllocatableMemory, |
696 "kMaxRegularHeapObjectSize <= MemoryChunk::kAllocatableMemory"); | 642 "kMaxRegularHeapObjectSize <= MemoryChunk::kAllocatableMemory"); |
697 | 643 |
| 644 class MarkingState { |
| 645 public: |
| 646 static MarkingState External(HeapObject* object) { |
| 647 return External(MemoryChunk::FromAddress(object->address())); |
| 648 } |
| 649 |
| 650 static MarkingState External(MemoryChunk* chunk) { |
| 651 return MarkingState(chunk->young_generation_bitmap_, |
| 652 &chunk->young_generation_live_byte_count_); |
| 653 } |
| 654 |
| 655 static MarkingState Internal(HeapObject* object) { |
| 656 return Internal(MemoryChunk::FromAddress(object->address())); |
| 657 } |
| 658 |
| 659 static MarkingState Internal(MemoryChunk* chunk) { |
| 660 return MarkingState( |
| 661 Bitmap::FromAddress(chunk->address() + MemoryChunk::kHeaderSize), |
| 662 &chunk->live_byte_count_); |
| 663 } |
| 664 |
| 665 MarkingState(Bitmap* bitmap, intptr_t* live_bytes) |
| 666 : bitmap_(bitmap), live_bytes_(live_bytes) {} |
| 667 |
| 668 void IncrementLiveBytes(intptr_t by) const { |
| 669 *live_bytes_ += static_cast<int>(by); |
| 670 } |
| 671 void SetLiveBytes(intptr_t value) const { |
| 672 *live_bytes_ = static_cast<int>(value); |
| 673 } |
| 674 |
| 675 void ClearLiveness() const { |
| 676 bitmap_->Clear(); |
| 677 *live_bytes_ = 0; |
| 678 } |
| 679 |
| 680 Bitmap* bitmap() const { return bitmap_; } |
| 681 intptr_t live_bytes() const { return *live_bytes_; } |
| 682 |
| 683 private: |
| 684 Bitmap* bitmap_; |
| 685 intptr_t* live_bytes_; |
| 686 }; |
| 687 |
698 // ----------------------------------------------------------------------------- | 688 // ----------------------------------------------------------------------------- |
699 // A page is a memory chunk of a size 1MB. Large object pages may be larger. | 689 // A page is a memory chunk of a size 1MB. Large object pages may be larger. |
700 // | 690 // |
701 // The only way to get a page pointer is by calling factory methods: | 691 // The only way to get a page pointer is by calling factory methods: |
702 // Page* p = Page::FromAddress(addr); or | 692 // Page* p = Page::FromAddress(addr); or |
703 // Page* p = Page::FromTopOrLimit(top); | 693 // Page* p = Page::FromTopOrLimit(top); |
704 class Page : public MemoryChunk { | 694 class Page : public MemoryChunk { |
705 public: | 695 public: |
706 static const intptr_t kCopyAllFlags = ~0; | 696 static const intptr_t kCopyAllFlags = ~0; |
707 | 697 |
(...skipping 2256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2964 PageIterator old_iterator_; | 2954 PageIterator old_iterator_; |
2965 PageIterator code_iterator_; | 2955 PageIterator code_iterator_; |
2966 PageIterator map_iterator_; | 2956 PageIterator map_iterator_; |
2967 LargePageIterator lo_iterator_; | 2957 LargePageIterator lo_iterator_; |
2968 }; | 2958 }; |
2969 | 2959 |
2970 } // namespace internal | 2960 } // namespace internal |
2971 } // namespace v8 | 2961 } // namespace v8 |
2972 | 2962 |
2973 #endif // V8_HEAP_SPACES_H_ | 2963 #endif // V8_HEAP_SPACES_H_ |
OLD | NEW |