// 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 #include #include #include "src/common/globals.h" namespace v8 { namespace internal { class AllocationObserver; class AllocationCounter { public: AllocationCounter() : paused_(false), current_counter_(0), next_counter_(0), step_in_progress_(false) {} V8_EXPORT_PRIVATE void AddAllocationObserver(AllocationObserver* observer); V8_EXPORT_PRIVATE void RemoveAllocationObserver(AllocationObserver* observer); bool IsActive() { return !IsPaused() && observers_.size() > 0; } void Pause() { DCHECK(!paused_); DCHECK(!step_in_progress_); paused_ = true; } void Resume() { DCHECK(paused_); DCHECK(!step_in_progress_); paused_ = false; } V8_EXPORT_PRIVATE void AdvanceAllocationObservers(size_t allocated); V8_EXPORT_PRIVATE void InvokeAllocationObservers(Address soon_object, size_t object_size, size_t aligned_object_size); size_t NextBytes() { DCHECK(IsActive()); return next_counter_ - current_counter_; } bool IsStepInProgress() { return step_in_progress_; } private: bool IsPaused() { return paused_; } struct AllocationObserverCounter { 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 observers_; std::vector pending_added_; std::unordered_set pending_removed_; bool paused_; size_t current_counter_; size_t next_counter_; bool step_in_progress_; }; // ----------------------------------------------------------------------------- // Allows observation of allocations. class AllocationObserver { public: explicit AllocationObserver(intptr_t step_size) : step_size_(step_size) { DCHECK_LE(kTaggedSize, step_size); } virtual ~AllocationObserver() = default; protected: // Pure virtual method provided by the subclasses that gets called when at // least step_size bytes have been allocated. soon_object is the address just // allocated (but not yet initialized.) size is the size of the object as // requested (i.e. w/o the alignment fillers). Some complexities to be aware // of: // 1) soon_object will be nullptr in cases where we end up observing an // allocation that happens to be a filler space (e.g. page boundaries.) // 2) size is the requested size at the time of allocation. Right-trimming // may change the object size dynamically. // 3) 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. 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: intptr_t step_size_; friend class AllocationCounter; DISALLOW_COPY_AND_ASSIGN(AllocationObserver); }; class V8_EXPORT_PRIVATE PauseAllocationObserversScope { public: explicit PauseAllocationObserversScope(Heap* heap); ~PauseAllocationObserversScope(); private: Heap* heap_; DISALLOW_COPY_AND_ASSIGN(PauseAllocationObserversScope); }; } // namespace internal } // namespace v8 #endif // V8_HEAP_ALLOCATION_OBSERVER_H_