diff options
author | 2023-10-17 21:24:20 -0700 | |
---|---|---|
committer | 2023-10-17 21:24:20 -0700 | |
commit | 55fb29667add625762e33398e8737626d1648a03 (patch) | |
tree | 302791d1f08d8bdc497ead16cfb685bcabc9d43f | |
parent | b8175ac13d2a3fc2ebf33a95a959400a1d5d9c56 (diff) | |
download | bun-55fb29667add625762e33398e8737626d1648a03.tar.gz bun-55fb29667add625762e33398e8737626d1648a03.tar.zst bun-55fb29667add625762e33398e8737626d1648a03.zip |
Add JSC.Weak
-rw-r--r-- | src/bun.js/Weak.zig | 199 | ||||
-rw-r--r-- | src/bun.js/bindings/Weak.cpp | 94 |
2 files changed, 293 insertions, 0 deletions
diff --git a/src/bun.js/Weak.zig b/src/bun.js/Weak.zig new file mode 100644 index 000000000..c1c5d0484 --- /dev/null +++ b/src/bun.js/Weak.zig @@ -0,0 +1,199 @@ +const bun = @import("root").bun; +const JSC = bun.JSC; +const std = @import("std"); + +/// This value must be kept in sync with Weak.cpp +pub const WeakRefFinalizerTag = *const fn (*anyopaque) callconv(.C) void; + +const WeakImpl = opaque { + pub fn init(ptr: *anyopaque, comptime tag: ?WeakRefFinalizerTag, value: JSC.JSValue) *WeakImpl { + JSC.markBinding(@src()); + return Bun__WeakRef__new(value, tag, ptr); + } + + pub fn get(this: *WeakImpl) JSC.JSValue { + JSC.markBinding(@src()); + return Bun__WeakRef__get(this); + } + + pub fn set(this: *WeakImpl, ptr: *anyopaque, comptime tag: ?WeakRefFinalizerTag, value: JSC.JSValue) void { + JSC.markBinding(@src()); + Bun__WeakRef__set(this, value, tag, ptr); + } + + pub fn clear(this: *WeakImpl) void { + JSC.markBinding(@src()); + Bun__WeakRef__clear(this); + } + + pub fn deinit( + this: *WeakImpl, + ) void { + JSC.markBinding(@src()); + Bun__WeakRef__delete(this); + } + + extern fn Bun__WeakRef__delete(this: *WeakImpl) void; + extern fn Bun__WeakRef__new(JSC.JSValue, ?WeakRefFinalizerTag, *anyopaque) *WeakImpl; + extern fn Bun__WeakRef__get(this: *WeakImpl) JSC.JSValue; + extern fn Bun__WeakRef__set(this: *WeakImpl, JSC.JSValue, ?WeakRefFinalizerTag, *anyopaque) void; + extern fn Bun__WeakRef__clear(this: *WeakImpl) void; +}; + +pub fn NewWeakFinalizer(comptime Context: type, comptime FinalizerFn: *const fn (*Context) callconv(.C) void) type { + return struct { + ref: ?*WeakImpl = null, + + const finalizer: WeakRefFinalizerTag = @ptrCast(FinalizerFn); + + pub const WeakFinalizer = @This(); + + pub fn init() WeakFinalizer { + return .{}; + } + + pub fn create( + ptr: *Context, + value: JSC.JSValue, + ) WeakFinalizer { + if (value != .zero) { + return .{ .ref = WeakImpl.init( + ptr, + finalizer, + value, + ) }; + } + + return .{}; + } + + pub fn get(this: *WeakFinalizer) ?JSC.JSValue { + var ref = this.ref orelse return null; + const result = ref.get(); + if (result == .zero) { + return null; + } + + return result; + } + + pub fn swap(this: *WeakFinalizer) JSC.JSValue { + var ref = this.ref orelse return .zero; + const result = ref.get(); + if (result == .zero) { + return .zero; + } + + ref.clear(); + return result; + } + + pub fn has(this: *WeakFinalizer) bool { + var ref = this.ref orelse return false; + return ref.get() != .zero; + } + + pub fn trySwap(this: *WeakFinalizer) ?JSC.JSValue { + const result = this.swap(); + if (result == .zero) { + return null; + } + + return result; + } + + pub fn set(this: *WeakFinalizer, ptr: *Context, value: JSC.JSValue) void { + var ref: *WeakImpl = this.ref orelse { + if (value == .zero) return; + this.ref = WeakImpl.init(ptr, finalizer, value); + return; + }; + ref.set(ptr, finalizer, value); + } + + pub fn clear(this: *WeakFinalizer) void { + var ref: *WeakImpl = this.ref orelse return; + ref.clear(); + } + + pub fn deinit(this: *WeakFinalizer) void { + var ref: *WeakImpl = this.ref orelse return; + this.ref = null; + ref.deinit(); + } + }; +} + +pub const Weak = struct { + ref: ?*WeakImpl = null, + + pub fn init() Weak { + return .{}; + } + + pub fn create( + ptr: *anyopaque, + value: JSC.JSValue, + ) Weak { + if (value != .zero) { + return .{ .ref = WeakImpl.init(ptr, value, null) }; + } + + return .{}; + } + + pub fn get(this: *Weak) ?JSC.JSValue { + var ref = this.ref orelse return null; + const result = ref.get(); + if (result == .zero) { + return null; + } + + return result; + } + + pub fn swap(this: *Weak) JSC.JSValue { + var ref = this.ref orelse return .zero; + const result = ref.get(); + if (result == .zero) { + return .zero; + } + + ref.clear(); + return result; + } + + pub fn has(this: *Weak) bool { + var ref = this.ref orelse return false; + return ref.get() != .zero; + } + + pub fn trySwap(this: *Weak) ?JSC.JSValue { + const result = this.swap(); + if (result == .zero) { + return null; + } + + return result; + } + + pub fn set(this: *Weak, ptr: *anyopaque, value: JSC.JSValue) void { + var ref: *WeakImpl = this.ref orelse { + if (value == .zero) return; + this.ref = WeakImpl.init(ptr, null, value); + return; + }; + ref.set(ptr, null, value); + } + + pub fn clear(this: *Weak) void { + var ref: *WeakImpl = this.ref orelse return; + ref.clear(); + } + + pub fn deinit(this: *Weak) void { + var ref: *WeakImpl = this.ref orelse return; + this.ref = null; + ref.deinit(); + } +}; diff --git a/src/bun.js/bindings/Weak.cpp b/src/bun.js/bindings/Weak.cpp new file mode 100644 index 000000000..a1b669343 --- /dev/null +++ b/src/bun.js/bindings/Weak.cpp @@ -0,0 +1,94 @@ +#include "root.h" +#include "BunClientData.h" +#include <JavaScriptCore/Weak.h> +#include <JavaScriptCore/WeakInlines.h> + +namespace Bun { +using WeakRefFinalizerTag = uintptr_t; + +template<void (*finalizer)(void*)> +class WeakRefFinalizerClass : public JSC::WeakHandleOwner { +public: + WeakRefFinalizerClass() + : JSC::WeakHandleOwner() + { + } + + void finalize(JSC::Handle<JSC::Unknown>, void* context) + { + finalizer(context); + } + + static WeakHandleOwner& singleton() + { + static NeverDestroyed<WeakRefFinalizerClass<finalizer>> s_singleton; + return s_singleton; + } +}; + +extern "C" void Bun__PostgreSQLQueryClient__target_onFinalize(void*); + +using PostgreSQLQueryClient__targetWeakRefFinalizer = WeakRefFinalizerClass<Bun__PostgreSQLQueryClient__target_onFinalize>; + +static inline JSC::WeakHandleOwner* getOwner(WeakRefFinalizerTag tag) +{ + if (tag == reinterpret_cast<uintptr_t>(Bun__PostgreSQLQueryClient__target_onFinalize)) + return &PostgreSQLQueryClient__targetWeakRefFinalizer::singleton(); + + if (tag == 0) + return nullptr; + + RELEASE_ASSERT_NOT_REACHED_WITH_MESSAGE("Unknown WeakRefFinalizerTag"); + return nullptr; +} + +class WeakRef { + WTF_MAKE_ISO_ALLOCATED(WeakRef); + +public: + WeakRef() + : m_weak() + { + } + + static inline WeakRef* create(JSC::JSObject* value, WeakRefFinalizerTag tag, void* context) + { + return new WeakRef(value, tag, context); + } + + WeakRef(JSC::JSObject* value, WeakRefFinalizerTag tag, void* context) + { + m_weak = JSC::Weak<JSC::JSObject>(value, getOwner(tag), context); + } + + JSC::Weak<JSC::JSObject> m_weak; +}; + +WTF_MAKE_ISO_ALLOCATED_IMPL(WeakRef); + +extern "C" void Bun__WeakRef__delete(Bun::WeakRef* ref) +{ + delete ref; +} + +extern "C" Bun::WeakRef* Bun__WeakRef__new(JSC::EncodedJSValue encodedValue, WeakRefFinalizerTag tag, void* context) +{ + return Bun::WeakRef::create(JSC::JSValue::decode(encodedValue).getObject(), tag, context); +} + +extern "C" JSC::EncodedJSValue Bun__WeakRef__get(Bun::WeakRef* weakRef) +{ + return JSC::JSValue::encode(weakRef->m_weak.get()); +} + +extern "C" void Bun__WeakRef__set(Bun::WeakRef* weakRef, JSC::EncodedJSValue encodedValue, WeakRefFinalizerTag tag, void* context) +{ + weakRef->m_weak = JSC::Weak<JSC::JSObject>(JSC::JSValue::decode(encodedValue).getObject(), getOwner(tag), context); +} + +extern "C" void Bun__WeakRef__clear(Bun::WeakRef* weakRef) +{ + weakRef->m_weak.clear(); +} + +}
\ No newline at end of file |