aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-10-17 21:24:20 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-10-17 21:24:20 -0700
commit55fb29667add625762e33398e8737626d1648a03 (patch)
tree302791d1f08d8bdc497ead16cfb685bcabc9d43f
parentb8175ac13d2a3fc2ebf33a95a959400a1d5d9c56 (diff)
downloadbun-55fb29667add625762e33398e8737626d1648a03.tar.gz
bun-55fb29667add625762e33398e8737626d1648a03.tar.zst
bun-55fb29667add625762e33398e8737626d1648a03.zip
Add JSC.Weak
-rw-r--r--src/bun.js/Weak.zig199
-rw-r--r--src/bun.js/bindings/Weak.cpp94
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