blob: 6ddbe8fb17544dc8fe8641518a3e0376533149ad [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/base/logging.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
namespace {
class UnusedObserver : public AllocationObserver {
public:
explicit UnusedObserver(size_t step_size) : AllocationObserver(step_size) {}
void Step(int bytes_allocated, Address soon_object, size_t size) override {
CHECK(false);
}
};
} // namespace
TEST(AllocationObserverTest, AddAndRemoveUnusedObservers) {
AllocationCounter counter;
CHECK(!counter.IsActive());
UnusedObserver observer100(100);
UnusedObserver observer200(200);
counter.AddAllocationObserver(&observer200);
CHECK_EQ(counter.NextBytes(), 200);
counter.AddAllocationObserver(&observer100);
CHECK_EQ(counter.NextBytes(), 100);
counter.AdvanceAllocationObservers(90);
CHECK_EQ(counter.NextBytes(), 10);
counter.RemoveAllocationObserver(&observer100);
CHECK_EQ(counter.NextBytes(), 110);
counter.RemoveAllocationObserver(&observer200);
CHECK(!counter.IsActive());
}
namespace {
class VerifyStepObserver : public AllocationObserver {
public:
explicit VerifyStepObserver(size_t step_size)
: AllocationObserver(step_size) {}
void Step(int bytes_allocated, Address soon_object, size_t size) override {
CHECK(!do_not_invoke_);
invocations_++;
CHECK_EQ(expected_bytes_allocated_, bytes_allocated);
CHECK_EQ(expected_size_, size);
}
void ExpectNoInvocation() { do_not_invoke_ = true; }
void Expect(int expected_bytes_allocated, size_t expected_size) {
do_not_invoke_ = false;
expected_bytes_allocated_ = expected_bytes_allocated;
expected_size_ = expected_size;
}
int Invocations() { return invocations_; }
private:
bool do_not_invoke_ = false;
int invocations_ = 0;
int expected_bytes_allocated_ = 0;
size_t expected_size_ = 0;
};
} // namespace
TEST(AllocationObserverTest, Step) {
AllocationCounter counter;
CHECK(!counter.IsActive());
const Address kSomeObjectAddress = 8;
VerifyStepObserver observer100(100);
VerifyStepObserver observer200(200);
counter.AddAllocationObserver(&observer100);
counter.AddAllocationObserver(&observer200);
observer100.Expect(90, 8);
observer200.ExpectNoInvocation();
counter.AdvanceAllocationObservers(90);
counter.InvokeAllocationObservers(kSomeObjectAddress, 8, 10);
CHECK_EQ(observer100.Invocations(), 1);
CHECK_EQ(observer200.Invocations(), 0);
CHECK_EQ(counter.NextBytes(),
10 /* aligned_object_size */ + 100 /* smallest step size*/);
observer100.Expect(90, 16);
observer200.Expect(180, 16);
counter.AdvanceAllocationObservers(90);
counter.InvokeAllocationObservers(kSomeObjectAddress, 16, 20);
CHECK_EQ(observer100.Invocations(), 2);
CHECK_EQ(observer200.Invocations(), 1);
CHECK_EQ(counter.NextBytes(),
20 /* aligned_object_size */ + 100 /* smallest step size*/);
}
namespace {
class RecursiveAddObserver : public AllocationObserver {
public:
explicit RecursiveAddObserver(size_t step_size, AllocationCounter* counter,
AllocationObserver* observer)
: AllocationObserver(step_size), counter_(counter), observer_(observer) {}
void Step(int bytes_allocated, Address soon_object, size_t size) override {
counter_->AddAllocationObserver(observer_);
}
private:
AllocationCounter* counter_;
AllocationObserver* observer_;
};
} // namespace
TEST(AllocationObserverTest, RecursiveAdd) {
AllocationCounter counter;
const Address kSomeObjectAddress = 8;
UnusedObserver observer50(50);
RecursiveAddObserver observer100(100, &counter, &observer50);
counter.AddAllocationObserver(&observer100);
CHECK_EQ(counter.NextBytes(), 100);
counter.AdvanceAllocationObservers(90);
counter.InvokeAllocationObservers(kSomeObjectAddress, 10, 10);
CHECK_EQ(counter.NextBytes(),
10 /* aligned_object_size */ + 50 /* smallest step size */);
}
namespace {
class RecursiveRemoveObserver : public AllocationObserver {
public:
explicit RecursiveRemoveObserver(size_t step_size, AllocationCounter* counter,
AllocationObserver* observer)
: AllocationObserver(step_size), counter_(counter), observer_(observer) {}
void Step(int bytes_allocated, Address soon_object, size_t size) override {
counter_->RemoveAllocationObserver(observer_);
}
private:
AllocationCounter* counter_;
AllocationObserver* observer_;
};
} // namespace
TEST(AllocationObserverTest, RecursiveRemove) {
AllocationCounter counter;
const Address kSomeObjectAddress = 8;
UnusedObserver observer75(75);
RecursiveRemoveObserver observer50(50, &counter, &observer75);
counter.AddAllocationObserver(&observer50);
counter.AddAllocationObserver(&observer75);
CHECK_EQ(counter.NextBytes(), 50);
counter.AdvanceAllocationObservers(40);
counter.InvokeAllocationObservers(kSomeObjectAddress, 10, 10);
CHECK_EQ(counter.NextBytes(),
10 /* aligned_object_size */ + 50 /* smallest step size */);
}
} // namespace internal
} // namespace v8