Introduce SinkDestructor so that we can tack on an extra finalizer

This commit is contained in:
Jarred Sumner
2024-02-11 04:33:56 -08:00
parent 6d96790fcf
commit abc607d6d1
2 changed files with 75 additions and 13 deletions

View File

@@ -1489,6 +1489,40 @@ const AutoFlusher = struct {
}
};
pub const SinkDestructor = struct {
const Detached = opaque {};
const Subprocess = JSC.API.Bun.Subprocess;
pub const Ptr = bun.TaggedPointerUnion(.{
Detached,
Subprocess,
});
pub export fn Bun__onSinkDestroyed(
ptr_value: ?*anyopaque,
sink_ptr: ?*anyopaque,
) callconv(.C) void {
_ = sink_ptr; // autofix
const ptr = Ptr.from(ptr_value);
if (ptr.isNull()) {
return;
}
switch (ptr.tag()) {
.Detached => {
return;
},
.Subprocess => {
const subprocess = ptr.as(Subprocess);
subprocess.onStdinDestroyed();
},
else => {
Output.debugWarn("Unknown sink type", .{});
},
}
}
};
pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
return struct {
sink: SinkType,

View File

@@ -64,7 +64,7 @@ function header() {
class ${className} final : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;
static ${className}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr);
static ${className}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr, uintptr_t destructor = 0);
static constexpr SinkID Sink = SinkID::${name};
DECLARE_EXPORT_INFO;
@@ -105,11 +105,14 @@ function header() {
void* m_sinkPtr;
int m_refCount { 1 };
uintptr_t m_onDestroy { 0 };
${className}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
${className}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
: Base(vm, structure)
{
m_sinkPtr = sinkPtr;
m_onDestroy = onDestroy;
}
void finishCreation(JSC::VM&);
@@ -120,7 +123,7 @@ function header() {
class ${controller} final : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;
static ${controller}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr);
static ${controller}* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy);
static constexpr SinkID Sink = SinkID::${name};
DECLARE_EXPORT_INFO;
@@ -158,11 +161,14 @@ function header() {
mutable WriteBarrier<JSC::Unknown> m_onPull;
mutable WriteBarrier<JSC::Unknown> m_onClose;
mutable JSC::Weak<JSObject> m_weakReadableStream;
uintptr_t m_onDestroy { 0 };
${controller}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
${controller}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
: Base(vm, structure)
{
m_sinkPtr = sinkPtr;
m_onDestroy = onDestroy;
}
void finishCreation(JSC::VM&);
@@ -267,7 +273,7 @@ async function implementation() {
#include <JavaScriptCore/Weak.h>
#include <JavaScriptCore/WeakInlines.h>
extern "C" void Bun__onSinkDestroyed(uintptr_t destructor, void* sinkPtr);
namespace WebCore {
using namespace JSC;
@@ -403,7 +409,6 @@ JSC_DEFINE_CUSTOM_GETTER(function${name}__getter, (JSC::JSGlobalObject * lexical
return JSC::JSValue::encode(globalObject->${name}());
}
JSC_DECLARE_HOST_FUNCTION(${controller}__close);
JSC_DEFINE_HOST_FUNCTION(${controller}__close, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame *callFrame))
{
@@ -562,6 +567,10 @@ const ClassInfo ${controller}::s_info = { "${controllerName}"_s, &Base::s_info,
${className}::~${className}()
{
if (m_onDestroy) {
Bun__onSinkDestroyed(m_onDestroy, m_sinkPtr);
}
if (m_sinkPtr) {
${name}__finalize(m_sinkPtr);
}
@@ -570,6 +579,10 @@ ${className}::~${className}()
${controller}::~${controller}()
{
if (m_onDestroy) {
Bun__onSinkDestroyed(m_onDestroy, m_sinkPtr);
}
if (m_sinkPtr) {
${name}__finalize(m_sinkPtr);
}
@@ -586,6 +599,12 @@ JSObject* JS${controllerName}::createPrototype(VM& vm, JSDOMGlobalObject& global
}
void JS${controllerName}::detach() {
if (m_onDestroy) {
auto destroy = m_onDestroy;
m_onDestroy = 0;
Bun__onSinkDestroyed(destroy, m_sinkPtr);
}
m_sinkPtr = nullptr;
m_onPull.clear();
@@ -617,16 +636,16 @@ ${constructor}* ${constructor}::create(JSC::VM& vm, JSC::JSGlobalObject* globalO
return ptr;
}
${className}* ${className}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr)
${className}* ${className}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
{
${className}* ptr = new (NotNull, JSC::allocateCell<${className}>(vm)) ${className}(vm, structure, sinkPtr);
${className}* ptr = new (NotNull, JSC::allocateCell<${className}>(vm)) ${className}(vm, structure, sinkPtr, onDestroy);
ptr->finishCreation(vm);
return ptr;
}
${controller}* ${controller}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr)
${controller}* ${controller}::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
{
${controller}* ptr = new (NotNull, JSC::allocateCell<${controller}>(vm)) ${controller}(vm, structure, sinkPtr);
${controller}* ptr = new (NotNull, JSC::allocateCell<${controller}>(vm)) ${controller}(vm, structure, sinkPtr, onDestroy);
ptr->finishCreation(vm);
return ptr;
}
@@ -679,6 +698,15 @@ void ${controller}::finishCreation(VM& vm)
ASSERT(inherits(info()));
}
extern "C" void ${name}__setDestroyCallback(EncodedJSValue encodedValue, uintptr_t callback)
{
JSValue value = JSValue::decode(encodedValue);
if (auto* sink = JSC::jsDynamicCast<WebCore::${className}*>(value)) {
sink->m_onDestroy = callback;
} else if (auto* controller = JSC::jsDynamicCast<WebCore::${controller}*>(value)) {
controller->m_onDestroy = callback;
}
}
void ${className}::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
{
@@ -817,12 +845,12 @@ default:
const { className, controller, prototypeName, controllerPrototypeName, constructor } = names(name);
templ += `
extern "C" JSC__JSValue ${name}__createObject(JSC__JSGlobalObject* arg0, void* sinkPtr)
extern "C" JSC__JSValue ${name}__createObject(JSC__JSGlobalObject* arg0, void* sinkPtr, uintptr_t destructor)
{
auto& vm = arg0->vm();
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg0);
JSC::Structure* structure = globalObject->${name}Structure();
return JSC::JSValue::encode(WebCore::JS${name}::create(vm, globalObject, structure, sinkPtr));
return JSC::JSValue::encode(WebCore::JS${name}::create(vm, globalObject, structure, sinkPtr, destructor));
}
extern "C" void* ${name}__fromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1)
@@ -857,7 +885,7 @@ extern "C" JSC__JSValue ${name}__assignToStream(JSC__JSGlobalObject* arg0, JSC__
Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg0);
JSC::Structure* structure = WebCore::getDOMStructure<WebCore::${controller}>(vm, *globalObject);
WebCore::${controller} *controller = WebCore::${controller}::create(vm, globalObject, structure, sinkPtr);
WebCore::${controller} *controller = WebCore::${controller}::create(vm, globalObject, structure, sinkPtr, 0);
*controllerValue = reinterpret_cast<void*>(JSC::JSValue::encode(controller));
return globalObject->assignToStream(JSC::JSValue::decode(stream), controller);
}