blob: 8df718babfc98fc4cd9f574c09aed12ee13fc9f4 [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.
#include "platform/heap/CallbackStack.h"
#include "platform/heap/GarbageCollected.h"
#include "platform/heap/Heap.h"
#include "platform/heap/IncrementalMarkingFlag.h"
#include "platform/heap/Member.h"
#include "platform/heap/ThreadState.h"
#include "platform/heap/TraceTraits.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING)
namespace blink {
namespace incremental_marking_test {
class Dummy : public GarbageCollected<Dummy> {
public:
static Dummy* Create() { return new Dummy(); }
void set_next(Dummy* next) { next_ = next; }
virtual void Trace(blink::Visitor* visitor) { visitor->Trace(next_); }
private:
Dummy() : next_(nullptr) {}
Member<Dummy> next_;
};
TEST(IncrementalMarkingTest, EnableDisableBarrier) {
Dummy* dummy = Dummy::Create();
BasePage* page = PageFromObject(dummy);
ThreadHeap& heap = ThreadState::Current()->Heap();
EXPECT_FALSE(page->IsIncrementalMarking());
heap.EnableIncrementalMarkingBarrier();
EXPECT_TRUE(page->IsIncrementalMarking());
heap.DisableIncrementalMarkingBarrier();
EXPECT_FALSE(page->IsIncrementalMarking());
}
TEST(IncrementalMarkingTest, WriteBarrierOnUnmarkedObject) {
Dummy* parent = Dummy::Create();
Dummy* child = Dummy::Create();
HeapObjectHeader* child_header = HeapObjectHeader::FromPayload(child);
ThreadHeap& heap = ThreadState::Current()->Heap();
CallbackStack* marking_stack = heap.MarkingStack();
EXPECT_TRUE(marking_stack->IsEmpty());
marking_stack->Commit();
heap.EnableIncrementalMarkingBarrier();
EXPECT_FALSE(child_header->IsMarked());
parent->set_next(child);
EXPECT_TRUE(child_header->IsMarked());
EXPECT_FALSE(marking_stack->IsEmpty());
CallbackStack::Item* item = marking_stack->Pop();
EXPECT_EQ(child, item->Object());
heap.DisableIncrementalMarkingBarrier();
marking_stack->Decommit();
}
TEST(IncrementalMarkingTest, NoWriteBarrierOnMarkedObject) {
Dummy* parent = Dummy::Create();
Dummy* child = Dummy::Create();
HeapObjectHeader* child_header = HeapObjectHeader::FromPayload(child);
child_header->Mark();
ThreadHeap& heap = ThreadState::Current()->Heap();
CallbackStack* marking_stack = heap.MarkingStack();
EXPECT_TRUE(marking_stack->IsEmpty());
heap.EnableIncrementalMarkingBarrier();
EXPECT_TRUE(child_header->IsMarked());
parent->set_next(child);
EXPECT_TRUE(marking_stack->IsEmpty());
heap.DisableIncrementalMarkingBarrier();
}
TEST(IncrementalMarkingTest, ManualWriteBarrierTriggersWhenMarkingIsOn) {
Dummy* dummy = Dummy::Create();
HeapObjectHeader* dummy_header = HeapObjectHeader::FromPayload(dummy);
ThreadHeap& heap = ThreadState::Current()->Heap();
CallbackStack* marking_stack = heap.MarkingStack();
EXPECT_TRUE(marking_stack->IsEmpty());
marking_stack->Commit();
heap.EnableIncrementalMarkingBarrier();
EXPECT_FALSE(dummy_header->IsMarked());
heap.WriteBarrier(dummy);
EXPECT_TRUE(dummy_header->IsMarked());
EXPECT_FALSE(marking_stack->IsEmpty());
CallbackStack::Item* item = marking_stack->Pop();
EXPECT_EQ(dummy, item->Object());
heap.DisableIncrementalMarkingBarrier();
marking_stack->Decommit();
}
TEST(IncrementalMarkingTest, ManualWriteBarrierBailoutWhenMarkingIsOff) {
Dummy* dummy = Dummy::Create();
HeapObjectHeader* dummy_header = HeapObjectHeader::FromPayload(dummy);
ThreadHeap& heap = ThreadState::Current()->Heap();
CallbackStack* marking_stack = heap.MarkingStack();
EXPECT_TRUE(marking_stack->IsEmpty());
EXPECT_FALSE(dummy_header->IsMarked());
heap.WriteBarrier(dummy);
EXPECT_FALSE(dummy_header->IsMarked());
EXPECT_TRUE(marking_stack->IsEmpty());
}
namespace {
class Mixin : public GarbageCollectedMixin {
public:
Mixin() : next_(nullptr) {}
virtual ~Mixin() {}
virtual void Trace(blink::Visitor* visitor) { visitor->Trace(next_); }
virtual void Bar() {}
protected:
Member<Dummy> next_;
};
class ClassWithVirtual {
protected:
virtual void Foo() {}
};
class Child : public GarbageCollected<Child>,
public ClassWithVirtual,
public Mixin {
USING_GARBAGE_COLLECTED_MIXIN(Child);
public:
static Child* Create() { return new Child(); }
virtual ~Child() {}
virtual void Trace(blink::Visitor* visitor) { Mixin::Trace(visitor); }
virtual void Foo() {}
virtual void Bar() {}
protected:
Child() : ClassWithVirtual(), Mixin() {}
};
class ParentWithMixinPointer : public GarbageCollected<ParentWithMixinPointer> {
public:
static ParentWithMixinPointer* Create() {
return new ParentWithMixinPointer();
}
void set_mixin(Mixin* mixin) { mixin_ = mixin; }
virtual void Trace(blink::Visitor* visitor) { visitor->Trace(mixin_); }
protected:
ParentWithMixinPointer() : mixin_(nullptr) {}
Member<Mixin> mixin_;
};
} // namespace
TEST(IncrementalMarkingTest, WriteBarrierOnUnmarkedMixinApplication) {
ParentWithMixinPointer* parent = ParentWithMixinPointer::Create();
Child* child = Child::Create();
HeapObjectHeader* child_header = HeapObjectHeader::FromPayload(child);
ThreadHeap& heap = ThreadState::Current()->Heap();
CallbackStack* marking_stack = heap.MarkingStack();
Mixin* mixin = static_cast<Mixin*>(child);
EXPECT_NE(static_cast<void*>(child), static_cast<void*>(mixin));
EXPECT_TRUE(marking_stack->IsEmpty());
marking_stack->Commit();
heap.EnableIncrementalMarkingBarrier();
EXPECT_FALSE(child_header->IsMarked());
parent->set_mixin(mixin);
EXPECT_TRUE(child_header->IsMarked());
EXPECT_FALSE(marking_stack->IsEmpty());
CallbackStack::Item* item = marking_stack->Pop();
EXPECT_EQ(child, item->Object());
heap.DisableIncrementalMarkingBarrier();
marking_stack->Decommit();
}
TEST(IncrementalMarkingTest, NoWriteBarrierOnMarkedMixinApplication) {
ParentWithMixinPointer* parent = ParentWithMixinPointer::Create();
Child* child = Child::Create();
HeapObjectHeader* child_header = HeapObjectHeader::FromPayload(child);
child_header->Mark();
ThreadHeap& heap = ThreadState::Current()->Heap();
CallbackStack* marking_stack = heap.MarkingStack();
Mixin* mixin = static_cast<Mixin*>(child);
EXPECT_NE(static_cast<void*>(child), static_cast<void*>(mixin));
EXPECT_TRUE(marking_stack->IsEmpty());
heap.EnableIncrementalMarkingBarrier();
EXPECT_TRUE(child_header->IsMarked());
parent->set_mixin(mixin);
EXPECT_TRUE(marking_stack->IsEmpty());
heap.DisableIncrementalMarkingBarrier();
}
} // namespace incremental_marking_test
} // namespace blink
#endif // BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING)