cppgc: Add testing API structure
Adds testing API that can only be used after enabling it on a heap. The call that enables testing is only provided via v8_for_testing or cppgc_for_testing build targets which protects against misusing from production code. Change-Id: I24a8f5543a2bb479481384e2c555d231383e5d12 Bug: chromium:1056170 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2667513 Reviewed-by: Hannes Payer <hpayer@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Omer Katz <omerkatz@chromium.org> Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#72503}
This commit is contained in:
parent
8798b3ef4e
commit
e963b636a5
36
BUILD.gn
36
BUILD.gn
@ -4419,6 +4419,7 @@ v8_component("v8_libbase") {
|
||||
|
||||
if (is_tsan && !build_with_chromium) {
|
||||
data += [ "tools/sanitizers/tsan_suppressions.txt" ]
|
||||
|
||||
# llvm-symbolizer uses libstdc++ from the clang package.
|
||||
data += [ "//third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6" ]
|
||||
}
|
||||
@ -4730,6 +4731,22 @@ v8_source_set("cppgc_base") {
|
||||
]
|
||||
}
|
||||
|
||||
v8_source_set("cppgc_base_for_testing") {
|
||||
visibility = [ ":*" ]
|
||||
|
||||
sources = [
|
||||
"include/cppgc/testing.h",
|
||||
"src/heap/cppgc/testing.cc",
|
||||
]
|
||||
|
||||
configs = [
|
||||
":internal_config",
|
||||
":cppgc_base_config",
|
||||
]
|
||||
|
||||
public_deps = [ ":cppgc_base" ]
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Produce a single static library for embedders
|
||||
#
|
||||
@ -5066,6 +5083,7 @@ if (is_component_build) {
|
||||
sources = [ "src/utils/v8dll-main.cc" ]
|
||||
|
||||
public_deps = [
|
||||
":cppgc_base_for_testing",
|
||||
":torque_base",
|
||||
":torque_ls_base",
|
||||
":v8_base",
|
||||
@ -5082,12 +5100,11 @@ if (is_component_build) {
|
||||
v8_component("cppgc") {
|
||||
public_deps = [ ":cppgc_base" ]
|
||||
|
||||
configs = [ ":internal_config" ]
|
||||
|
||||
if (!cppgc_is_standalone) {
|
||||
deps = [ ":v8" ]
|
||||
}
|
||||
|
||||
configs = []
|
||||
public_configs = [ ":external_config" ]
|
||||
}
|
||||
|
||||
@ -5095,9 +5112,12 @@ if (is_component_build) {
|
||||
v8_component("cppgc_for_testing") {
|
||||
testonly = true
|
||||
|
||||
public_deps = [ ":cppgc_base" ]
|
||||
public_deps = [
|
||||
":cppgc_base",
|
||||
":cppgc_base_for_testing",
|
||||
]
|
||||
|
||||
configs = [ ":internal_config" ]
|
||||
configs = []
|
||||
public_configs = [ ":external_config" ]
|
||||
}
|
||||
}
|
||||
@ -5107,7 +5127,7 @@ if (is_component_build) {
|
||||
|
||||
public_deps = [ ":v8_cppgc_shared" ]
|
||||
|
||||
configs = [ ":internal_config" ]
|
||||
configs = []
|
||||
public_configs = [ ":external_config" ]
|
||||
}
|
||||
} else {
|
||||
@ -5124,6 +5144,7 @@ if (is_component_build) {
|
||||
testonly = true
|
||||
|
||||
public_deps = [
|
||||
":cppgc_base_for_testing",
|
||||
":torque_base",
|
||||
":torque_ls_base",
|
||||
":v8_base",
|
||||
@ -5148,7 +5169,10 @@ if (is_component_build) {
|
||||
group("cppgc_for_testing") {
|
||||
testonly = true
|
||||
|
||||
public_deps = [ ":cppgc_base" ]
|
||||
public_deps = [
|
||||
":cppgc_base",
|
||||
":cppgc_base_for_testing",
|
||||
]
|
||||
|
||||
public_configs = [ ":external_config" ]
|
||||
}
|
||||
|
@ -64,6 +64,8 @@ _TEST_CODE_EXCLUDED_PATHS = (
|
||||
r'src[\\\/]extensions[\\\/]gc-extension\.cc',
|
||||
# Runtime functions used for testing.
|
||||
r'src[\\\/]runtime[\\\/]runtime-test\.cc',
|
||||
# Testing helpers.
|
||||
r'src[\\\/]heap[\\\/]cppgc[\\\/]testing\.cc',
|
||||
)
|
||||
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef INCLUDE_CPPGC_MACROS_H_
|
||||
#define INCLUDE_CPPGC_MACROS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "cppgc/internal/compiler-specific.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
69
include/cppgc/testing.h
Normal file
69
include/cppgc/testing.h
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_TESTING_H_
|
||||
#define INCLUDE_CPPGC_TESTING_H_
|
||||
|
||||
#include "cppgc/common.h"
|
||||
#include "cppgc/macros.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
class HeapHandle;
|
||||
|
||||
/**
|
||||
* Namespace contains testing helpers.
|
||||
|
||||
* Helpers are only enabled after invoking `Heap::EnableTestingAPIsForTesting()`
|
||||
and will crash otherwise.
|
||||
*/
|
||||
namespace testing {
|
||||
|
||||
/**
|
||||
* Testing helper used to acces heap internals.
|
||||
|
||||
* Only enabled after invoking `EnableTestingAPIsForTesting()`.
|
||||
*/
|
||||
class V8_EXPORT Heap final {
|
||||
public:
|
||||
/**
|
||||
* Enables testing APIs that can be found in the corresponding `testing`
|
||||
* namespace.
|
||||
*
|
||||
* \param heap_handle
|
||||
*/
|
||||
static void EnableTestingAPIsForTesting(HeapHandle& heap_handle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Overrides the state of the stack with the provided value. Takes precedence
|
||||
* over other parameters that set the stack state. Must no be nested.
|
||||
*/
|
||||
class V8_EXPORT V8_NODISCARD OverrideEmbedderStackStateScope final {
|
||||
CPPGC_STACK_ALLOCATED();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a scoped object that automatically enters and leaves the scope.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
*/
|
||||
explicit OverrideEmbedderStackStateScope(HeapHandle& heap_handle,
|
||||
EmbedderStackState state);
|
||||
~OverrideEmbedderStackStateScope();
|
||||
|
||||
OverrideEmbedderStackStateScope(const OverrideEmbedderStackStateScope&) =
|
||||
delete;
|
||||
OverrideEmbedderStackStateScope& operator=(
|
||||
const OverrideEmbedderStackStateScope&) = delete;
|
||||
|
||||
private:
|
||||
HeapHandle& heap_handle_;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_TESTING_H_
|
@ -261,6 +261,9 @@ void CppHeap::EnterFinalPause(EmbedderStackState stack_state) {
|
||||
cppgc::internal::StatsCollector::EnabledScope stats_scope(
|
||||
AsBase(), cppgc::internal::StatsCollector::kAtomicMark);
|
||||
in_atomic_pause_ = true;
|
||||
if (override_stack_state_) {
|
||||
stack_state = *override_stack_state_;
|
||||
}
|
||||
marker_->EnterAtomicPause(stack_state);
|
||||
if (compactor_.CancelIfShouldNotCompact(cppgc::Heap::MarkingType::kAtomic,
|
||||
stack_state)) {
|
||||
|
@ -53,6 +53,20 @@ class ObjectSizeCounter : private HeapVisitor<ObjectSizeCounter> {
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
HeapBase& HeapBase::ForTesting(cppgc::HeapHandle& heap_handle) {
|
||||
auto& heap = From(heap_handle);
|
||||
CHECK(heap.TestingEnabled());
|
||||
return heap;
|
||||
}
|
||||
|
||||
// static
|
||||
const HeapBase& HeapBase::ForTesting(const cppgc::HeapHandle& heap_handle) {
|
||||
const auto& heap = From(heap_handle);
|
||||
CHECK(heap.TestingEnabled());
|
||||
return heap;
|
||||
}
|
||||
|
||||
HeapBase::HeapBase(
|
||||
std::shared_ptr<cppgc::Platform> platform,
|
||||
const std::vector<std::unique_ptr<CustomSpaceBase>>& custom_spaces,
|
||||
|
@ -36,6 +36,10 @@ class DisallowGarbageCollectionScope;
|
||||
class NoGarbageCollectionScope;
|
||||
} // namespace subtle
|
||||
|
||||
namespace testing {
|
||||
class OverrideEmbedderStackStateScope;
|
||||
} // namespace testing
|
||||
|
||||
class Platform;
|
||||
|
||||
class V8_EXPORT HeapHandle {
|
||||
@ -66,6 +70,9 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
|
||||
return static_cast<const HeapBase&>(heap_handle);
|
||||
}
|
||||
|
||||
static HeapBase& ForTesting(cppgc::HeapHandle& heap_handle);
|
||||
static const HeapBase& ForTesting(const cppgc::HeapHandle& heap_handle);
|
||||
|
||||
HeapBase(std::shared_ptr<cppgc::Platform> platform,
|
||||
const std::vector<std::unique_ptr<CustomSpaceBase>>& custom_spaces,
|
||||
StackSupport stack_support,
|
||||
@ -153,6 +160,9 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
|
||||
bool in_disallow_gc_scope() const { return disallow_gc_scope_ > 0; }
|
||||
bool in_atomic_pause() const { return in_atomic_pause_; }
|
||||
|
||||
void EnableTestingAPIsForTesting() { testing_enabled_ = true; }
|
||||
bool TestingEnabled() const { return testing_enabled_; }
|
||||
|
||||
protected:
|
||||
virtual void FinalizeIncrementalGarbageCollectionIfNeeded(
|
||||
cppgc::Heap::StackState) = 0;
|
||||
@ -190,13 +200,16 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
|
||||
size_t disallow_gc_scope_ = 0;
|
||||
|
||||
const StackSupport stack_support_;
|
||||
std::unique_ptr<EmbedderStackState> override_stack_state_;
|
||||
|
||||
bool in_atomic_pause_ = false;
|
||||
bool testing_enabled_ = false;
|
||||
|
||||
friend class MarkerBase::IncrementalMarkingTask;
|
||||
friend class testing::TestWithHeap;
|
||||
friend class cppgc::subtle::DisallowGarbageCollectionScope;
|
||||
friend class cppgc::subtle::NoGarbageCollectionScope;
|
||||
friend class cppgc::testing::OverrideEmbedderStackStateScope;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -173,12 +173,15 @@ void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
|
||||
DCHECK(!in_no_gc_scope());
|
||||
CHECK(!in_disallow_gc_scope());
|
||||
config_.stack_state = stack_state;
|
||||
if (override_stack_state_) {
|
||||
config_.stack_state = *override_stack_state_;
|
||||
}
|
||||
in_atomic_pause_ = true;
|
||||
{
|
||||
// This guards atomic pause marking, meaning that no internal method or
|
||||
// external callbacks are allowed to allocate new objects.
|
||||
cppgc::subtle::DisallowGarbageCollectionScope no_gc_scope(*this);
|
||||
marker_->FinishMarking(stack_state);
|
||||
marker_->FinishMarking(config_.stack_state);
|
||||
}
|
||||
{
|
||||
// Pre finalizers are forbidden from allocating objects.
|
||||
@ -189,7 +192,7 @@ void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
|
||||
// TODO(chromium:1056170): replace build flag with dedicated flag.
|
||||
#if DEBUG
|
||||
MarkingVerifier verifier(*this);
|
||||
verifier.Run(stack_state);
|
||||
verifier.Run(config_.stack_state);
|
||||
#endif
|
||||
|
||||
subtle::NoGarbageCollectionScope no_gc(*this);
|
||||
|
31
src/heap/cppgc/testing.cc
Normal file
31
src/heap/cppgc/testing.cc
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2021 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 "include/cppgc/testing.h"
|
||||
|
||||
#include "src/base/logging.h"
|
||||
#include "src/heap/cppgc/heap-base.h"
|
||||
|
||||
namespace cppgc {
|
||||
namespace testing {
|
||||
|
||||
void Heap::EnableTestingAPIsForTesting(HeapHandle& heap_handle) {
|
||||
internal::HeapBase::From(heap_handle).EnableTestingAPIsForTesting();
|
||||
}
|
||||
|
||||
OverrideEmbedderStackStateScope::OverrideEmbedderStackStateScope(
|
||||
HeapHandle& heap_handle, EmbedderStackState state)
|
||||
: heap_handle_(heap_handle) {
|
||||
auto& heap = internal::HeapBase::ForTesting(heap_handle_);
|
||||
CHECK_NULL(heap.override_stack_state_.get());
|
||||
heap.override_stack_state_ = std::make_unique<EmbedderStackState>(state);
|
||||
}
|
||||
|
||||
OverrideEmbedderStackStateScope::~OverrideEmbedderStackStateScope() {
|
||||
auto& heap = internal::HeapBase::ForTesting(heap_handle_);
|
||||
heap.override_stack_state_.reset();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace cppgc
|
@ -119,6 +119,7 @@ v8_source_set("cppgc_unittests_sources") {
|
||||
"heap/cppgc/sweeper-unittest.cc",
|
||||
"heap/cppgc/test-platform.cc",
|
||||
"heap/cppgc/test-platform.h",
|
||||
"heap/cppgc/testing-unittest.cc",
|
||||
"heap/cppgc/tests.cc",
|
||||
"heap/cppgc/tests.h",
|
||||
"heap/cppgc/visitor-unittest.cc",
|
||||
|
62
test/unittests/heap/cppgc/testing-unittest.cc
Normal file
62
test/unittests/heap/cppgc/testing-unittest.cc
Normal file
@ -0,0 +1,62 @@
|
||||
// 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 "include/cppgc/testing.h"
|
||||
|
||||
#include "include/cppgc/allocation.h"
|
||||
#include "include/cppgc/garbage-collected.h"
|
||||
#include "include/cppgc/persistent.h"
|
||||
#include "test/unittests/heap/cppgc/tests.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
class TestingTest : public testing::TestWithHeap {};
|
||||
|
||||
class GCed : public GarbageCollected<GCed> {
|
||||
public:
|
||||
void Trace(Visitor*) const {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_F(TestingTest, EnableTesting) {
|
||||
EXPECT_FALSE(internal::Heap::From(GetHeap())->TestingEnabled());
|
||||
cppgc::testing::Heap::EnableTestingAPIsForTesting(GetHeap()->GetHeapHandle());
|
||||
EXPECT_TRUE(internal::Heap::From(GetHeap())->TestingEnabled());
|
||||
}
|
||||
|
||||
TEST_F(TestingTest, OverrideEmbedderStackStateScope) {
|
||||
{
|
||||
auto* gced = MakeGarbageCollected<GCed>(GetHeap()->GetAllocationHandle());
|
||||
WeakPersistent<GCed> weak{gced};
|
||||
internal::Heap::From(GetHeap())->CollectGarbage(
|
||||
Heap::Config::PreciseAtomicConfig());
|
||||
EXPECT_FALSE(weak);
|
||||
}
|
||||
cppgc::testing::Heap::EnableTestingAPIsForTesting(GetHeap()->GetHeapHandle());
|
||||
{
|
||||
auto* gced = MakeGarbageCollected<GCed>(GetHeap()->GetAllocationHandle());
|
||||
WeakPersistent<GCed> weak{gced};
|
||||
cppgc::testing::OverrideEmbedderStackStateScope override_stack(
|
||||
GetHeap()->GetHeapHandle(),
|
||||
EmbedderStackState::kMayContainHeapPointers);
|
||||
internal::Heap::From(GetHeap())->CollectGarbage(
|
||||
Heap::Config::PreciseAtomicConfig());
|
||||
EXPECT_TRUE(weak);
|
||||
}
|
||||
{
|
||||
auto* gced = MakeGarbageCollected<GCed>(GetHeap()->GetAllocationHandle());
|
||||
WeakPersistent<GCed> weak{gced};
|
||||
cppgc::testing::OverrideEmbedderStackStateScope override_stack(
|
||||
GetHeap()->GetHeapHandle(), EmbedderStackState::kNoHeapPointers);
|
||||
internal::Heap::From(GetHeap())->CollectGarbage(
|
||||
Heap::Config::ConservativeAtomicConfig());
|
||||
EXPECT_FALSE(weak);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
Loading…
Reference in New Issue
Block a user