From 6274f1009605e57ffab10741d2b066b6557c8b64 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 17 Jun 2025 13:30:58 -0700 Subject: [PATCH] Make Strong use less ram (#20437) Co-authored-by: Claude Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: Jarred Sumner --- src/bun.js/bindings/BunDebugger.cpp | 7 ++-- src/bun.js/bindings/Strong.cpp | 52 +++++++++++++++++++---------- src/bun.js/bindings/Strong.h | 35 ------------------- src/bun.js/bindings/napi.cpp | 1 - 4 files changed, 37 insertions(+), 58 deletions(-) delete mode 100644 src/bun.js/bindings/Strong.h diff --git a/src/bun.js/bindings/BunDebugger.cpp b/src/bun.js/bindings/BunDebugger.cpp index 9abe76a820..ed686b308d 100644 --- a/src/bun.js/bindings/BunDebugger.cpp +++ b/src/bun.js/bindings/BunDebugger.cpp @@ -7,7 +7,6 @@ #include #include #include "ScriptExecutionContext.h" -#include "Strong.h" #include "debug-helpers.h" #include "BunInjectedScriptHost.h" #include @@ -311,7 +310,7 @@ public: this->debuggerThreadMessages.swap(messages); } - JSFunction* onMessageFn = jsCast(jsBunDebuggerOnMessageFunction->m_cell.get()); + JSFunction* onMessageFn = jsCast(jsBunDebuggerOnMessageFunction.get()); MarkedArgumentBuffer arguments; arguments.ensureCapacity(messages.size()); auto& vm = debuggerGlobalObject->vm(); @@ -381,7 +380,7 @@ public: JSC::JSGlobalObject* globalObject; ScriptExecutionContextIdentifier scriptExecutionContextIdentifier; - Bun::StrongRef* jsBunDebuggerOnMessageFunction = nullptr; + JSC::Strong jsBunDebuggerOnMessageFunction {}; WTF::Lock jsWaitForMessageFromInspectorLock; std::atomic status = ConnectionStatus::Pending; @@ -567,7 +566,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionCreateConnection, (JSGlobalObject * globalObj connections.append(connection); inspectorConnections->set(targetContext->identifier(), connections); } - connection->jsBunDebuggerOnMessageFunction = new Bun::StrongRef(vm, onMessageFn); + connection->jsBunDebuggerOnMessageFunction = { vm, onMessageFn }; connection->connect(); return JSValue::encode(JSBunInspectorConnection::create(vm, JSBunInspectorConnection::createStructure(vm, globalObject, globalObject->objectPrototype()), connection)); diff --git a/src/bun.js/bindings/Strong.cpp b/src/bun.js/bindings/Strong.cpp index f30bd7f758..d60f52eb7c 100644 --- a/src/bun.js/bindings/Strong.cpp +++ b/src/bun.js/bindings/Strong.cpp @@ -1,37 +1,53 @@ #include "root.h" +#include #include #include "BunClientData.h" #include "wtf/DebugHeap.h" -#include "Strong.h" -namespace Bun { +#include "ZigGlobalObject.h" -#if ENABLE(MALLOC_BREAKDOWN) -DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(StrongRef); -#endif - -} - -extern "C" void Bun__StrongRef__delete(Bun::StrongRef* strongRef) +extern "C" void Bun__StrongRef__delete(JSC::JSValue* _Nonnull handleSlot) { - delete strongRef; + // deallocate() will correctly remove the handle from the strong list if it's currently on it. + JSC::HandleSet::heapFor(handleSlot)->deallocate(handleSlot); } -extern "C" Bun::StrongRef* Bun__StrongRef__new(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue) +extern "C" JSC::JSValue* Bun__StrongRef__new(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue) { - return new Bun::StrongRef(globalObject->vm(), JSC::JSValue::decode(encodedValue)); + auto& vm = globalObject->vm(); + JSC::HandleSet* handleSet = vm.heap.handleSet(); + JSC::HandleSlot handleSlot = handleSet->allocate(); + JSC::JSValue value = JSC::JSValue::decode(encodedValue); + + // The write barrier must be called to add the handle to the strong + // list if the new value is a cell. We must use because the value + // might be a primitive. + handleSet->writeBarrier(handleSlot, value); + *handleSlot = value; + return handleSlot; } -extern "C" JSC::EncodedJSValue Bun__StrongRef__get(Bun::StrongRef* strongRef) +extern "C" JSC::EncodedJSValue Bun__StrongRef__get(JSC::JSValue* _Nonnull handleSlot) { - return JSC::JSValue::encode(strongRef->m_cell.get()); + return JSC::JSValue::encode(*handleSlot); } -extern "C" void Bun__StrongRef__set(Bun::StrongRef* strongRef, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +extern "C" void Bun__StrongRef__set(JSC::JSValue* _Nonnull handleSlot, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue) { - strongRef->m_cell.set(globalObject->vm(), JSC::JSValue::decode(value)); + auto& vm = globalObject->vm(); + JSC::JSValue value = JSC::JSValue::decode(encodedValue); + + // The write barrier must be called *before* the value in the slot is updated + // to correctly update the handle's status in the strong list (e.g. moving + // from strong to not strong or vice versa). + // Use because the new value can be a primitive. + vm.heap.handleSet()->writeBarrier(handleSlot, value); + *handleSlot = value; } -extern "C" void Bun__StrongRef__clear(Bun::StrongRef* strongRef) +extern "C" void Bun__StrongRef__clear(JSC::JSValue* _Nonnull handleSlot) { - strongRef->m_cell.clear(); + // The write barrier must be called *before* the value is cleared + // to correctly remove the handle from the strong list if it held a cell. + JSC::HandleSet::heapFor(handleSlot)->writeBarrier(handleSlot, JSC::JSValue()); + *handleSlot = JSC::JSValue(); } diff --git a/src/bun.js/bindings/Strong.h b/src/bun.js/bindings/Strong.h deleted file mode 100644 index bd87efd7c9..0000000000 --- a/src/bun.js/bindings/Strong.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "root.h" -#include "wtf/DebugHeap.h" -#include - -namespace Bun { - -// We tried to pool these -// But it was very complicated -#if ENABLE(MALLOC_BREAKDOWN) -DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(StrongRef); -#endif -class StrongRef { -#if ENABLE(MALLOC_BREAKDOWN) - WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(StrongRef); -#else - WTF_MAKE_TZONE_ALLOCATED(StrongRef); -#endif - -public: - StrongRef(JSC::VM& vm, JSC::JSValue value) - : m_cell(vm, value) - { - } - - StrongRef() - : m_cell() - { - } - - JSC::Strong m_cell; -}; - -} diff --git a/src/bun.js/bindings/napi.cpp b/src/bun.js/bindings/napi.cpp index 8fd003ceab..48154a3293 100644 --- a/src/bun.js/bindings/napi.cpp +++ b/src/bun.js/bindings/napi.cpp @@ -58,7 +58,6 @@ #include #include #include "ScriptExecutionContext.h" -#include "Strong.h" #include "../modules/ObjectModule.h"