• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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