• 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 #include "src/heap/allocation-observer.h"
6 
7 #include "src/heap/heap.h"
8 #include "src/heap/spaces.h"
9 
10 namespace v8 {
11 namespace internal {
12 
AddAllocationObserver(AllocationObserver * observer)13 void AllocationCounter::AddAllocationObserver(AllocationObserver* observer) {
14 #if DEBUG
15   auto it = std::find_if(observers_.begin(), observers_.end(),
16                          [observer](const AllocationObserverCounter& aoc) {
17                            return aoc.observer_ == observer;
18                          });
19   DCHECK_EQ(observers_.end(), it);
20 #endif
21 
22   if (step_in_progress_) {
23     pending_added_.push_back(AllocationObserverCounter(observer, 0, 0));
24     return;
25   }
26 
27   intptr_t step_size = observer->GetNextStepSize();
28   size_t observer_next_counter = current_counter_ + step_size;
29 
30   observers_.push_back(AllocationObserverCounter(observer, current_counter_,
31                                                  observer_next_counter));
32 
33   if (observers_.size() == 1) {
34     DCHECK_EQ(current_counter_, next_counter_);
35     next_counter_ = observer_next_counter;
36   } else {
37     size_t missing_bytes = next_counter_ - current_counter_;
38     next_counter_ = current_counter_ +
39                     std::min(static_cast<intptr_t>(missing_bytes), step_size);
40   }
41 }
42 
RemoveAllocationObserver(AllocationObserver * observer)43 void AllocationCounter::RemoveAllocationObserver(AllocationObserver* observer) {
44   auto it = std::find_if(observers_.begin(), observers_.end(),
45                          [observer](const AllocationObserverCounter& aoc) {
46                            return aoc.observer_ == observer;
47                          });
48   DCHECK_NE(observers_.end(), it);
49 
50   if (step_in_progress_) {
51     DCHECK_EQ(pending_removed_.count(observer), 0);
52     pending_removed_.insert(observer);
53     return;
54   }
55 
56   observers_.erase(it);
57 
58   if (observers_.size() == 0) {
59     current_counter_ = next_counter_ = 0;
60   } else {
61     size_t step_size = 0;
62 
63     for (AllocationObserverCounter& observer_counter : observers_) {
64       size_t left_in_step = observer_counter.next_counter_ - current_counter_;
65       DCHECK_GT(left_in_step, 0);
66       step_size = step_size ? std::min(step_size, left_in_step) : left_in_step;
67     }
68 
69     next_counter_ = current_counter_ + step_size;
70   }
71 }
72 
AdvanceAllocationObservers(size_t allocated)73 void AllocationCounter::AdvanceAllocationObservers(size_t allocated) {
74   if (!IsActive()) {
75     return;
76   }
77 
78   DCHECK(!step_in_progress_);
79   DCHECK_LT(allocated, next_counter_ - current_counter_);
80   current_counter_ += allocated;
81 }
82 
InvokeAllocationObservers(Address soon_object,size_t object_size,size_t aligned_object_size)83 void AllocationCounter::InvokeAllocationObservers(Address soon_object,
84                                                   size_t object_size,
85                                                   size_t aligned_object_size) {
86   if (!IsActive()) {
87     return;
88   }
89 
90   DCHECK(!step_in_progress_);
91   DCHECK_GE(aligned_object_size, next_counter_ - current_counter_);
92   DCHECK(soon_object);
93   bool step_run = false;
94   step_in_progress_ = true;
95   size_t step_size = 0;
96 
97   DCHECK(pending_added_.empty());
98   DCHECK(pending_removed_.empty());
99 
100   for (AllocationObserverCounter& aoc : observers_) {
101     if (aoc.next_counter_ - current_counter_ <= aligned_object_size) {
102       {
103         DisallowGarbageCollection no_gc;
104         aoc.observer_->Step(
105             static_cast<int>(current_counter_ - aoc.prev_counter_), soon_object,
106             object_size);
107       }
108       size_t observer_step_size = aoc.observer_->GetNextStepSize();
109 
110       aoc.prev_counter_ = current_counter_;
111       aoc.next_counter_ =
112           current_counter_ + aligned_object_size + observer_step_size;
113       step_run = true;
114     }
115 
116     size_t left_in_step = aoc.next_counter_ - current_counter_;
117     step_size = step_size ? std::min(step_size, left_in_step) : left_in_step;
118   }
119 
120   CHECK(step_run);
121 
122   // Now process newly added allocation observers.
123   for (AllocationObserverCounter& aoc : pending_added_) {
124     size_t observer_step_size = aoc.observer_->GetNextStepSize();
125     aoc.prev_counter_ = current_counter_;
126     aoc.next_counter_ =
127         current_counter_ + aligned_object_size + observer_step_size;
128 
129     DCHECK_NE(step_size, 0);
130     step_size = std::min(step_size, aligned_object_size + observer_step_size);
131 
132     observers_.push_back(aoc);
133   }
134 
135   pending_added_.clear();
136 
137   if (!pending_removed_.empty()) {
138     observers_.erase(
139         std::remove_if(observers_.begin(), observers_.end(),
140                        [this](const AllocationObserverCounter& aoc) {
141                          return pending_removed_.count(aoc.observer_) != 0;
142                        }));
143     pending_removed_.clear();
144 
145     // Some observers were removed, recalculate step size.
146     step_size = 0;
147     for (AllocationObserverCounter& aoc : observers_) {
148       size_t left_in_step = aoc.next_counter_ - current_counter_;
149       step_size = step_size ? std::min(step_size, left_in_step) : left_in_step;
150     }
151 
152     if (observers_.empty()) {
153       next_counter_ = current_counter_ = 0;
154       step_in_progress_ = false;
155       return;
156     }
157   }
158 
159   next_counter_ = current_counter_ + step_size;
160   step_in_progress_ = false;
161 }
162 
PauseAllocationObserversScope(Heap * heap)163 PauseAllocationObserversScope::PauseAllocationObserversScope(Heap* heap)
164     : heap_(heap) {
165   DCHECK_EQ(heap->gc_state(), Heap::NOT_IN_GC);
166 
167   for (SpaceIterator it(heap_); it.HasNext();) {
168     it.Next()->PauseAllocationObservers();
169   }
170 }
171 
~PauseAllocationObserversScope()172 PauseAllocationObserversScope::~PauseAllocationObserversScope() {
173   for (SpaceIterator it(heap_); it.HasNext();) {
174     it.Next()->ResumeAllocationObservers();
175   }
176 }
177 
178 }  // namespace internal
179 }  // namespace v8
180