cppgc: Fix flaky crash due to used bytes counters mismatch
Cppgc reports used bytes statistics to CppHeap. CppHeap should forward the stats to v8. However, if we are not allowed to trigger a GC, CppHeap will cache the stats until the reporting. On GC finalization, CppHeap resets v8's counters to the current marked bytes counter. If the last reported stats before GC finalization are cached, CppHeap doesn't clear the cache on GC finalization. On the next stats reporting, CppHeap will report the cached values. If the cache is a decrease that is larger than the current marked bytes, a DCHECK in LocalEmbedderHeapTracer::DecreaseAllocatedSize will fail. Bug: chromium:1056170 Change-Id: I47933abc3e5f5c4a91454e0ec03adde5cf61d8fc Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3056970 Commit-Queue: Omer Katz <omerkatz@chromium.org> Reviewed-by: Anton Bikineev <bikineev@chromium.org> Cr-Commit-Position: refs/heads/master@{#75986}
This commit is contained in:
parent
1d249e8cb4
commit
acb0263c7f
@ -474,13 +474,6 @@ void CppHeap::TraceEpilogue(TraceSummary* trace_summary) {
|
|||||||
marker_->LeaveAtomicPause();
|
marker_->LeaveAtomicPause();
|
||||||
}
|
}
|
||||||
marker_.reset();
|
marker_.reset();
|
||||||
if (isolate_) {
|
|
||||||
auto* tracer = isolate_->heap()->local_embedder_heap_tracer();
|
|
||||||
DCHECK_NOT_NULL(tracer);
|
|
||||||
tracer->UpdateRemoteStats(
|
|
||||||
stats_collector_->marked_bytes(),
|
|
||||||
stats_collector_->marking_time().InMillisecondsF());
|
|
||||||
}
|
|
||||||
ExecutePreFinalizers();
|
ExecutePreFinalizers();
|
||||||
// TODO(chromium:1056170): replace build flag with dedicated flag.
|
// TODO(chromium:1056170): replace build flag with dedicated flag.
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@ -528,6 +521,20 @@ void CppHeap::AllocatedObjectSizeDecreased(size_t bytes) {
|
|||||||
ReportBufferedAllocationSizeIfPossible();
|
ReportBufferedAllocationSizeIfPossible();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppHeap::ResetAllocatedObjectSize(size_t bytes) {
|
||||||
|
DCHECK(!sweeper().IsSweepingOnMutatorThread());
|
||||||
|
DCHECK(!in_no_gc_scope());
|
||||||
|
buffered_allocated_bytes_ = 0;
|
||||||
|
if (isolate_) {
|
||||||
|
auto* tracer = isolate_->heap()->local_embedder_heap_tracer();
|
||||||
|
DCHECK_NOT_NULL(tracer);
|
||||||
|
DCHECK_EQ(bytes, stats_collector_->marked_bytes());
|
||||||
|
tracer->UpdateRemoteStats(
|
||||||
|
stats_collector_->marked_bytes(),
|
||||||
|
stats_collector_->marking_time().InMillisecondsF());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CppHeap::ReportBufferedAllocationSizeIfPossible() {
|
void CppHeap::ReportBufferedAllocationSizeIfPossible() {
|
||||||
// Avoid reporting to V8 in the following conditions as that may trigger GC
|
// Avoid reporting to V8 in the following conditions as that may trigger GC
|
||||||
// finalizations where not allowed.
|
// finalizations where not allowed.
|
||||||
|
@ -114,7 +114,7 @@ class V8_EXPORT_PRIVATE CppHeap final
|
|||||||
// StatsCollector::AllocationObserver interface.
|
// StatsCollector::AllocationObserver interface.
|
||||||
void AllocatedObjectSizeIncreased(size_t) final;
|
void AllocatedObjectSizeIncreased(size_t) final;
|
||||||
void AllocatedObjectSizeDecreased(size_t) final;
|
void AllocatedObjectSizeDecreased(size_t) final;
|
||||||
void ResetAllocatedObjectSize(size_t) final {}
|
void ResetAllocatedObjectSize(size_t) final;
|
||||||
|
|
||||||
MetricRecorderAdapter* GetMetricRecorder() const;
|
MetricRecorderAdapter* GetMetricRecorder() const;
|
||||||
|
|
||||||
|
@ -5,7 +5,10 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "include/cppgc/allocation.h"
|
#include "include/cppgc/allocation.h"
|
||||||
|
#include "include/cppgc/explicit-management.h"
|
||||||
#include "include/cppgc/garbage-collected.h"
|
#include "include/cppgc/garbage-collected.h"
|
||||||
|
#include "include/cppgc/heap-consistency.h"
|
||||||
|
#include "include/cppgc/internal/api-constants.h"
|
||||||
#include "include/cppgc/persistent.h"
|
#include "include/cppgc/persistent.h"
|
||||||
#include "include/cppgc/platform.h"
|
#include "include/cppgc/platform.h"
|
||||||
#include "include/cppgc/testing.h"
|
#include "include/cppgc/testing.h"
|
||||||
@ -132,6 +135,43 @@ TEST_F(UnifiedHeapTest, WriteBarrierCppToV8Reference) {
|
|||||||
wrappable->wrapper()->GetAlignedPointerFromInternalField(1));
|
wrappable->wrapper()->GetAlignedPointerFromInternalField(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
namespace {
|
||||||
|
class Unreferenced : public cppgc::GarbageCollected<Unreferenced> {
|
||||||
|
public:
|
||||||
|
void Trace(cppgc::Visitor*) const {}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_F(UnifiedHeapTest, FreeUnreferencedDuringNoGcScope) {
|
||||||
|
v8::HandleScope scope(v8_isolate());
|
||||||
|
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
|
||||||
|
v8::Context::Scope context_scope(context);
|
||||||
|
auto* unreferenced = cppgc::MakeGarbageCollected<Unreferenced>(
|
||||||
|
allocation_handle(),
|
||||||
|
cppgc::AdditionalBytes(cppgc::internal::api_constants::kMB));
|
||||||
|
// Force safepoint to force flushing of cached allocated/freed sizes in cppgc.
|
||||||
|
cpp_heap().stats_collector()->NotifySafePointForTesting();
|
||||||
|
{
|
||||||
|
cppgc::subtle::NoGarbageCollectionScope scope(cpp_heap());
|
||||||
|
cppgc::internal::FreeUnreferencedObject(cpp_heap(), unreferenced);
|
||||||
|
// Force safepoint to make sure allocated size decrease due to freeing
|
||||||
|
// unreferenced object is reported to CppHeap. Due to
|
||||||
|
// NoGarbageCollectionScope, CppHeap will cache the reported decrease and
|
||||||
|
// won't report it further.
|
||||||
|
cpp_heap().stats_collector()->NotifySafePointForTesting();
|
||||||
|
}
|
||||||
|
// Running a GC resets the allocated size counters to the current marked bytes
|
||||||
|
// counter.
|
||||||
|
CollectGarbageWithoutEmbedderStack(cppgc::Heap::SweepingType::kAtomic);
|
||||||
|
// If CppHeap didn't clear it's cached values when the counters were reset,
|
||||||
|
// the next safepoint will try to decrease the cached value from the last
|
||||||
|
// marked bytes (which is smaller than the cached value) and crash.
|
||||||
|
cppgc::MakeGarbageCollected<Unreferenced>(allocation_handle());
|
||||||
|
cpp_heap().stats_collector()->NotifySafePointForTesting();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
#if !V8_OS_FUCHSIA
|
#if !V8_OS_FUCHSIA
|
||||||
TEST_F(UnifiedHeapTest, TracedReferenceRetainsFromStack) {
|
TEST_F(UnifiedHeapTest, TracedReferenceRetainsFromStack) {
|
||||||
v8::HandleScope scope(v8_isolate());
|
v8::HandleScope scope(v8_isolate());
|
||||||
|
Loading…
Reference in New Issue
Block a user