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 class AllocationObserver;
18 
19 class AllocationCounter {
20  public:
AllocationCounter()21   AllocationCounter()
22       : paused_(false),
23         current_counter_(0),
24         next_counter_(0),
25         step_in_progress_(false) {}
26   V8_EXPORT_PRIVATE void AddAllocationObserver(AllocationObserver* observer);
27   V8_EXPORT_PRIVATE void RemoveAllocationObserver(AllocationObserver* observer);
28 
IsActive()29   bool IsActive() { return !IsPaused() && observers_.size() > 0; }
30 
Pause()31   void Pause() {
32     DCHECK(!paused_);
33     DCHECK(!step_in_progress_);
34     paused_ = true;
35   }
36 
Resume()37   void Resume() {
38     DCHECK(paused_);
39     DCHECK(!step_in_progress_);
40     paused_ = false;
41   }
42 
43   V8_EXPORT_PRIVATE void AdvanceAllocationObservers(size_t allocated);
44   V8_EXPORT_PRIVATE void InvokeAllocationObservers(Address soon_object,
45                                                    size_t object_size,
46                                                    size_t aligned_object_size);
47 
NextBytes()48   size_t NextBytes() {
49     DCHECK(IsActive());
50     return next_counter_ - current_counter_;
51   }
52 
IsStepInProgress()53   bool IsStepInProgress() { return step_in_progress_; }
54 
55  private:
IsPaused()56   bool IsPaused() { return paused_; }
57 
58   struct AllocationObserverCounter {
AllocationObserverCounterAllocationObserverCounter59     AllocationObserverCounter(AllocationObserver* observer, size_t prev_counter,
60                               size_t next_counter)
61         : observer_(observer),
62           prev_counter_(prev_counter),
63           next_counter_(next_counter) {}
64 
65     AllocationObserver* observer_;
66     size_t prev_counter_;
67     size_t next_counter_;
68   };
69 
70   std::vector<AllocationObserverCounter> observers_;
71   std::vector<AllocationObserverCounter> pending_added_;
72   std::unordered_set<AllocationObserver*> pending_removed_;
73 
74   bool paused_;
75 
76   size_t current_counter_;
77   size_t next_counter_;
78 
79   bool step_in_progress_;
80 };
81 
82 // -----------------------------------------------------------------------------
83 // Allows observation of allocations.
84 class AllocationObserver {
85  public:
AllocationObserver(intptr_t step_size)86   explicit AllocationObserver(intptr_t step_size) : step_size_(step_size) {
87     DCHECK_LE(kTaggedSize, step_size);
88   }
89   virtual ~AllocationObserver() = default;
90 
91  protected:
92   // Pure virtual method provided by the subclasses that gets called when at
93   // least step_size bytes have been allocated. soon_object is the address just
94   // allocated (but not yet initialized.) size is the size of the object as
95   // requested (i.e. w/o the alignment fillers). Some complexities to be aware
96   // of:
97   // 1) soon_object will be nullptr in cases where we end up observing an
98   //    allocation that happens to be a filler space (e.g. page boundaries.)
99   // 2) size is the requested size at the time of allocation. Right-trimming
100   //    may change the object size dynamically.
101   // 3) soon_object may actually be the first object in an allocation-folding
102   //    group. In such a case size is the size of the group rather than the
103   //    first object.
104   virtual void Step(int bytes_allocated, Address soon_object, size_t size) = 0;
105 
106   // Subclasses can override this method to make step size dynamic.
GetNextStepSize()107   virtual intptr_t GetNextStepSize() { return step_size_; }
108 
109  private:
110   intptr_t step_size_;
111 
112   friend class AllocationCounter;
113   DISALLOW_COPY_AND_ASSIGN(AllocationObserver);
114 };
115 
116 class V8_EXPORT_PRIVATE PauseAllocationObserversScope {
117  public:
118   explicit PauseAllocationObserversScope(Heap* heap);
119   ~PauseAllocationObserversScope();
120 
121  private:
122   Heap* heap_;
123   DISALLOW_COPY_AND_ASSIGN(PauseAllocationObserversScope);
124 };
125 
126 }  // namespace internal
127 }  // namespace v8
128 
129 #endif  // V8_HEAP_ALLOCATION_OBSERVER_H_
130