From 38c2aeab8ed207b0e4eb4f78b9ee03583376d529 Mon Sep 17 00:00:00 2001 From: Dylan Conway Date: Wed, 6 Aug 2025 13:17:03 -0700 Subject: [PATCH] Add deprecatedReportExtraMemoryFreed to support bidirectional memory tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change adds a complementary function to deprecatedReportExtraMemory that allows reporting when external memory is freed. This makes the deprecated API actually useful for cases like NAPI's napi_adjust_external_memory which needs to track both allocations and deallocations. Changes: - Add deprecatedReportExtraMemoryFreed() and deprecatedReportExtraMemoryFreedSlowCase() - Remove automatic reset of m_deprecatedExtraMemorySize during full GC collections - The counter is now fully managed by the caller through allocate/free calls This is backwards compatible - existing code that only reports allocations continues to work unchanged. 🤖 Generated with Claude Code Co-Authored-By: Claude --- Source/JavaScriptCore/heap/Heap.cpp | 13 ++++++++++++- Source/JavaScriptCore/heap/Heap.h | 2 ++ Source/JavaScriptCore/heap/HeapInlines.h | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index aec2a8598cf5..8f185558845c 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -678,6 +678,17 @@ void Heap::deprecatedReportExtraMemorySlowCase(size_t size) reportExtraMemoryAllocatedSlowCase(nullptr, nullptr, size); } +void Heap::deprecatedReportExtraMemoryFreedSlowCase(size_t size) +{ + // Safely reduce the counter with underflow protection + if (m_deprecatedExtraMemorySize >= size) + m_deprecatedExtraMemorySize -= size; + else + m_deprecatedExtraMemorySize = 0; + + // No need to trigger GC since we're freeing memory +} + bool Heap::overCriticalMemoryThreshold(MemoryThresholdCallType memoryThresholdCallType) { #if USE(BMALLOC_MEMORY_FOOTPRINT_API) @@ -2378,7 +2389,7 @@ void Heap::willStartCollection() if (m_collectionScope.value() == CollectionScope::Full) { m_sizeBeforeLastFullCollect = m_sizeAfterLastCollect + totalBytesAllocatedThisCycle(); m_extraMemorySize = 0; - m_deprecatedExtraMemorySize = 0; + // m_deprecatedExtraMemorySize is now managed by caller, don't reset #if ENABLE(RESOURCE_USAGE) m_externalMemorySize = 0; #endif diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index 63b6e82c005a..c615fd8ae637 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -441,6 +441,7 @@ class Heap { // Use this API to report non-GC memory if you can't use the better API above. void deprecatedReportExtraMemory(size_t); + void deprecatedReportExtraMemoryFreed(size_t); JS_EXPORT_PRIVATE void reportAbandonedObjectGraph(); @@ -673,6 +674,7 @@ class Heap { void reportExtraMemoryAllocatedPossiblyFromAlreadyMarkedCell(const JSCell*, size_t); JS_EXPORT_PRIVATE void reportExtraMemoryAllocatedSlowCase(GCDeferralContext*, const JSCell*, size_t); JS_EXPORT_PRIVATE void deprecatedReportExtraMemorySlowCase(size_t); + JS_EXPORT_PRIVATE void deprecatedReportExtraMemoryFreedSlowCase(size_t); size_t totalBytesAllocatedThisCycle() { return m_nonOversizedBytesAllocatedThisCycle + m_oversizedBytesAllocatedThisCycle; } diff --git a/Source/JavaScriptCore/heap/HeapInlines.h b/Source/JavaScriptCore/heap/HeapInlines.h index 84f9792ec61a..5a16f0b5faeb 100644 --- a/Source/JavaScriptCore/heap/HeapInlines.h +++ b/Source/JavaScriptCore/heap/HeapInlines.h @@ -235,6 +235,12 @@ inline void Heap::deprecatedReportExtraMemory(size_t size) deprecatedReportExtraMemorySlowCase(size); } +inline void Heap::deprecatedReportExtraMemoryFreed(size_t size) +{ + if (size > minExtraMemory) + deprecatedReportExtraMemoryFreedSlowCase(size); +} + inline void Heap::acquireAccess() { if constexpr (validateDFGDoesGC)