| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_HEAP_ALLOCATION_OBSERVER_H_ |
| #define V8_HEAP_ALLOCATION_OBSERVER_H_ |
| |
| #include <cstdint> |
| #include <unordered_set> |
| #include <vector> |
| |
| #include "src/common/globals.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // Observer for allocations that is aware of LAB-based allocation. |
| class AllocationObserver { |
| public: |
| explicit AllocationObserver(intptr_t step_size) : step_size_(step_size) { |
| DCHECK_LE(kTaggedSize, step_size); |
| } |
| virtual ~AllocationObserver() = default; |
| AllocationObserver(const AllocationObserver&) = delete; |
| AllocationObserver& operator=(const AllocationObserver&) = delete; |
| |
| protected: |
| // Called when at least `step_size_` bytes have been allocated. `soon_object` |
| // points to the uninitialized memory that has just been allocated and is the |
| // result for a request of `size` bytes. |
| // |
| // Some caveats: |
| // 1. `soon_object` will be nullptr in cases where the allocation returns a |
| // filler object, which is e.g. needed at page boundaries. |
| // 2. `soon_object` may actually be the first object in an |
| // allocation-folding group. In such a case size is the size of the group |
| // rather than the first object. |
| // 3. `size` is the requested size at the time of allocation. Right-trimming |
| // may change the object size dynamically. |
| virtual void Step(int bytes_allocated, Address soon_object, size_t size) = 0; |
| |
| // Subclasses can override this method to make step size dynamic. |
| virtual intptr_t GetNextStepSize() { return step_size_; } |
| |
| private: |
| const intptr_t step_size_; |
| |
| friend class AllocationCounter; |
| }; |
| |
| // A global allocation counter observers can be added to. |
| class AllocationCounter final { |
| public: |
| AllocationCounter() = default; |
| |
| // Adds an observer. May be called from `AllocationObserver::Step()`. |
| V8_EXPORT_PRIVATE void AddAllocationObserver(AllocationObserver* observer); |
| |
| // Removes an observer. May be called from `AllocationObserver::Step()`. |
| V8_EXPORT_PRIVATE void RemoveAllocationObserver(AllocationObserver* observer); |
| |
| // Advances forward by `allocated` bytes. Does not invoke any observers. |
| V8_EXPORT_PRIVATE void AdvanceAllocationObservers(size_t allocated); |
| |
| // Invokes observers via `AllocationObserver::Step()` and computes new step |
| // sizes. Does not advance the current allocation counter. |
| V8_EXPORT_PRIVATE void InvokeAllocationObservers(Address soon_object, |
| size_t object_size, |
| size_t aligned_object_size); |
| |
| bool IsActive() const { return !IsPaused() && observers_.size() > 0; } |
| |
| bool IsStepInProgress() const { return step_in_progress_; } |
| |
| size_t NextBytes() const { |
| DCHECK(IsActive()); |
| return next_counter_ - current_counter_; |
| } |
| |
| void Pause() { |
| DCHECK(!step_in_progress_); |
| paused_++; |
| } |
| |
| void Resume() { |
| DCHECK_NE(0, paused_); |
| DCHECK(!step_in_progress_); |
| paused_--; |
| } |
| |
| private: |
| bool IsPaused() const { return paused_; } |
| |
| struct AllocationObserverCounter final { |
| AllocationObserverCounter(AllocationObserver* observer, size_t prev_counter, |
| size_t next_counter) |
| : observer_(observer), |
| prev_counter_(prev_counter), |
| next_counter_(next_counter) {} |
| |
| AllocationObserver* observer_; |
| size_t prev_counter_; |
| size_t next_counter_; |
| }; |
| |
| std::vector<AllocationObserverCounter> observers_; |
| std::vector<AllocationObserverCounter> pending_added_; |
| std::unordered_set<AllocationObserver*> pending_removed_; |
| |
| size_t current_counter_ = 0; |
| size_t next_counter_ = 0; |
| bool step_in_progress_ = false; |
| int paused_ = 0; |
| }; |
| |
| class V8_EXPORT_PRIVATE V8_NODISCARD PauseAllocationObserversScope { |
| public: |
| explicit PauseAllocationObserversScope(Heap* heap); |
| ~PauseAllocationObserversScope(); |
| PauseAllocationObserversScope(const PauseAllocationObserversScope&) = delete; |
| PauseAllocationObserversScope& operator=( |
| const PauseAllocationObserversScope&) = delete; |
| |
| private: |
| Heap* heap_; |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_HEAP_ALLOCATION_OBSERVER_H_ |