blob: c376d67f539ca32e8d6567e1fa422e2479de6356 [file] [log] [blame]
/*
* Copyright 2017 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TEST_UTILITIES_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TEST_UTILITIES_H_
#include "base/callback.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/heap/blink_gc.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
namespace blink {
class HeapPointersOnStackScope final {
STACK_ALLOCATED();
public:
explicit HeapPointersOnStackScope(ThreadState* state) : state_(state) {
DCHECK(!state_->heap_pointers_on_stack_forced_);
state_->heap_pointers_on_stack_forced_ = true;
}
~HeapPointersOnStackScope() {
DCHECK(state_->heap_pointers_on_stack_forced_);
state_->heap_pointers_on_stack_forced_ = false;
}
private:
ThreadState* const state_;
};
class TestSupportingGC : public testing::Test {
public:
// Performs a precise garbage collection with eager sweeping.
static void PreciselyCollectGarbage(
BlinkGC::SweepingType sweeping_type = BlinkGC::kEagerSweeping);
// Performs a conservative garbage collection.
static void ConservativelyCollectGarbage(
BlinkGC::SweepingType sweeping_type = BlinkGC::kEagerSweeping);
~TestSupportingGC() override;
// Performs multiple rounds of garbage collections until no more memory can be
// freed. This is useful to avoid other garbage collections having to deal
// with stale memory.
void ClearOutOldGarbage();
// Completes sweeping if it is currently running.
void CompleteSweepingIfNeeded();
protected:
base::test::TaskEnvironment task_environment_;
};
template <typename T>
class ObjectWithCallbackBeforeInitializer
: public GarbageCollected<ObjectWithCallbackBeforeInitializer<T>> {
public:
ObjectWithCallbackBeforeInitializer(
base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb,
T* value)
: bool_(ExecuteCallbackReturnTrue(this, std::move(cb))), value_(value) {}
ObjectWithCallbackBeforeInitializer( // NOLINT
base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb)
: bool_(ExecuteCallbackReturnTrue(this, std::move(cb))) {}
virtual void Trace(Visitor* visitor) const { visitor->Trace(value_); }
T* value() const { return value_.Get(); }
private:
static bool ExecuteCallbackReturnTrue(
ObjectWithCallbackBeforeInitializer* thiz,
base::OnceCallback<void(ObjectWithCallbackBeforeInitializer<T>*)>&& cb) {
std::move(cb).Run(thiz);
return true;
}
bool bool_;
Member<T> value_;
};
template <typename T>
class MixinWithCallbackBeforeInitializer : public GarbageCollectedMixin {
public:
MixinWithCallbackBeforeInitializer(
base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb,
T* value)
: bool_(ExecuteCallbackReturnTrue(this, std::move(cb))), value_(value) {}
MixinWithCallbackBeforeInitializer( // NOLINT
base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb)
: bool_(ExecuteCallbackReturnTrue(this, std::move(cb))) {}
void Trace(Visitor* visitor) const override { visitor->Trace(value_); }
T* value() const { return value_.Get(); }
private:
static bool ExecuteCallbackReturnTrue(
MixinWithCallbackBeforeInitializer* thiz,
base::OnceCallback<void(MixinWithCallbackBeforeInitializer<T>*)>&& cb) {
std::move(cb).Run(thiz);
return true;
}
bool bool_;
Member<T> value_;
};
class BoolMixin {
protected:
bool bool_ = false;
};
template <typename T>
class ObjectWithMixinWithCallbackBeforeInitializer
: public GarbageCollected<ObjectWithMixinWithCallbackBeforeInitializer<T>>,
public BoolMixin,
public MixinWithCallbackBeforeInitializer<T> {
public:
using Mixin = MixinWithCallbackBeforeInitializer<T>;
ObjectWithMixinWithCallbackBeforeInitializer(
base::OnceCallback<void(Mixin*)>&& cb,
T* value)
: Mixin(std::move(cb), value) {}
ObjectWithMixinWithCallbackBeforeInitializer( // NOLINT
base::OnceCallback<void(Mixin*)>&& cb)
: Mixin(std::move(cb)) {}
void Trace(Visitor* visitor) const override { Mixin::Trace(visitor); }
};
// Simple linked object to be used in tests.
class LinkedObject : public GarbageCollected<LinkedObject> {
public:
LinkedObject() = default;
explicit LinkedObject(LinkedObject* next) : next_(next) {}
void set_next(LinkedObject* next) { next_ = next; }
LinkedObject* next() const { return next_; }
Member<LinkedObject>& next_ref() { return next_; }
virtual void Trace(Visitor* visitor) const { visitor->Trace(next_); }
private:
Member<LinkedObject> next_;
};
// Test driver for incremental marking. Assumes that no stack handling is
// required.
class IncrementalMarkingTestDriver {
public:
explicit IncrementalMarkingTestDriver(ThreadState* thread_state)
: thread_state_(thread_state) {}
~IncrementalMarkingTestDriver();
void Start();
bool SingleStep(BlinkGC::StackState stack_state =
BlinkGC::StackState::kNoHeapPointersOnStack);
void FinishSteps(BlinkGC::StackState stack_state =
BlinkGC::StackState::kNoHeapPointersOnStack);
void FinishGC(bool complete_sweep = true);
// Methods for forcing a concurrent marking step without any assistance from
// mutator thread (i.e. without incremental marking on the mutator thread).
bool SingleConcurrentStep(BlinkGC::StackState stack_state =
BlinkGC::StackState::kNoHeapPointersOnStack);
void FinishConcurrentSteps(BlinkGC::StackState stack_state =
BlinkGC::StackState::kNoHeapPointersOnStack);
size_t GetHeapCompactLastFixupCount() const;
private:
ThreadState* const thread_state_;
};
class IntegerObject : public GarbageCollected<IntegerObject> {
public:
static std::atomic_int destructor_calls;
explicit IntegerObject(int x) : x_(x) {}
virtual ~IntegerObject() {
destructor_calls.fetch_add(1, std::memory_order_relaxed);
}
virtual void Trace(Visitor* visitor) const {}
int Value() const { return x_; }
bool operator==(const IntegerObject& other) const {
return other.Value() == Value();
}
unsigned GetHash() { return IntHash<int>::GetHash(x_); }
private:
int x_;
};
struct IntegerObjectHash {
static unsigned GetHash(const IntegerObject& key) {
return WTF::HashInt(static_cast<uint32_t>(key.Value()));
}
static bool Equal(const IntegerObject& a, const IntegerObject& b) {
return a == b;
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TEST_UTILITIES_H_