Commit 6a429cf7 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

Reland "cppgc: Integrate conservative stack scan into GC"

With this change we support allocation of objects and keeping them
alive via conservative stack scan.

This reverts commit 2b047a58.

Change-Id: Iac1913e7ef0556c28399509a160777a89e60150c
Bug: chromium:1056170
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2137402
Auto-Submit: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarAnton Bikineev <bikineev@chromium.org>
Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67016}
parent c4a2d8bb
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
#include <memory> #include <memory>
#include "src/heap/cppgc/heap-object-header.h" #include "src/base/platform/platform.h"
#include "src/heap/cppgc/heap-object-header-inl.h"
#include "src/heap/cppgc/stack.h"
namespace cppgc { namespace cppgc {
...@@ -16,12 +18,54 @@ std::unique_ptr<Heap> Heap::Create() { ...@@ -16,12 +18,54 @@ std::unique_ptr<Heap> Heap::Create() {
namespace internal { namespace internal {
void Heap::CollectGarbage() { namespace {
constexpr bool NeedsConservativeStackScan(Heap::GCConfig config) {
return config.stack_state == Heap::GCConfig::StackState::kNonEmpty;
}
} // namespace
// TODO(chromium:1056170): Replace with fast stack scanning once
// object are allocated actual arenas/spaces.
class StackMarker final : public StackVisitor {
public:
explicit StackMarker(const std::vector<HeapObjectHeader*>& objects)
: objects_(objects) {}
void VisitPointer(const void* address) final {
for (auto* header : objects_) {
if (address >= header->Payload() &&
address < (header + header->GetSize())) {
header->TryMarkAtomic();
}
}
}
private:
const std::vector<HeapObjectHeader*>& objects_;
};
Heap::Heap()
: stack_(std::make_unique<Stack>(v8::base::Stack::GetStackStart())) {}
void Heap::CollectGarbage(GCConfig config) {
current_config_ = config;
// TODO(chromium:1056170): Replace with proper mark-sweep algorithm.
// "Marking".
if (NeedsConservativeStackScan(current_config_)) {
StackMarker marker(objects_);
stack_->IteratePointers(&marker);
}
// "Sweeping and finalization".
for (HeapObjectHeader* header : objects_) { for (HeapObjectHeader* header : objects_) {
header->Finalize(); if (header->IsMarked()) {
free(header); header->Unmark();
} else {
header->Finalize();
free(header);
}
} }
objects_.clear();
} }
} // namespace internal } // namespace internal
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_HEAP_CPPGC_HEAP_H_ #ifndef V8_HEAP_CPPGC_HEAP_H_
#define V8_HEAP_CPPGC_HEAP_H_ #define V8_HEAP_CPPGC_HEAP_H_
#include <memory>
#include <vector> #include <vector>
#include "include/cppgc/gc-info.h" #include "include/cppgc/gc-info.h"
...@@ -14,18 +15,34 @@ ...@@ -14,18 +15,34 @@
namespace cppgc { namespace cppgc {
namespace internal { namespace internal {
class Stack;
class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap { class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap {
public: public:
struct GCConfig {
enum class StackState : uint8_t {
kEmpty,
kNonEmpty,
};
static GCConfig Default() { return {StackState::kNonEmpty}; }
StackState stack_state = StackState::kNonEmpty;
};
static Heap* From(cppgc::Heap* heap) { return static_cast<Heap*>(heap); } static Heap* From(cppgc::Heap* heap) { return static_cast<Heap*>(heap); }
Heap() = default; Heap();
~Heap() final = default; ~Heap() final = default;
inline void* Allocate(size_t size, GCInfoIndex index); inline void* Allocate(size_t size, GCInfoIndex index);
void CollectGarbage(); void CollectGarbage(GCConfig config = GCConfig::Default());
private: private:
GCConfig current_config_;
std::unique_ptr<Stack> stack_;
std::vector<HeapObjectHeader*> objects_; std::vector<HeapObjectHeader*> objects_;
}; };
......
...@@ -122,14 +122,16 @@ void IteratePointersImpl(const Stack* stack, StackVisitor* visitor, ...@@ -122,14 +122,16 @@ void IteratePointersImpl(const Stack* stack, StackVisitor* visitor,
} // namespace } // namespace
#ifdef CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
void Stack::IteratePointers(StackVisitor* visitor) const { void Stack::IteratePointers(StackVisitor* visitor) const {
#ifdef CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
PushAllRegistersAndIterateStack(this, visitor, &IteratePointersImpl); PushAllRegistersAndIterateStack(this, visitor, &IteratePointersImpl);
// No need to deal with callee-saved registers as they will be kept alive by // No need to deal with callee-saved registers as they will be kept alive by
// the regular conservative stack iteration. // the regular conservative stack iteration.
IterateSafeStackIfNecessary(visitor); IterateSafeStackIfNecessary(visitor);
#else // !CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
FATAL("Conservative stack scan not supported on current platform.");
#endif // !CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
} }
#endif // CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
} // namespace internal } // namespace internal
} // namespace cppgc } // namespace cppgc
...@@ -28,9 +28,7 @@ class V8_EXPORT_PRIVATE Stack final { ...@@ -28,9 +28,7 @@ class V8_EXPORT_PRIVATE Stack final {
// Word-aligned iteration of the stack. Slot values are passed on to // Word-aligned iteration of the stack. Slot values are passed on to
// |visitor|. // |visitor|.
#ifdef CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
void IteratePointers(StackVisitor* visitor) const; void IteratePointers(StackVisitor* visitor) const;
#endif // CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
// Returns the start of the stack. // Returns the start of the stack.
const void* stack_start() const { return stack_start_; } const void* stack_start() const { return stack_start_; }
......
...@@ -44,11 +44,11 @@ v8_source_set("cppgc_unittests_sources") { ...@@ -44,11 +44,11 @@ v8_source_set("cppgc_unittests_sources") {
testonly = true testonly = true
sources = [ sources = [
"heap/cppgc/allocation_unittest.cc",
"heap/cppgc/finalizer-trait_unittest.cc", "heap/cppgc/finalizer-trait_unittest.cc",
"heap/cppgc/garbage-collected_unittest.cc", "heap/cppgc/garbage-collected_unittest.cc",
"heap/cppgc/gc-info_unittest.cc", "heap/cppgc/gc-info_unittest.cc",
"heap/cppgc/heap-object-header_unittest.cc", "heap/cppgc/heap-object-header_unittest.cc",
"heap/cppgc/heap_unittest.cc",
"heap/cppgc/member_unittests.cc", "heap/cppgc/member_unittests.cc",
"heap/cppgc/source-location_unittest.cc", "heap/cppgc/source-location_unittest.cc",
"heap/cppgc/stack_unittest.cc", "heap/cppgc/stack_unittest.cc",
......
...@@ -60,6 +60,8 @@ TEST(GarbageCollectedTest, GarbageCollectedMixinTrait) { ...@@ -60,6 +60,8 @@ TEST(GarbageCollectedTest, GarbageCollectedMixinTrait) {
STATIC_ASSERT(IsGarbageCollectedMixinType<GCWithMergedMixins>::value); STATIC_ASSERT(IsGarbageCollectedMixinType<GCWithMergedMixins>::value);
} }
#ifdef CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCorrentAddress) { TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCorrentAddress) {
GCed* gced = MakeGarbageCollected<GCed>(GetHeap()); GCed* gced = MakeGarbageCollected<GCed>(GetHeap());
GCedWithMixin* gced_with_mixin = GCedWithMixin* gced_with_mixin =
...@@ -68,5 +70,8 @@ TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCorrentAddress) { ...@@ -68,5 +70,8 @@ TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCorrentAddress) {
static_cast<Mixin*>(gced_with_mixin)->GetObjectStart()); static_cast<Mixin*>(gced_with_mixin)->GetObjectStart());
EXPECT_NE(gced, static_cast<Mixin*>(gced_with_mixin)->GetObjectStart()); EXPECT_NE(gced, static_cast<Mixin*>(gced_with_mixin)->GetObjectStart());
} }
#endif // CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
} // namespace internal } // namespace internal
} // namespace cppgc } // namespace cppgc
...@@ -2,22 +2,30 @@ ...@@ -2,22 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "include/cppgc/allocation.h" #ifdef CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
#include <memory>
#include "src/heap/cppgc/heap.h" #include "src/heap/cppgc/heap.h"
#include "include/cppgc/allocation.h"
#include "test/unittests/heap/cppgc/tests.h" #include "test/unittests/heap/cppgc/tests.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace cppgc { namespace cppgc {
namespace internal {
TEST(GCBasicHeapTest, CreateAndDestroyHeap) {
std::unique_ptr<Heap> heap{Heap::Create()};
}
namespace { namespace {
class GCHeapTest : public testing::TestWithHeap {
public:
void ConservativeGC() {
internal::Heap::From(GetHeap())->CollectGarbage(
{Heap::GCConfig::StackState::kNonEmpty});
}
void PreciseGC() {
internal::Heap::From(GetHeap())->CollectGarbage(
{Heap::GCConfig::StackState::kEmpty});
}
};
class Foo : public GarbageCollected<Foo> { class Foo : public GarbageCollected<Foo> {
public: public:
static size_t destructor_callcount; static size_t destructor_callcount;
...@@ -28,15 +36,27 @@ class Foo : public GarbageCollected<Foo> { ...@@ -28,15 +36,27 @@ class Foo : public GarbageCollected<Foo> {
size_t Foo::destructor_callcount; size_t Foo::destructor_callcount;
class GCAllocationTest : public testing::TestWithHeap {};
} // namespace } // namespace
TEST_F(GCAllocationTest, MakeGarbageCollectedAndReclaim) { TEST_F(GCHeapTest, PreciseGCReclaimsObjectOnStack) {
MakeGarbageCollected<Foo>(GetHeap()); Foo* volatile do_not_acces = MakeGarbageCollected<Foo>(GetHeap());
USE(do_not_acces);
EXPECT_EQ(0u, Foo::destructor_callcount); EXPECT_EQ(0u, Foo::destructor_callcount);
internal::Heap::From(GetHeap())->CollectGarbage(); PreciseGC();
EXPECT_EQ(1u, Foo::destructor_callcount); EXPECT_EQ(1u, Foo::destructor_callcount);
} }
TEST_F(GCHeapTest, ConservaitveGCRetainsObjectOnStack) {
Foo* volatile do_not_acces = MakeGarbageCollected<Foo>(GetHeap());
USE(do_not_acces);
EXPECT_EQ(0u, Foo::destructor_callcount);
ConservativeGC();
EXPECT_EQ(0u, Foo::destructor_callcount);
PreciseGC();
EXPECT_EQ(1u, Foo::destructor_callcount);
}
} // namespace internal
} // namespace cppgc } // namespace cppgc
#endif // CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment