blob: e2b03eb01ed53c867db97e22c4ad280480c7a735 [file] [log] [blame]
// 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.
#include "src/heap/allocation-observer.h"
#include "src/heap/heap.h"
#include "src/heap/spaces.h"
namespace v8 {
namespace internal {
void AllocationCounter::AddAllocationObserver(AllocationObserver* observer) {
#if DEBUG
auto it = std::find_if(observers_.begin(), observers_.end(),
[observer](const AllocationObserverCounter& aoc) {
return aoc.observer_ == observer;
});
DCHECK_EQ(observers_.end(), it);
#endif
if (step_in_progress_) {
pending_added_.push_back(AllocationObserverCounter(observer, 0, 0));
return;
}
intptr_t step_size = observer->GetNextStepSize();
size_t observer_next_counter = current_counter_ + step_size;
observers_.push_back(AllocationObserverCounter(observer, current_counter_,
observer_next_counter));
if (observers_.size() == 1) {
DCHECK_EQ(current_counter_, next_counter_);
next_counter_ = observer_next_counter;
} else {
size_t missing_bytes = next_counter_ - current_counter_;
next_counter_ =
current_counter_ + Min(static_cast<intptr_t>(missing_bytes), step_size);
}
}
void AllocationCounter::RemoveAllocationObserver(AllocationObserver* observer) {
auto it = std::find_if(observers_.begin(), observers_.end(),
[observer](const AllocationObserverCounter& aoc) {
return aoc.observer_ == observer;
});
DCHECK_NE(observers_.end(), it);
if (step_in_progress_) {
DCHECK_EQ(pending_removed_.count(observer), 0);
pending_removed_.insert(observer);
return;
}
observers_.erase(it);
if (observers_.size() == 0) {
current_counter_ = next_counter_ = 0;
} else {
size_t step_size = 0;
for (AllocationObserverCounter& observer : observers_) {
size_t left_in_step = observer.next_counter_ - current_counter_;
DCHECK_GT(left_in_step, 0);
step_size = step_size ? Min(step_size, left_in_step) : left_in_step;
}
next_counter_ = current_counter_ + step_size;
}
}
void AllocationCounter::AdvanceAllocationObservers(size_t allocated) {
if (!IsActive()) {
return;
}
DCHECK(!step_in_progress_);
DCHECK_LT(allocated, next_counter_ - current_counter_);
current_counter_ += allocated;
}
void AllocationCounter::InvokeAllocationObservers(Address soon_object,
size_t object_size,
size_t aligned_object_size) {
if (!IsActive()) {
return;
}
DCHECK(!step_in_progress_);
DCHECK_GE(aligned_object_size, next_counter_ - current_counter_);
DCHECK(soon_object);
bool step_run = false;
step_in_progress_ = true;
size_t step_size = 0;
DCHECK(pending_added_.empty());
DCHECK(pending_removed_.empty());
for (AllocationObserverCounter& aoc : observers_) {
if (aoc.next_counter_ - current_counter_ <= aligned_object_size) {
{
DisallowHeapAllocation disallow_heap_allocation;
aoc.observer_->Step(
static_cast<int>(current_counter_ - aoc.prev_counter_), soon_object,
object_size);
}
size_t observer_step_size = aoc.observer_->GetNextStepSize();
aoc.prev_counter_ = current_counter_;
aoc.next_counter_ =
current_counter_ + aligned_object_size + observer_step_size;
step_run = true;
}
size_t left_in_step = aoc.next_counter_ - current_counter_;
step_size = step_size ? Min(step_size, left_in_step) : left_in_step;
}
CHECK(step_run);
// Now process newly added allocation observers.
for (AllocationObserverCounter& aoc : pending_added_) {
size_t observer_step_size = aoc.observer_->GetNextStepSize();
aoc.prev_counter_ = current_counter_;
aoc.next_counter_ =
current_counter_ + aligned_object_size + observer_step_size;
DCHECK_NE(step_size, 0);
step_size = Min(step_size, aligned_object_size + observer_step_size);
observers_.push_back(aoc);
}
pending_added_.clear();
if (!pending_removed_.empty()) {
observers_.erase(
std::remove_if(observers_.begin(), observers_.end(),
[this](const AllocationObserverCounter& aoc) {
return pending_removed_.count(aoc.observer_) != 0;
}));
pending_removed_.clear();
// Some observers were removed, recalculate step size.
step_size = 0;
for (AllocationObserverCounter& aoc : observers_) {
size_t left_in_step = aoc.next_counter_ - current_counter_;
step_size = step_size ? Min(step_size, left_in_step) : left_in_step;
}
if (observers_.empty()) {
next_counter_ = current_counter_ = 0;
step_in_progress_ = false;
return;
}
}
next_counter_ = current_counter_ + step_size;
step_in_progress_ = false;
}
PauseAllocationObserversScope::PauseAllocationObserversScope(Heap* heap)
: heap_(heap) {
DCHECK_EQ(heap->gc_state(), Heap::NOT_IN_GC);
for (SpaceIterator it(heap_); it.HasNext();) {
it.Next()->PauseAllocationObservers();
}
}
PauseAllocationObserversScope::~PauseAllocationObserversScope() {
for (SpaceIterator it(heap_); it.HasNext();) {
it.Next()->ResumeAllocationObservers();
}
}
} // namespace internal
} // namespace v8