1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_HEAP_ALLOCATION_OBSERVER_H_ 6 #define V8_HEAP_ALLOCATION_OBSERVER_H_ 7 8 #include <cstdint> 9 #include <unordered_set> 10 #include <vector> 11 12 #include "src/common/globals.h" 13 14 namespace v8 { 15 namespace internal { 16 17 // Observer for allocations that is aware of LAB-based allocation. 18 class AllocationObserver { 19 public: AllocationObserver(intptr_t step_size)20 explicit AllocationObserver(intptr_t step_size) : step_size_(step_size) { 21 DCHECK_LE(kTaggedSize, step_size); 22 } 23 virtual ~AllocationObserver() = default; 24 AllocationObserver(const AllocationObserver&) = delete; 25 AllocationObserver& operator=(const AllocationObserver&) = delete; 26 27 protected: 28 // Called when at least `step_size_` bytes have been allocated. `soon_object` 29 // points to the uninitialized memory that has just been allocated and is the 30 // result for a request of `size` bytes. 31 // 32 // Some caveats: 33 // 1. `soon_object` will be nullptr in cases where the allocation returns a 34 // filler object, which is e.g. needed at page boundaries. 35 // 2. `soon_object` may actually be the first object in an 36 // allocation-folding group. In such a case size is the size of the group 37 // rather than the first object. 38 // 3. `size` is the requested size at the time of allocation. Right-trimming 39 // may change the object size dynamically. 40 virtual void Step(int bytes_allocated, Address soon_object, size_t size) = 0; 41 42 // Subclasses can override this method to make step size dynamic. GetNextStepSize()43 virtual intptr_t GetNextStepSize() { return step_size_; } 44 45 private: 46 const intptr_t step_size_; 47 48 friend class AllocationCounter; 49 }; 50 51 // A global allocation counter observers can be added to. 52 class AllocationCounter final { 53 public: 54 AllocationCounter() = default; 55 56 // Adds an observer. May be called from `AllocationObserver::Step()`. 57 V8_EXPORT_PRIVATE void AddAllocationObserver(AllocationObserver* observer); 58 59 // Removes an observer. May be called from `AllocationObserver::Step()`. 60 V8_EXPORT_PRIVATE void RemoveAllocationObserver(AllocationObserver* observer); 61 62 // Advances forward by `allocated` bytes. Does not invoke any observers. 63 V8_EXPORT_PRIVATE void AdvanceAllocationObservers(size_t allocated); 64 65 // Invokes observers via `AllocationObserver::Step()` and computes new step 66 // sizes. Does not advance the current allocation counter. 67 V8_EXPORT_PRIVATE void InvokeAllocationObservers(Address soon_object, 68 size_t object_size, 69 size_t aligned_object_size); 70 IsActive()71 bool IsActive() const { return !IsPaused() && observers_.size() > 0; } 72 IsStepInProgress()73 bool IsStepInProgress() const { return step_in_progress_; } 74 NextBytes()75 size_t NextBytes() const { 76 DCHECK(IsActive()); 77 return next_counter_ - current_counter_; 78 } 79 Pause()80 void Pause() { 81 DCHECK(!step_in_progress_); 82 paused_++; 83 } 84 Resume()85 void Resume() { 86 DCHECK_NE(0, paused_); 87 DCHECK(!step_in_progress_); 88 paused_--; 89 } 90 91 private: IsPaused()92 bool IsPaused() const { return paused_; } 93 94 struct AllocationObserverCounter final { AllocationObserverCounterfinal95 AllocationObserverCounter(AllocationObserver* observer, size_t prev_counter, 96 size_t next_counter) 97 : observer_(observer), 98 prev_counter_(prev_counter), 99 next_counter_(next_counter) {} 100 101 AllocationObserver* observer_; 102 size_t prev_counter_; 103 size_t next_counter_; 104 }; 105 106 std::vector<AllocationObserverCounter> observers_; 107 std::vector<AllocationObserverCounter> pending_added_; 108 std::unordered_set<AllocationObserver*> pending_removed_; 109 110 size_t current_counter_ = 0; 111 size_t next_counter_ = 0; 112 bool step_in_progress_ = false; 113 int paused_ = 0; 114 }; 115 116 class V8_EXPORT_PRIVATE V8_NODISCARD PauseAllocationObserversScope { 117 public: 118 explicit PauseAllocationObserversScope(Heap* heap); 119 ~PauseAllocationObserversScope(); 120 PauseAllocationObserversScope(const PauseAllocationObserversScope&) = delete; 121 PauseAllocationObserversScope& operator=( 122 const PauseAllocationObserversScope&) = delete; 123 124 private: 125 Heap* heap_; 126 }; 127 128 } // namespace internal 129 } // namespace v8 130 131 #endif // V8_HEAP_ALLOCATION_OBSERVER_H_ 132