From 80aff249510764e51d2e629527e138dbfa84e166 Mon Sep 17 00:00:00 2001 From: chloe caruso Date: Wed, 23 Apr 2025 17:52:41 -0700 Subject: [PATCH] fix: require.extensions uses Strong instead of being clever (#19231) --- build.zig | 3 +- package.json | 2 +- src/bake/DevServer.zig | 75 ++-------- src/bake/FrameworkRouter.zig | 6 +- src/bun.js/ModuleLoader.zig | 16 +-- src/bun.js/Strong.zig | 157 +++++++++++++-------- src/bun.js/VirtualMachine.zig | 4 +- src/bun.js/api/JSBundler.zig | 2 +- src/bun.js/api/Timer.zig | 2 +- src/bun.js/api/bun/h2_frame_parser.zig | 16 +-- src/bun.js/api/bun/socket.zig | 10 +- src/bun.js/api/bun/spawn/stdio.zig | 2 +- src/bun.js/api/html_rewriter.zig | 2 +- src/bun.js/api/server.zig | 16 +-- src/bun.js/api/server/NodeHTTPResponse.zig | 2 +- src/bun.js/bindings/AbortSignal.zig | 2 +- src/bun.js/bindings/JSPromise.zig | 4 +- src/bun.js/bindings/JSRef.zig | 8 +- src/bun.js/bindings/ModuleLoader.cpp | 7 +- src/bun.js/bindings/NodeModuleModule.zig | 93 +++--------- src/bun.js/bindings/ResolvedSource.zig | 6 +- src/bun.js/bindings/headers-handwritten.h | 2 +- src/bun.js/jsc/array_buffer.zig | 2 +- src/bun.js/node/node_cluster_binding.zig | 26 ++-- src/bun.js/node/node_crypto_binding.zig | 12 +- src/bun.js/node/node_fs_stat_watcher.zig | 6 +- src/bun.js/node/node_zlib_binding.zig | 4 +- src/bun.js/rare_data.zig | 4 +- src/bun.js/test/jest.zig | 4 +- src/bun.js/webcore/Body.zig | 8 +- src/bun.js/webcore/ByteStream.zig | 2 +- src/bun.js/webcore/FileReader.zig | 2 +- src/bun.js/webcore/ReadableStream.zig | 6 +- src/bun.js/webcore/Request.zig | 4 +- src/bun.js/webcore/fetch.zig | 14 +- src/bun.js/webcore/streams.zig | 2 +- src/deps/uws.zig | 18 +-- src/napi/napi.zig | 8 +- src/shell/Builtin.zig | 2 +- src/shell/interpreter.zig | 2 +- src/sql/postgres.zig | 6 +- 41 files changed, 254 insertions(+), 315 deletions(-) diff --git a/build.zig b/build.zig index 54fddd730d..3659c5936d 100644 --- a/build.zig +++ b/build.zig @@ -199,7 +199,8 @@ pub fn build(b: *Build) !void { const bun_version = b.option([]const u8, "version", "Value of `Bun.version`") orelse "0.0.0"; - b.reference_trace = b.reference_trace orelse 32; + // Lower the default reference trace for incremental + b.reference_trace = b.reference_trace orelse if (b.graph.incremental == true) 8 else 16; const obj_format = b.option(ObjectFormat, "obj_format", "Output file for object files") orelse .obj; diff --git a/package.json b/package.json index d3553805b9..c545d7889c 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ }, "scripts": { "build": "bun run build:debug", - "watch": "bun zig build check --watch -fincremental --prominent-compile-errors", + "watch": "zig build check --watch -fincremental --prominent-compile-errors --global-cache-dir build/debug/zig-check-cache --zig-lib-dir vendor/zig/lib", "bd": "(bun run --silent build:debug &> /tmp/bun.debug.build.log || (cat /tmp/bun.debug.build.log && rm -rf /tmp/bun.debug.build.log && exit 1)) && rm -f /tmp/bun.debug.build.log && ./build/debug/bun-debug", "build:debug": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -B build/debug", "build:valgrind": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_BASELINE=ON -ENABLE_VALGRIND=ON -B build/debug-valgrind", diff --git a/src/bake/DevServer.zig b/src/bake/DevServer.zig index 16204be37c..ac51b31853 100644 --- a/src/bake/DevServer.zig +++ b/src/bake/DevServer.zig @@ -72,8 +72,6 @@ html_router: HTMLRouter, assets: Assets, /// Similar to `assets`, specialized for the additional needs of source mappings. source_maps: SourceMapStore, -// /// Allocations that require a reference count. -// ref_strings: RefString.Store, /// All bundling failures are stored until a file is saved and rebuilt. /// They are stored in the wire format the HMR runtime expects so that /// serialization only happens once. @@ -93,8 +91,8 @@ has_tailwind_plugin_hack: ?bun.StringArrayHashMapUnmanaged(void) = null, // These values are handles to the functions in `hmr-runtime-server.ts`. // For type definitions, see `./bake.private.d.ts` -server_fetch_function_callback: JSC.Strong, -server_register_update_callback: JSC.Strong, +server_fetch_function_callback: JSC.Strong.Optional, +server_register_update_callback: JSC.Strong.Optional, // Watching bun_watcher: *bun.Watcher, @@ -236,13 +234,13 @@ pub const RouteBundle = struct { /// Cached to avoid re-creating the array every request. /// TODO: Invalidated when a layout is added or removed from this route. - cached_module_list: JSC.Strong, + cached_module_list: JSC.Strong.Optional, /// Cached to avoid re-creating the string every request. /// TODO: Invalidated when any client file associated with the route is updated. - cached_client_bundle_url: JSC.Strong, + cached_client_bundle_url: JSC.Strong.Optional, /// Cached to avoid re-creating the array every request. /// Invalidated when the list of CSS files changes. - cached_css_file_array: JSC.Strong, + cached_css_file_array: JSC.Strong.Optional, /// When state == .evaluation_failure, this is populated with the route /// evaluation error mirrored in the dev server hash map @@ -339,7 +337,7 @@ pub const RouteBundle = struct { if (self.client_bundle) |bundle| cost += bundle.memoryCost(); switch (self.data) { .framework => { - // the JSC.Strong children do not support memoryCost. likely not needed + // the JSC.Strong.Optional children do not support memoryCost. likely not needed // .evaluate_failure is not owned }, .html => |*html| { @@ -946,10 +944,10 @@ fn initServerRuntime(dev: *DevServer) void { const fetch_function = interface.get(dev.vm.global, "handleRequest") catch null orelse @panic("Internal assertion failure: expected interface from HMR runtime to contain handleRequest"); bun.assert(fetch_function.isCallable()); - dev.server_fetch_function_callback = JSC.Strong.create(fetch_function, dev.vm.global); + dev.server_fetch_function_callback = .create(fetch_function, dev.vm.global); const register_update = interface.get(dev.vm.global, "registerUpdate") catch null orelse @panic("Internal assertion failure: expected interface from HMR runtime to contain registerUpdate"); - dev.server_register_update_callback = JSC.Strong.create(register_update, dev.vm.global); + dev.server_register_update_callback = .create(register_update, dev.vm.global); fetch_function.ensureStillAlive(); register_update.ensureStillAlive(); @@ -1390,7 +1388,7 @@ fn onFrameworkRequestWithBundle( const name = dev.server_graph.bundled_files.keys()[fromOpaqueFileId(.server, router_type.server_file).get()]; const str = bun.String.createUTF8ForJS(dev.vm.global, dev.relativePath(name)); dev.releaseRelativePathBuf(); - router_type.server_file_string = JSC.Strong.create(str, dev.vm.global); + router_type.server_file_string = .create(str, dev.vm.global); break :str str; }, // routeModules @@ -1418,7 +1416,7 @@ fn onFrameworkRequestWithBundle( } route = dev.router.routePtr(route.parent.unwrap() orelse break); } - bundle.cached_module_list = JSC.Strong.create(arr, global); + bundle.cached_module_list = .create(arr, global); break :arr arr; }, // clientId @@ -1431,13 +1429,13 @@ fn onFrameworkRequestWithBundle( }) catch bun.outOfMemory(); defer str.deref(); const js = str.toJS(dev.vm.global); - bundle.cached_client_bundle_url = JSC.Strong.create(js, dev.vm.global); + bundle.cached_client_bundle_url = .create(js, dev.vm.global); break :str js; }, // styles bundle.cached_css_file_array.get() orelse arr: { const js = dev.generateCssJSArray(route_bundle) catch bun.outOfMemory(); - bundle.cached_css_file_array = JSC.Strong.create(js, dev.vm.global); + bundle.cached_css_file_array = .create(js, dev.vm.global); break :arr js; }, }, @@ -7125,55 +7123,6 @@ pub const SourceMapStore = struct { } }; -// NOTE: not used but keeping around in case a use case is found soon -// /// Instead of a pointer to `struct { data: []const u8, ref_count: u32 }`, all -// /// reference counts are in a shared map. This is used by strings shared between -// /// source maps and the incremental graph. Not thread-safe. -// /// -// /// Transfer from default allocator to RefString with `dev.ref_strings.register(slice)` -// /// -// /// Prefer `CowString` (maybe allocated or borrowed) or `[]const u8` (known lifetime) over this structure. -// const RefString = struct { -// /// Allocated by `dev.allocator`, free with `.unref()` -// data: []const u8, - -// pub fn deref(str: RefString, store: *Store) void { -// const index = store.strings.getIndex(str.ptr) orelse unreachable; -// const slice = store.strings.entries.slice(); -// const ref_count = &slice.items(.value)[index]; -// if (ref_count.* == 1) { -// store.strings.swapRemoveAt(index); -// dev.allocator.free(str.data); -// } else { -// ref_count.* -= 1; -// } -// } - -// pub fn dupeRef(str: RefString, store: *Store) RefString { -// const ref_count = store.strings.getPtr(str.ptr) orelse unreachable; -// ref_count.* += 1; -// return str; -// } - -// pub const Store = struct { -// /// Key -> Data. Value -> Reference count -// strings: AutoArrayHashMapUnmanaged([*]u8, u32), - -// pub const empty: Store = .{ .strings = .empty }; - -// /// `data` must be owned by `dev.allocator` -// pub fn register(store: *Store, data: []u8) !RefString { -// const gop = try store.strings.getOrPut(dev.allocator, data.ptr); -// if (gop.found_existing) { -// gop.value_ptr.* += 1; -// } else { -// gop.value_ptr = 1; -// } -// return .{ .data = data }; -// } -// }; -// }; - pub fn onPluginsResolved(dev: *DevServer, plugins: ?*Plugin) !void { dev.bundler_options.plugin = plugins; dev.plugin_state = .loaded; diff --git a/src/bake/FrameworkRouter.zig b/src/bake/FrameworkRouter.zig index 7a43987536..8a9fada1e2 100644 --- a/src/bake/FrameworkRouter.zig +++ b/src/bake/FrameworkRouter.zig @@ -91,7 +91,7 @@ pub const Type = struct { /// `FrameworkRouter` itself does not use this value. server_file: OpaqueFileId, /// `FrameworkRouter` itself does not use this value. - server_file_string: JSC.Strong, + server_file_string: JSC.Strong.Optional, pub fn rootRouteIndex(type_index: Index) Route.Index { return Route.Index.init(type_index.get()); @@ -412,7 +412,7 @@ pub const Style = union(enum) { nextjs_pages, nextjs_app_ui, nextjs_app_routes, - javascript_defined: JSC.Strong, + javascript_defined: JSC.Strong.Optional, pub const map = bun.ComptimeStringMap(Style, .{ .{ "nextjs-pages", .nextjs_pages }, @@ -431,7 +431,7 @@ pub const Style = union(enum) { return style; } } else if (value.isCallable()) { - return .{ .javascript_defined = JSC.Strong.create(value, global) }; + return .{ .javascript_defined = .create(value, global) }; } return global.throwInvalidArguments(error_message, .{}); diff --git a/src/bun.js/ModuleLoader.zig b/src/bun.js/ModuleLoader.zig index 76f13be4d9..6218ec12d3 100644 --- a/src/bun.js/ModuleLoader.zig +++ b/src/bun.js/ModuleLoader.zig @@ -69,7 +69,7 @@ pub fn resolveEmbeddedFile(vm: *VirtualMachine, input_path: []const u8, extname: pub const AsyncModule = struct { // This is all the state used by the printer to print the module parse_result: ParseResult, - promise: JSC.Strong = .empty, + promise: JSC.Strong.Optional = .empty, path: Fs.Path, specifier: string = "", referrer: string = "", @@ -376,7 +376,7 @@ pub const AsyncModule = struct { // var stmt_blocks = js_ast.Stmt.Data.toOwnedSlice(); // var expr_blocks = js_ast.Expr.Data.toOwnedSlice(); const this_promise = JSValue.createInternalPromise(globalObject); - const promise = JSC.Strong.create(this_promise, globalObject); + const promise = JSC.Strong.Optional.create(this_promise, globalObject); var buf = bun.StringBuilder{}; buf.count(opts.referrer); @@ -1625,13 +1625,13 @@ pub export fn Bun__transpileFile( .loader => |loader| { lr.loader = loader; }, - .custom => |index| { + .custom => |strong| { ret.* = JSC.ErrorableResolvedSource.ok(ResolvedSource{ .allocator = null, .source_code = bun.String.empty, .specifier = .empty, .source_url = .empty, - .cjs_custom_extension_index = index, + .cjs_custom_extension_index = strong.get(), .tag = .common_js_custom_extension, }); return null; @@ -1750,13 +1750,13 @@ pub export fn Bun__transpileFile( if (node_module_module.findLongestRegisteredExtension(jsc_vm, lr.path.text)) |entry| { switch (entry) { .loader => |loader| break :loader loader, - .custom => |index| { + .custom => |strong| { ret.* = JSC.ErrorableResolvedSource.ok(ResolvedSource{ .allocator = null, .source_code = bun.String.empty, .specifier = .empty, .source_url = .empty, - .cjs_custom_extension_index = index, + .cjs_custom_extension_index = strong.get(), .tag = .common_js_custom_extension, }); return null; @@ -2191,7 +2191,7 @@ pub const RuntimeTranspilerStore = struct { .vm = vm, .log = logger.Log.init(bun.default_allocator), .loader = loader, - .promise = JSC.Strong.create(JSValue.fromCell(promise), globalObject), + .promise = .create(JSValue.fromCell(promise), globalObject), .poll_ref = .{}, .fetcher = TranspilerJob.Fetcher{ .file = {}, @@ -2209,7 +2209,7 @@ pub const RuntimeTranspilerStore = struct { non_threadsafe_input_specifier: String, non_threadsafe_referrer: String, loader: options.Loader, - promise: JSC.Strong = .empty, + promise: JSC.Strong.Optional = .empty, vm: *VirtualMachine, globalThis: *JSGlobalObject, fetcher: Fetcher, diff --git a/src/bun.js/Strong.zig b/src/bun.js/Strong.zig index 8912f892ee..b908dc528b 100644 --- a/src/bun.js/Strong.zig +++ b/src/bun.js/Strong.zig @@ -1,83 +1,122 @@ //! Holds a strong reference to a JS value, protecting it from garbage -//! collection. When not holding a value, the strong may still be allocated. +//! collection. This type implies there is always a valid value held. +//! For a strong that may be empty (to reuse allocation), use `Strong.Optional`. const Strong = @This(); -impl: ?*Impl, - -pub const empty: Strong = .{ .impl = null }; +impl: *Impl, /// Hold a strong reference to a JavaScript value. Release with `deinit` or `clear` -pub fn create(value: JSC.JSValue, globalThis: *JSC.JSGlobalObject) Strong { - return if (value != .zero) - .{ .impl = .init(globalThis, value) } - else - .empty; +pub fn create(value: JSC.JSValue, global: *JSC.JSGlobalObject) Strong { + if (bun.Environment.allow_assert) bun.assert(value != .zero); + return .{ .impl = .init(global, value) }; } -/// Frees memory for the underlying Strong reference. +/// Release the strong reference. pub fn deinit(strong: *Strong) void { - const ref: *Impl = strong.impl orelse return; - strong.* = .empty; - ref.deinit(); + strong.impl.deinit(); + if (bun.Environment.isDebug) + strong.* = undefined; } -/// Clears the value, but does not de-allocate the Strong reference. -pub fn clearWithoutDeallocation(strong: *Strong) void { - const ref: *Impl = strong.impl orelse return; - ref.clear(); -} - -pub fn call(this: *Strong, global: *JSC.JSGlobalObject, args: []const JSC.JSValue) JSC.JSValue { - const function = this.trySwap() orelse return .zero; - return function.call(global, args); -} - -pub fn get(this: *const Strong) ?JSC.JSValue { - const impl = this.impl orelse return null; - const result = impl.get(); - if (result == .zero) { - return null; - } +pub fn get(strong: *const Strong) JSC.JSValue { + const result = strong.impl.get(); + if (bun.Environment.allow_assert) bun.assert(result != .zero); return result; } -pub fn swap(strong: *Strong) JSC.JSValue { - const impl = strong.impl orelse return .zero; - const result = impl.get(); - if (result == .zero) { - return .zero; - } - impl.clear(); +/// Set a new value for the strong reference. +pub fn set(strong: *Strong, global: *JSC.JSGlobalObject, new_value: JSC.JSValue) void { + if (bun.Environment.allow_assert) bun.assert(new_value != .zero); + strong.impl.set(global, new_value); +} + +/// Swap a new value for the strong reference. +pub fn swap(strong: *Strong, global: *JSC.JSGlobalObject, new_value: JSC.JSValue) JSC.JSValue { + const result = strong.impl.get(); + strong.set(global, new_value); return result; } -pub fn has(this: *const Strong) bool { - var ref = this.impl orelse return false; - return ref.get() != .zero; -} +/// Holds a strong reference to a JS value, protecting it from garbage +/// collection. When not holding a value, the strong may still be allocated. +pub const Optional = struct { + impl: ?*Impl, -pub fn trySwap(this: *Strong) ?JSC.JSValue { - const result = this.swap(); - if (result == .zero) { - return null; + pub const empty: Optional = .{ .impl = null }; + + /// Hold a strong reference to a JavaScript value. Release with `deinit` or `clear` + pub fn create(value: JSC.JSValue, global: *JSC.JSGlobalObject) Optional { + return if (value != .zero) + .{ .impl = .init(global, value) } + else + .empty; } - return result; -} + /// Frees memory for the underlying Strong reference. + pub fn deinit(strong: *Optional) void { + const ref: *Impl = strong.impl orelse return; + strong.* = .empty; + ref.deinit(); + } -pub fn set(strong: *Strong, globalThis: *JSC.JSGlobalObject, value: JSC.JSValue) void { - const ref: *Impl = strong.impl orelse { - if (value == .zero) return; - strong.impl = Impl.init(globalThis, value); - return; - }; - ref.set(globalThis, value); -} + /// Clears the value, but does not de-allocate the Strong reference. + pub fn clearWithoutDeallocation(strong: *Optional) void { + const ref: *Impl = strong.impl orelse return; + ref.clear(); + } + + pub fn call(this: *Optional, global: *JSC.JSGlobalObject, args: []const JSC.JSValue) JSC.JSValue { + const function = this.trySwap() orelse return .zero; + return function.call(global, args); + } + + pub fn get(this: *const Optional) ?JSC.JSValue { + const impl = this.impl orelse return null; + const result = impl.get(); + if (result == .zero) { + return null; + } + return result; + } + + pub fn swap(strong: *Optional) JSC.JSValue { + const impl = strong.impl orelse return .zero; + const result = impl.get(); + if (result == .zero) { + return .zero; + } + impl.clear(); + return result; + } + + pub fn has(this: *const Optional) bool { + var ref = this.impl orelse return false; + return ref.get() != .zero; + } + + pub fn trySwap(this: *Optional) ?JSC.JSValue { + const result = this.swap(); + if (result == .zero) { + return null; + } + + return result; + } + + pub fn set(strong: *Optional, global: *JSC.JSGlobalObject, value: JSC.JSValue) void { + const ref: *Impl = strong.impl orelse { + if (value == .zero) return; + strong.impl = Impl.init(global, value); + return; + }; + ref.set(global, value); + } +}; const Impl = opaque { - pub fn init(globalThis: *JSC.JSGlobalObject, value: JSC.JSValue) *Impl { + pub fn init(global: *JSC.JSGlobalObject, value: JSC.JSValue) *Impl { JSC.markBinding(@src()); - return Bun__StrongRef__new(globalThis, value); + return Bun__StrongRef__new(global, value); } pub fn get(this: *Impl) JSC.JSValue { @@ -85,9 +124,9 @@ const Impl = opaque { return Bun__StrongRef__get(this); } - pub fn set(this: *Impl, globalThis: *JSC.JSGlobalObject, value: JSC.JSValue) void { + pub fn set(this: *Impl, global: *JSC.JSGlobalObject, value: JSC.JSValue) void { JSC.markBinding(@src()); - Bun__StrongRef__set(this, globalThis, value); + Bun__StrongRef__set(this, global, value); } pub fn clear(this: *Impl) void { diff --git a/src/bun.js/VirtualMachine.zig b/src/bun.js/VirtualMachine.zig index aa4982d2bb..7a69b3452e 100644 --- a/src/bun.js/VirtualMachine.zig +++ b/src/bun.js/VirtualMachine.zig @@ -126,7 +126,7 @@ rare_data: ?*JSC.RareData = null, is_us_loop_entered: bool = false, pending_internal_promise: ?*JSInternalPromise = null, entry_point_result: struct { - value: JSC.Strong = .empty, + value: JSC.Strong.Optional = .empty, cjs_set_value: bool = false, } = .{}, @@ -179,7 +179,7 @@ destruct_main_thread_on_exit: bool, /// /// `.keys() == transpiler.resolver.opts.extra_cjs_extensions`, so /// mutations in this map must update the resolver. -commonjs_custom_extensions: bun.StringArrayHashMapUnmanaged(node_module_module.CustomLoader.Packed) = .empty, +commonjs_custom_extensions: bun.StringArrayHashMapUnmanaged(node_module_module.CustomLoader) = .empty, /// Incremented when the `require.extensions` for a built-in extension is mutated. /// An example is mutating `require.extensions['.js']` to intercept all '.js' files. /// The value is decremented when defaults are restored. diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig index 201bbbb803..ffd3f69d59 100644 --- a/src/bun.js/api/JSBundler.zig +++ b/src/bun.js/api/JSBundler.zig @@ -1096,7 +1096,7 @@ pub const BuildArtifact = struct { path: []const u8 = "", hash: u64 = std.math.maxInt(u64), output_kind: OutputKind, - sourcemap: JSC.Strong = .empty, + sourcemap: JSC.Strong.Optional = .empty, pub const OutputKind = enum { chunk, diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index c589fa4883..f1357fc5e2 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -743,7 +743,7 @@ const TimerObjectInternals = struct { /// Identifier for this timer that is exposed to JavaScript (by `+timer`) id: i32 = -1, interval: u31 = 0, - strong_this: JSC.Strong = .empty, + strong_this: JSC.Strong.Optional = .empty, flags: Flags = .{}, const Flags = packed struct(u32) { diff --git a/src/bun.js/api/bun/h2_frame_parser.zig b/src/bun.js/api/bun/h2_frame_parser.zig index ced78657ab..0b6874dda5 100644 --- a/src/bun.js/api/bun/h2_frame_parser.zig +++ b/src/bun.js/api/bun/h2_frame_parser.zig @@ -536,7 +536,7 @@ const Handlers = struct { vm: *JSC.VirtualMachine, globalObject: *JSC.JSGlobalObject, - strong_ctx: JSC.Strong = .empty, + strong_ctx: JSC.Strong.Optional = .empty, pub fn callEventHandler(this: *Handlers, comptime event: @Type(.enum_literal), thisValue: JSValue, data: []const JSValue) bool { const callback = @field(this, @tagName(event)); @@ -672,7 +672,7 @@ pub const H2FrameParser = struct { const H2FrameParserHiveAllocator = bun.HiveArray(H2FrameParser, 256).Fallback; pub threadlocal var pool: if (ENABLE_ALLOCATOR_POOL) ?*H2FrameParserHiveAllocator else u0 = if (ENABLE_ALLOCATOR_POOL) null else 0; - strong_ctx: JSC.Strong = .empty, + strong_ctx: JSC.Strong.Optional = .empty, globalThis: *JSC.JSGlobalObject, allocator: Allocator, handlers: Handlers, @@ -753,7 +753,7 @@ pub const H2FrameParser = struct { HALF_CLOSED_REMOTE = 6, CLOSED = 7, } = .IDLE, - jsContext: JSC.Strong = .empty, + jsContext: JSC.Strong.Optional = .empty, waitForTrailers: bool = false, closeAfterDrain: bool = false, endAfterHeaders: bool = false, @@ -866,7 +866,7 @@ pub const H2FrameParser = struct { end_stream: bool = false, // end_stream flag len: u32 = 0, // actually payload size buffer: []u8 = "", // allocated buffer if len > 0 - callback: JSC.Strong = .empty, // JSCallback for done + callback: JSC.Strong.Optional = .empty, // JSCallback for done pub fn deinit(this: *PendingFrame, allocator: Allocator) void { if (this.buffer.len > 0) { @@ -984,7 +984,7 @@ pub const H2FrameParser = struct { client.dispatchWriteCallback(old_callback); last_frame.callback.deinit(); } - last_frame.callback = JSC.Strong.create(callback, globalThis); + last_frame.callback = .create(callback, globalThis); return; } if (last_frame.len == 0) { @@ -1012,7 +1012,7 @@ pub const H2FrameParser = struct { client.dispatchWriteCallback(old_callback); last_frame.callback.deinit(); } - last_frame.callback = JSC.Strong.create(callback, globalThis); + last_frame.callback = .create(callback, globalThis); return; } // we keep the old callback because the new will be part of another frame @@ -1026,7 +1026,7 @@ pub const H2FrameParser = struct { .len = @intCast(bytes.len), // we need to clone this data to send it later .buffer = if (bytes.len == 0) "" else client.allocator.alloc(u8, MAX_PAYLOAD_SIZE_WITHOUT_FRAME) catch bun.outOfMemory(), - .callback = if (callback.isCallable()) JSC.Strong.create(callback, globalThis) else .empty, + .callback = if (callback.isCallable()) JSC.Strong.Optional.create(callback, globalThis) else .empty, }; if (bytes.len > 0) { @memcpy(frame.buffer[0..bytes.len], bytes); @@ -1067,7 +1067,7 @@ pub const H2FrameParser = struct { pub fn setContext(this: *Stream, value: JSValue, globalObject: *JSC.JSGlobalObject) void { var context = this.jsContext; defer context.deinit(); - this.jsContext = JSC.Strong.create(value, globalObject); + this.jsContext = .create(value, globalObject); } pub fn getIdentifier(this: *const Stream) JSValue { diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index e43d68b560..d7f5a0e1f7 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -130,7 +130,7 @@ const Handlers = struct { globalObject: *JSC.JSGlobalObject, active_connections: u32 = 0, is_server: bool = false, - promise: JSC.Strong = .empty, + promise: JSC.Strong.Optional = .empty, protection_count: bun.DebugOnly(u32) = if (Environment.isDebug) 0, @@ -522,8 +522,8 @@ pub const Listener = struct { ssl: bool = false, protos: ?[]const u8 = null, - strong_data: JSC.Strong = .empty, - strong_self: JSC.Strong = .empty, + strong_data: JSC.Strong.Optional = .empty, + strong_self: JSC.Strong.Optional = .empty, pub const js = JSC.Codegen.JSListener; pub const toJS = js.toJS; @@ -664,7 +664,7 @@ pub const Listener = struct { socket.handlers.protect(); if (socket_config.default_data != .zero) { - socket.strong_data = JSC.Strong.create(socket_config.default_data, globalObject); + socket.strong_data = .create(socket_config.default_data, globalObject); } var this: *Listener = handlers.vm.allocator.create(Listener) catch bun.outOfMemory(); @@ -825,7 +825,7 @@ pub const Listener = struct { socket.handlers.protect(); if (socket_config.default_data != .zero) { - socket.strong_data = JSC.Strong.create(socket_config.default_data, globalObject); + socket.strong_data = .create(socket_config.default_data, globalObject); } if (ssl) |ssl_config| { diff --git a/src/bun.js/api/bun/spawn/stdio.zig b/src/bun.js/api/bun/spawn/stdio.zig index 33d3382345..ac302a9343 100644 --- a/src/bun.js/api/bun/spawn/stdio.zig +++ b/src/bun.js/api/bun/spawn/stdio.zig @@ -391,7 +391,7 @@ pub const Stdio = union(enum) { out_stdio.* = .{ .array_buffer = JSC.ArrayBuffer.Strong{ .array_buffer = array_buffer, - .held = JSC.Strong.create(array_buffer.value, globalThis), + .held = .create(array_buffer.value, globalThis), }, }; return; diff --git a/src/bun.js/api/html_rewriter.zig b/src/bun.js/api/html_rewriter.zig index 67e9b4f98b..d0a3398e3a 100644 --- a/src/bun.js/api/html_rewriter.zig +++ b/src/bun.js/api/html_rewriter.zig @@ -401,7 +401,7 @@ pub const HTMLRewriter = struct { rewriter: ?*LOLHTML.HTMLRewriter = null, context: *LOLHTMLContext, response: *Response, - response_value: JSC.Strong = .empty, + response_value: JSC.Strong.Optional = .empty, bodyValueBufferer: ?JSC.WebCore.Body.ValueBufferer = null, tmp_sync_error: ?*JSC.JSValue = null, diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 489e7b7686..2be8456b06 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -328,7 +328,7 @@ pub const ServerInitContext = struct { const UserRouteBuilder = struct { route: RouteDeclaration, - callback: JSC.Strong = .empty, + callback: JSC.Strong.Optional = .empty, // We need to be able to apply the route to multiple Apps even when there is only one RouteList. pub const RouteDeclaration = struct { @@ -1402,7 +1402,7 @@ pub const ServerConfig = struct { .path = bun.default_allocator.dupeZ(u8, path) catch bun.outOfMemory(), .method = .any, }, - .callback = JSC.Strong.create(value.withAsyncContextIfNeeded(global), global), + .callback = .create(value.withAsyncContextIfNeeded(global), global), }) catch bun.outOfMemory(); bun.default_allocator.free(path); continue; @@ -1433,7 +1433,7 @@ pub const ServerConfig = struct { .path = bun.default_allocator.dupeZ(u8, path) catch bun.outOfMemory(), .method = .{ .specific = method }, }, - .callback = JSC.Strong.create(function.withAsyncContextIfNeeded(global), global), + .callback = .create(function.withAsyncContextIfNeeded(global), global), }) catch bun.outOfMemory(); } } @@ -5177,7 +5177,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d pub const App = uws.NewApp(ssl_enabled); listener: ?*App.ListenSocket = null, - js_value: JSC.Strong = .empty, + js_value: JSC.Strong.Optional = .empty, /// Potentially null before listen() is called, and once .destroy() is called. app: ?*App = null, vm: *JSC.VirtualMachine, @@ -6106,7 +6106,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d .globalObject = this.globalThis, // Duplicate the Strong handle so that we can hold two independent strong references to it. .promise = .{ - .strong = JSC.Strong.create(this.all_closed_promise.value(), this.globalThis), + .strong = .create(this.all_closed_promise.value(), this.globalThis), }, .tracker = JSC.Debugger.AsyncTaskTracker.init(vm), }); @@ -6489,7 +6489,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d success: void, pending: JSC.JSValue, }; - var strong_promise: JSC.Strong = .empty; + var strong_promise: JSC.Strong.Optional = .empty; var needs_to_drain = true; defer { @@ -6760,7 +6760,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d prepared.ctx.toAsync(req, prepared.request_object); return .{ - .js_request = JSC.Strong.create(prepared.js_request, global), + .js_request = .create(prepared.js_request, global), .request = prepared.request_object, .ctx = AnyRequestContext.init(prepared.ctx), .response = uws.AnyResponse.init(resp), @@ -7342,7 +7342,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d } pub const SavedRequest = struct { - js_request: JSC.Strong, + js_request: JSC.Strong.Optional, request: *Request, ctx: AnyRequestContext, response: uws.AnyResponse, diff --git a/src/bun.js/api/server/NodeHTTPResponse.zig b/src/bun.js/api/server/NodeHTTPResponse.zig index 0dfd98a7e9..5505ef8611 100644 --- a/src/bun.js/api/server/NodeHTTPResponse.zig +++ b/src/bun.js/api/server/NodeHTTPResponse.zig @@ -20,7 +20,7 @@ js_ref: JSC.Ref = .{}, body_read_state: BodyReadState = .none, body_read_ref: JSC.Ref = .{}, -promise: JSC.Strong = .empty, +promise: JSC.Strong.Optional = .empty, server: AnyServer, /// When you call pause() on the node:http IncomingMessage diff --git a/src/bun.js/bindings/AbortSignal.zig b/src/bun.js/bindings/AbortSignal.zig index 693cff1fb4..9ecc321c3f 100644 --- a/src/bun.js/bindings/AbortSignal.zig +++ b/src/bun.js/bindings/AbortSignal.zig @@ -89,7 +89,7 @@ pub const AbortSignal = opaque { pub fn toBodyValueError(this: AbortReason, globalObject: *JSC.JSGlobalObject) JSC.WebCore.Body.Value.ValueError { return switch (this) { .common => |reason| .{ .AbortReason = reason }, - .js => |value| .{ .JSValue = JSC.Strong.create(value, globalObject) }, + .js => |value| .{ .JSValue = .create(value, globalObject) }, }; } diff --git a/src/bun.js/bindings/JSPromise.zig b/src/bun.js/bindings/JSPromise.zig index c6b24216ec..58874d2564 100644 --- a/src/bun.js/bindings/JSPromise.zig +++ b/src/bun.js/bindings/JSPromise.zig @@ -107,7 +107,7 @@ pub const JSPromise = opaque { } pub const Strong = struct { - strong: JSC.Strong = .empty, + strong: JSC.Strong.Optional = .empty, pub const empty: Strong = .{ .strong = .empty }; @@ -140,7 +140,7 @@ pub const JSPromise = opaque { pub fn init(globalThis: *JSC.JSGlobalObject) Strong { return Strong{ - .strong = JSC.Strong.create( + .strong = .create( JSC.JSPromise.create(globalThis).asValue(globalThis), globalThis, ), diff --git a/src/bun.js/bindings/JSRef.zig b/src/bun.js/bindings/JSRef.zig index 0e49d74fdd..6697f3e8e9 100644 --- a/src/bun.js/bindings/JSRef.zig +++ b/src/bun.js/bindings/JSRef.zig @@ -1,6 +1,6 @@ pub const JSRef = union(enum) { weak: JSC.JSValue, - strong: JSC.Strong, + strong: JSC.Strong.Optional, finalized: void, pub fn initWeak(value: JSC.JSValue) @This() { @@ -8,7 +8,7 @@ pub const JSRef = union(enum) { } pub fn initStrong(value: JSC.JSValue, globalThis: *JSC.JSGlobalObject) @This() { - return .{ .strong = JSC.Strong.create(value, globalThis) }; + return .{ .strong = .create(value, globalThis) }; } pub fn empty() @This() { @@ -48,14 +48,14 @@ pub const JSRef = union(enum) { this.strong.set(globalThis, value); return; } - this.* = .{ .strong = JSC.Strong.create(value, globalThis) }; + this.* = .{ .strong = .create(value, globalThis) }; } pub fn upgrade(this: *@This(), globalThis: *JSC.JSGlobalObject) void { switch (this.*) { .weak => { bun.assert(this.weak != .zero); - this.* = .{ .strong = JSC.Strong.create(this.weak, globalThis) }; + this.* = .{ .strong = .create(this.weak, globalThis) }; }, .strong => {}, .finalized => { diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp index face386f1c..4cdb70fcc2 100644 --- a/src/bun.js/bindings/ModuleLoader.cpp +++ b/src/bun.js/bindings/ModuleLoader.cpp @@ -575,13 +575,10 @@ void evaluateCommonJSCustomExtension( JSCommonJSModule* target, String filename, JSValue filenameValue, - uint32_t extensionIndex) + JSValue extension) { auto& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); - Bun::JSCommonJSExtensions* extensions = globalObject->lazyRequireExtensionsObject(); - JSValue extension = extensions->m_registeredFunctions[extensionIndex].get(); - if (!extension) { throwTypeError(globalObject, scope, makeString("require.extension is not a function"_s)); return; @@ -793,7 +790,7 @@ JSValue fetchCommonJSModuleNonBuiltin( JSC::throwException(globalObject, scope, JSC::createSyntaxError(globalObject, "Recursive extension. This is a bug in Bun"_s)); RELEASE_AND_RETURN(scope, {}); } - evaluateCommonJSCustomExtension(globalObject, target, specifierWtfString, specifierValue, res->result.value.cjsCustomExtensionIndex); + evaluateCommonJSCustomExtension(globalObject, target, specifierWtfString, specifierValue, JSC::JSValue::decode(res->result.value.cjsCustomExtension)); RETURN_IF_EXCEPTION(scope, {}); RELEASE_AND_RETURN(scope, target); } diff --git a/src/bun.js/bindings/NodeModuleModule.zig b/src/bun.js/bindings/NodeModuleModule.zig index aae75cdb0d..2b903d806d 100644 --- a/src/bun.js/bindings/NodeModuleModule.zig +++ b/src/bun.js/bindings/NodeModuleModule.zig @@ -84,44 +84,7 @@ pub fn _stat(path: []const u8) i32 { pub const CustomLoader = union(enum) { loader: bun.options.Loader, - /// Retrieve via WriteBarrier in `global->lazyRequireExtensionsObject().get(index)` - custom: u32, - - pub const Packed = enum(u32) { - const loader_start: u32 = std.math.maxInt(u32) - 4; - js = loader_start, - json = loader_start + 1, - napi = loader_start + 2, - ts = loader_start + 3, - /// custom - _, - - pub fn pack(loader: CustomLoader) Packed { - return switch (loader) { - .loader => |basic| switch (basic) { - .js => .js, - .json => .json, - .napi => .napi, - .ts => .ts, - else => brk: { - bun.debugAssert(false); - break :brk .js; - }, - }, - .custom => |custom| @enumFromInt(custom), - }; - } - - pub fn unpack(self: Packed) CustomLoader { - return switch (self) { - .js => .{ .loader = .js }, - .json => .{ .loader = .json }, - .napi => .{ .loader = .napi }, - .ts => .{ .loader = .ts }, - _ => .{ .custom = @intFromEnum(self) }, - }; - } - }; + custom: JSC.Strong, }; extern fn JSCommonJSExtensions__appendFunction(global: *JSC.JSGlobalObject, value: JSC.JSValue) u32; @@ -148,58 +111,46 @@ fn onRequireExtensionModify(global: *JSC.JSGlobalObject, str: []const u8, kind: const gop = try list.getOrPut(bun.default_allocator, str); if (!gop.found_existing) { const dupe = try bun.default_allocator.dupe(u8, str); - errdefer bun.default_allocator.free(dupe); gop.key_ptr.* = dupe; if (is_built_in) { vm.has_mutated_built_in_extensions += 1; } - gop.value_ptr.* = .pack(switch (loader) { + gop.value_ptr.* = switch (loader) { .loader => loader, .custom => .{ - .custom = JSCommonJSExtensions__appendFunction(global, value), + .custom = .create(value, global), }, - }); + }; } else { - const existing = gop.value_ptr.*.unpack(); - if (existing == .custom and loader != .custom) { - swapRemoveExtension(vm, existing.custom); - } - gop.value_ptr.* = .pack(switch (loader) { - .loader => loader, - .custom => .{ - .custom = if (existing == .custom) new: { - JSCommonJSExtensions__setFunction(global, existing.custom, value); - break :new existing.custom; - } else JSCommonJSExtensions__appendFunction(global, value), + switch (loader) { + .loader => { + switch (gop.value_ptr.*) { + .loader => {}, + .custom => |*strong| strong.deinit(), + } + gop.value_ptr.* = loader; }, - }); + .custom => switch (gop.value_ptr.*) { + .loader => gop.value_ptr.* = .{ .custom = .create(value, global) }, + .custom => |*strong| strong.set(global, value), + }, + } } } else if (list.fetchSwapRemove(str)) |prev| { bun.default_allocator.free(prev.key); if (is_built_in) { vm.has_mutated_built_in_extensions -= 1; } - switch (prev.value.unpack()) { + switch (prev.value) { .loader => {}, - .custom => |index| swapRemoveExtension(vm, index), + .custom => |strong| { + var mut = strong; + mut.deinit(); + }, } } } -fn swapRemoveExtension(vm: *JSC.VirtualMachine, index: u32) void { - const last_index = JSCommonJSExtensions__swapRemove(vm.global, index); - if (last_index == index) return; - // Find and rewrite the last index to the new index. - // Since packed structs are sugar over the backing int, this code can use - // the simd path in the standard library search. - const find: u32 = @intFromEnum(CustomLoader.Packed.pack(.{ .custom = last_index })); - const values = vm.commonjs_custom_extensions.values(); - const values_reinterpret = bun.reinterpretSlice(u32, values); - const i = std.mem.indexOfScalar(u32, values_reinterpret, find) orelse - return bun.debugAssert(false); - values[i] = .pack(.{ .custom = last_index }); -} - pub fn findLongestRegisteredExtension(vm: *JSC.VirtualMachine, filename: []const u8) ?CustomLoader { const basename = std.fs.path.basename(filename); var next: usize = 0; @@ -208,7 +159,7 @@ pub fn findLongestRegisteredExtension(vm: *JSC.VirtualMachine, filename: []const if (i == 0) continue; const ext = basename[i..]; if (vm.commonjs_custom_extensions.get(ext)) |value| { - return value.unpack(); + return value; } } return null; diff --git a/src/bun.js/bindings/ResolvedSource.zig b/src/bun.js/bindings/ResolvedSource.zig index d3cdf92d1b..85a57d264b 100644 --- a/src/bun.js/bindings/ResolvedSource.zig +++ b/src/bun.js/bindings/ResolvedSource.zig @@ -14,8 +14,10 @@ pub const ResolvedSource = extern struct { is_commonjs_module: bool = false, /// When .tag is .common_js_custom_extension, this is special-cased to hold - /// the index of the extension, since the module is stored in a WriteBarrier. - cjs_custom_extension_index: u32 = 0, + /// the JSFunction extension. It is kept alive by + /// - This structure is stored on the stack + /// - There is a JSC::Strong reference to it + cjs_custom_extension_index: JSValue = .zero, allocator: ?*anyopaque = null, diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h index 9106a6c17e..b568fab6be 100644 --- a/src/bun.js/bindings/headers-handwritten.h +++ b/src/bun.js/bindings/headers-handwritten.h @@ -106,7 +106,7 @@ typedef struct ResolvedSource { BunString source_code; BunString source_url; bool isCommonJSModule; - uint32_t cjsCustomExtensionIndex; + JSC::EncodedJSValue cjsCustomExtension; void* allocator; JSC::EncodedJSValue jsvalue_for_export; uint32_t tag; diff --git a/src/bun.js/jsc/array_buffer.zig b/src/bun.js/jsc/array_buffer.zig index 7be8abebee..8904402659 100644 --- a/src/bun.js/jsc/array_buffer.zig +++ b/src/bun.js/jsc/array_buffer.zig @@ -116,7 +116,7 @@ pub const ArrayBuffer = extern struct { pub const Strong = struct { array_buffer: ArrayBuffer, - held: JSC.Strong = .empty, + held: JSC.Strong.Optional = .empty, pub fn clear(this: *ArrayBuffer.Strong) void { var ref: *bun.api.napi.Ref = this.ref orelse return; diff --git a/src/bun.js/node/node_cluster_binding.zig b/src/bun.js/node/node_cluster_binding.zig index ae6155b810..27f259661f 100644 --- a/src/bun.js/node/node_cluster_binding.zig +++ b/src/bun.js/node/node_cluster_binding.zig @@ -1,5 +1,5 @@ // Most of this code should be rewritten. -// - Usage of JSC.Strong here is likely to cause memory leaks. +// - Usage of JSC.Strong.Optional here is likely to cause memory leaks. // - These sequence numbers and ACKs shouldn't exist from JavaScript's perspective // at all. It should happen in the protocol before it reaches JS. // - We should not be creating JSFunction's in process.nextTick. @@ -42,7 +42,7 @@ pub fn sendHelperChild(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFram if (callback.isFunction()) { // TODO: remove this strong. This is expensive and would be an easy way to create a memory leak. // These sequence numbers shouldn't exist from JavaScript's perspective at all. - child_singleton.callbacks.put(bun.default_allocator, child_singleton.seq, JSC.Strong.create(callback, globalThis)) catch bun.outOfMemory(); + child_singleton.callbacks.put(bun.default_allocator, child_singleton.seq, JSC.Strong.Optional.create(callback, globalThis)) catch bun.outOfMemory(); } // sequence number for InternalMsgHolder @@ -81,9 +81,9 @@ pub fn sendHelperChild(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFram pub fn onInternalMessageChild(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { log("onInternalMessageChild", .{}); const arguments = callframe.arguments_old(2).ptr; - // TODO: we should not create two JSC.Strong here. If absolutely necessary, a single Array. should be all we use. - child_singleton.worker = JSC.Strong.create(arguments[0], globalThis); - child_singleton.cb = JSC.Strong.create(arguments[1], globalThis); + // TODO: we should not create two JSC.Strong.Optional here. If absolutely necessary, a single Array. should be all we use. + child_singleton.worker = .create(arguments[0], globalThis); + child_singleton.cb = .create(arguments[1], globalThis); try child_singleton.flush(globalThis); return .undefined; } @@ -103,10 +103,10 @@ pub const InternalMsgHolder = struct { // TODO: move this to an Array or a JS Object or something which doesn't // individually create a Strong for every single IPC message... - callbacks: std.AutoArrayHashMapUnmanaged(i32, JSC.Strong) = .{}, - worker: JSC.Strong = .empty, - cb: JSC.Strong = .empty, - messages: std.ArrayListUnmanaged(JSC.Strong) = .{}, + callbacks: std.AutoArrayHashMapUnmanaged(i32, JSC.Strong.Optional) = .{}, + worker: JSC.Strong.Optional = .empty, + cb: JSC.Strong.Optional = .empty, + messages: std.ArrayListUnmanaged(JSC.Strong.Optional) = .{}, pub fn isReady(this: *InternalMsgHolder) bool { return this.worker.has() and this.cb.has(); @@ -115,7 +115,7 @@ pub const InternalMsgHolder = struct { pub fn enqueue(this: *InternalMsgHolder, message: JSC.JSValue, globalThis: *JSC.JSGlobalObject) void { //TODO: .addOne is workaround for .append causing crash/ dependency loop in zig compiler const new_item_ptr = this.messages.addOne(bun.default_allocator) catch bun.outOfMemory(); - new_item_ptr.* = JSC.Strong.create(message, globalThis); + new_item_ptr.* = .create(message, globalThis); } pub fn dispatch(this: *InternalMsgHolder, message: JSC.JSValue, globalThis: *JSC.JSGlobalObject) bun.JSError!void { @@ -197,7 +197,7 @@ pub fn sendHelperPrimary(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFr return globalThis.throwInvalidArgumentTypeValue("message", "object", message); } if (callback.isFunction()) { - ipc_data.internal_msg_queue.callbacks.put(bun.default_allocator, ipc_data.internal_msg_queue.seq, JSC.Strong.create(callback, globalThis)) catch bun.outOfMemory(); + ipc_data.internal_msg_queue.callbacks.put(bun.default_allocator, ipc_data.internal_msg_queue.seq, JSC.Strong.Optional.create(callback, globalThis)) catch bun.outOfMemory(); } // sequence number for InternalMsgHolder @@ -221,8 +221,8 @@ pub fn onInternalMessagePrimary(globalThis: *JSC.JSGlobalObject, callframe: *JSC const subprocess = arguments[0].as(bun.JSC.Subprocess).?; const ipc_data = subprocess.ipc() orelse return .undefined; // TODO: remove these strongs. - ipc_data.internal_msg_queue.worker = JSC.Strong.create(arguments[1], globalThis); - ipc_data.internal_msg_queue.cb = JSC.Strong.create(arguments[2], globalThis); + ipc_data.internal_msg_queue.worker = .create(arguments[1], globalThis); + ipc_data.internal_msg_queue.cb = .create(arguments[2], globalThis); return .undefined; } diff --git a/src/bun.js/node/node_crypto_binding.zig b/src/bun.js/node/node_crypto_binding.zig index 3f03ad4ae5..c45c62fb54 100644 --- a/src/bun.js/node/node_crypto_binding.zig +++ b/src/bun.js/node/node_crypto_binding.zig @@ -26,7 +26,7 @@ fn ExternCryptoJob(comptime name: []const u8) type { task: JSC.WorkPoolTask, any_task: JSC.AnyTask, poll: Async.KeepAlive = .{}, - callback: JSC.Strong, + callback: JSC.Strong.Optional, ctx: *Ctx, @@ -46,7 +46,7 @@ fn ExternCryptoJob(comptime name: []const u8) type { }, .any_task = undefined, .ctx = ctx, - .callback = JSC.Strong.create(callback, global), + .callback = .create(callback, global), }); job.any_task = JSC.AnyTask.New(@This(), &runFromJS).init(job); return job; @@ -134,7 +134,7 @@ fn CryptoJob(comptime Ctx: type) type { any_task: JSC.AnyTask, poll: Async.KeepAlive = .{}, - callback: JSC.Strong, + callback: JSC.Strong.Optional, ctx: Ctx, @@ -147,7 +147,7 @@ fn CryptoJob(comptime Ctx: type) type { }, .any_task = undefined, .ctx = ctx.*, - .callback = JSC.Strong.create(callback, global), + .callback = .create(callback, global), }); errdefer bun.destroy(job); try job.ctx.init(global); @@ -534,7 +534,7 @@ const Scrypt = struct { keylen: u32, // used in async mode - buf: JSC.Strong = .empty, + buf: JSC.Strong.Optional = .empty, result: []u8 = &.{}, err: ?u32 = null, @@ -679,7 +679,7 @@ const Scrypt = struct { // to be filled in later this.result = bytes; - this.buf = JSC.Strong.create(buf, global); + this.buf = .create(buf, global); } fn runTask(this: *Scrypt, key: []u8) void { diff --git a/src/bun.js/node/node_fs_stat_watcher.zig b/src/bun.js/node/node_fs_stat_watcher.zig index dec326a95f..2dd4c0f272 100644 --- a/src/bun.js/node/node_fs_stat_watcher.zig +++ b/src/bun.js/node/node_fs_stat_watcher.zig @@ -198,7 +198,7 @@ pub const StatWatcher = struct { poll_ref: bun.Async.KeepAlive = .{}, last_stat: bun.Stat, - last_jsvalue: JSC.Strong, + last_jsvalue: JSC.Strong.Optional, pub const js = JSC.Codegen.JSStatWatcher; pub const toJS = js.toJS; @@ -379,7 +379,7 @@ pub const StatWatcher = struct { } const jsvalue = statToJSStats(this.globalThis, &this.last_stat, this.bigint); - this.last_jsvalue = JSC.Strong.create(jsvalue, this.globalThis); + this.last_jsvalue = .create(jsvalue, this.globalThis); const vm = this.globalThis.bunVM(); vm.rareData().nodeFSStatWatcherScheduler(vm).append(this); @@ -392,7 +392,7 @@ pub const StatWatcher = struct { } const jsvalue = statToJSStats(this.globalThis, &this.last_stat, this.bigint); - this.last_jsvalue = JSC.Strong.create(jsvalue, this.globalThis); + this.last_jsvalue = .create(jsvalue, this.globalThis); const vm = this.globalThis.bunVM(); diff --git a/src/bun.js/node/node_zlib_binding.zig b/src/bun.js/node/node_zlib_binding.zig index 9cd417ff77..1811a1a13f 100644 --- a/src/bun.js/node/node_zlib_binding.zig +++ b/src/bun.js/node/node_zlib_binding.zig @@ -338,7 +338,7 @@ pub const SNativeZlib = struct { stream: ZlibContext = .{}, write_result: ?[*]u32 = null, poll_ref: CountedKeepAlive = .{}, - this_value: JSC.Strong = .empty, + this_value: JSC.Strong.Optional = .empty, write_in_progress: bool = false, pending_close: bool = false, closed: bool = false, @@ -720,7 +720,7 @@ pub const SNativeBrotli = struct { stream: BrotliContext = .{}, write_result: ?[*]u32 = null, poll_ref: CountedKeepAlive = .{}, - this_value: JSC.Strong = .empty, + this_value: JSC.Strong.Optional = .empty, write_in_progress: bool = false, pending_close: bool = false, closed: bool = false, diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig index 88422b4073..5bbda16ed4 100644 --- a/src/bun.js/rare_data.zig +++ b/src/bun.js/rare_data.zig @@ -50,7 +50,7 @@ temp_pipe_read_buffer: ?*PipeReadBuffer = null, aws_signature_cache: AWSSignatureCache = .{}, -s3_default_client: JSC.Strong = .empty, +s3_default_client: JSC.Strong.Optional = .empty, default_csrf_secret: []const u8 = "", valkey_context: ValkeyContext = .{}, @@ -471,7 +471,7 @@ pub fn s3DefaultClient(rare: *RareData, globalThis: *JSC.JSGlobalObject) JSC.JSV }); const js_client = client.toJS(globalThis); js_client.ensureStillAlive(); - rare.s3_default_client = JSC.Strong.create(js_client, globalThis); + rare.s3_default_client = .create(js_client, globalThis); return js_client; }; } diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 23a38d3690..18b54d5dbd 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -2014,7 +2014,7 @@ fn formatLabel(globalThis: *JSGlobalObject, label: string, function_args: []JSVa return list.toOwnedSlice(allocator); } -pub const EachData = struct { strong: JSC.Strong, is_test: bool }; +pub const EachData = struct { strong: JSC.Strong.Optional, is_test: bool }; fn eachBind(globalThis: *JSGlobalObject, callframe: *CallFrame) bun.JSError!JSValue { const signature = "eachBind"; @@ -2206,7 +2206,7 @@ inline fn createEach( const allocator = bun.default_allocator; const name = ZigString.static(property); - const strong = JSC.Strong.create(array, globalThis); + const strong = JSC.Strong.Optional.create(array, globalThis); const each_data = allocator.create(EachData) catch unreachable; each_data.* = EachData{ .strong = strong, diff --git a/src/bun.js/webcore/Body.zig b/src/bun.js/webcore/Body.zig index 0f4944576f..d68fe4bc93 100644 --- a/src/bun.js/webcore/Body.zig +++ b/src/bun.js/webcore/Body.zig @@ -287,7 +287,7 @@ pub const Value = union(Tag) { AbortReason: JSC.CommonAbortReason, SystemError: JSC.SystemError, Message: bun.String, - JSValue: JSC.Strong, + JSValue: JSC.Strong.Optional, pub fn toStreamError(this: *@This(), globalObject: *JSC.JSGlobalObject) streams.Result.StreamError { return switch (this.*) { @@ -308,7 +308,7 @@ pub const Value = union(Tag) { // do a early return in this case we don't need to create a new Strong .JSValue => |js_value| return js_value.get() orelse JSC.JSValue.jsUndefined(), }; - this.* = .{ .JSValue = JSC.Strong.create(js_value, globalObject) }; + this.* = .{ .JSValue = .create(js_value, globalObject) }; return js_value; } @@ -319,7 +319,7 @@ pub const Value = union(Tag) { .Message => value.Message.ref(), .JSValue => |js_ref| { if (js_ref.get()) |js_value| { - return .{ .JSValue = JSC.Strong.create(js_value, globalObject) }; + return .{ .JSValue = .create(js_value, globalObject) }; } return .{ .JSValue = .empty }; }, @@ -1520,7 +1520,7 @@ pub const ValueBufferer = struct { sink.js_sink = null; wrapper.sink.destroy(); } - var ref = JSC.Strong.create(err, sink.global); + var ref = JSC.Strong.Optional.create(err, sink.global); defer ref.deinit(); sink.onFinishedBuffering(sink.ctx, "", .{ .JSValue = ref }, is_async); } diff --git a/src/bun.js/webcore/ByteStream.zig b/src/bun.js/webcore/ByteStream.zig index de09b5a6ef..e9094c59a7 100644 --- a/src/bun.js/webcore/ByteStream.zig +++ b/src/bun.js/webcore/ByteStream.zig @@ -9,7 +9,7 @@ has_received_last_chunk: bool = false, pending: streams.Result.Pending = .{ .result = .{ .done = {} } }, done: bool = false, pending_buffer: []u8 = &.{}, -pending_value: jsc.Strong = .empty, +pending_value: jsc.Strong.Optional = .empty, offset: usize = 0, highWaterMark: Blob.SizeType = 0, pipe: Pipe = .{}, diff --git a/src/bun.js/webcore/FileReader.zig b/src/bun.js/webcore/FileReader.zig index 0657ed7688..a50dd143c5 100644 --- a/src/bun.js/webcore/FileReader.zig +++ b/src/bun.js/webcore/FileReader.zig @@ -4,7 +4,7 @@ const log = Output.scoped(.FileReader, false); reader: IOReader = IOReader.init(FileReader), done: bool = false, pending: streams.Result.Pending = .{}, -pending_value: JSC.Strong = .empty, +pending_value: JSC.Strong.Optional = .empty, pending_view: []u8 = &.{}, fd: bun.FileDescriptor = bun.invalid_fd, start_offset: ?usize = null, diff --git a/src/bun.js/webcore/ReadableStream.zig b/src/bun.js/webcore/ReadableStream.zig index 96af7e0290..17c339743d 100644 --- a/src/bun.js/webcore/ReadableStream.zig +++ b/src/bun.js/webcore/ReadableStream.zig @@ -4,7 +4,7 @@ value: JSValue, ptr: Source, pub const Strong = struct { - held: JSC.Strong = .empty, + held: JSC.Strong.Optional = .empty, pub fn has(this: *Strong) bool { return this.held.has(); @@ -20,7 +20,7 @@ pub const Strong = struct { pub fn init(this: ReadableStream, global: *JSGlobalObject) Strong { return .{ - .held = JSC.Strong.create(this.value, global), + .held = .create(this.value, global), }; } @@ -437,7 +437,7 @@ pub fn NewSource( pending_err: ?Syscall.Error = null, close_handler: ?*const fn (?*anyopaque) void = null, close_ctx: ?*anyopaque = null, - close_jsvalue: JSC.Strong = .empty, + close_jsvalue: JSC.Strong.Optional = .empty, globalThis: *JSGlobalObject = undefined, this_jsvalue: JSC.JSValue = .zero, is_closed: bool = false, diff --git a/src/bun.js/webcore/Request.zig b/src/bun.js/webcore/Request.zig index f042290c92..066f0becf0 100644 --- a/src/bun.js/webcore/Request.zig +++ b/src/bun.js/webcore/Request.zig @@ -73,13 +73,13 @@ comptime { } pub const InternalJSEventCallback = struct { - function: JSC.Strong = .empty, + function: JSC.Strong.Optional = .empty, pub const EventType = JSC.API.NodeHTTPResponse.AbortEvent; pub fn init(function: JSC.JSValue, globalThis: *JSC.JSGlobalObject) InternalJSEventCallback { return InternalJSEventCallback{ - .function = JSC.Strong.create(function, globalThis), + .function = .create(function, globalThis), }; } diff --git a/src/bun.js/webcore/fetch.zig b/src/bun.js/webcore/fetch.zig index 9454eae135..c5ba03e460 100644 --- a/src/bun.js/webcore/fetch.zig +++ b/src/bun.js/webcore/fetch.zig @@ -107,10 +107,10 @@ pub const FetchTasklet = struct { has_schedule_callback: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), // must be stored because AbortSignal stores reason weakly - abort_reason: JSC.Strong = .empty, + abort_reason: JSC.Strong.Optional = .empty, // custom checkServerIdentity - check_server_identity: JSC.Strong = .empty, + check_server_identity: JSC.Strong.Optional = .empty, reject_unauthorized: bool = true, // Custom Hostname hostname: ?[]u8 = null, @@ -709,9 +709,9 @@ pub const FetchTasklet = struct { } const success = this.result.isSuccess(); const result = switch (success) { - true => JSC.Strong.create(this.onResolve(), globalThis), + true => JSC.Strong.Optional.create(this.onResolve(), globalThis), false => brk: { - // in this case we wanna a JSC.Strong so we just convert it + // in this case we wanna a JSC.Strong.Optional so we just convert it var value = this.onReject(); _ = value.toJS(globalThis); break :brk value.JSValue; @@ -720,8 +720,8 @@ pub const FetchTasklet = struct { promise_value.ensureStillAlive(); const Holder = struct { - held: JSC.Strong, - promise: JSC.Strong, + held: JSC.Strong.Optional, + promise: JSC.Strong.Optional, globalObject: *JSC.JSGlobalObject, task: JSC.AnyTask, @@ -1310,7 +1310,7 @@ pub const FetchTasklet = struct { // Custom Hostname hostname: ?[]u8 = null, memory_reporter: *bun.MemoryReportingAllocator, - check_server_identity: JSC.Strong = .empty, + check_server_identity: JSC.Strong.Optional = .empty, unix_socket_path: ZigString.Slice, ssl_config: ?*SSLConfig = null, }; diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index 9235250072..d418b31a78 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -222,7 +222,7 @@ pub const Result = union(Tag) { Error: Syscall.Error, AbortReason: JSC.CommonAbortReason, - // TODO: use an explicit JSC.Strong here. + // TODO: use an explicit JSC.Strong.Optional here. JSValue: JSC.JSValue, WeakJSValue: JSC.JSValue, diff --git a/src/deps/uws.zig b/src/deps/uws.zig index 0885acc79e..11ebc9106a 100644 --- a/src/deps/uws.zig +++ b/src/deps/uws.zig @@ -104,15 +104,15 @@ pub const UpgradedDuplex = struct { const WrapperType = SSLWrapper(*UpgradedDuplex); wrapper: ?WrapperType, - origin: JSC.Strong = .empty, // any duplex + origin: JSC.Strong.Optional = .empty, // any duplex global: ?*JSC.JSGlobalObject = null, ssl_error: CertError = .{}, vm: *JSC.VirtualMachine, handlers: Handlers, - onDataCallback: JSC.Strong = .empty, - onEndCallback: JSC.Strong = .empty, - onWritableCallback: JSC.Strong = .empty, - onCloseCallback: JSC.Strong = .empty, + onDataCallback: JSC.Strong.Optional = .empty, + onEndCallback: JSC.Strong.Optional = .empty, + onWritableCallback: JSC.Strong.Optional = .empty, + onCloseCallback: JSC.Strong.Optional = .empty, event_loop_timer: EventLoopTimer = .{ .next = .{}, .tag = .UpgradedDuplex, @@ -349,7 +349,7 @@ pub const UpgradedDuplex = struct { JSC.host_fn.setFunctionData(dataCallback, this); - this.onDataCallback = JSC.Strong.create(dataCallback, globalThis); + this.onDataCallback = .create(dataCallback, globalThis); break :brk dataCallback; }; array.putIndex(globalThis, 0, callback); @@ -369,7 +369,7 @@ pub const UpgradedDuplex = struct { JSC.host_fn.setFunctionData(endCallback, this); - this.onEndCallback = JSC.Strong.create(endCallback, globalThis); + this.onEndCallback = .create(endCallback, globalThis); break :brk endCallback; }; array.putIndex(globalThis, 1, callback); @@ -388,7 +388,7 @@ pub const UpgradedDuplex = struct { writableCallback.ensureStillAlive(); JSC.host_fn.setFunctionData(writableCallback, this); - this.onWritableCallback = JSC.Strong.create(writableCallback, globalThis); + this.onWritableCallback = .create(writableCallback, globalThis); break :brk writableCallback; }; array.putIndex(globalThis, 2, callback); @@ -407,7 +407,7 @@ pub const UpgradedDuplex = struct { closeCallback.ensureStillAlive(); JSC.host_fn.setFunctionData(closeCallback, this); - this.onCloseCallback = JSC.Strong.create(closeCallback, globalThis); + this.onCloseCallback = .create(closeCallback, globalThis); break :brk closeCallback; }; array.putIndex(globalThis, 3, callback); diff --git a/src/napi/napi.zig b/src/napi/napi.zig index 504bbef5a8..fff0bbd1b6 100644 --- a/src/napi/napi.zig +++ b/src/napi/napi.zig @@ -1425,9 +1425,9 @@ pub const Finalizer = struct { // TODO: generate comptime version of this instead of runtime checking pub const ThreadSafeFunction = struct { pub const Callback = union(enum) { - js: JSC.Strong, + js: JSC.Strong.Optional, c: struct { - js: JSC.Strong, + js: JSC.Strong.Optional, napi_threadsafe_function_call_js: napi_threadsafe_function_call_js, }, @@ -1771,10 +1771,10 @@ pub export fn napi_create_threadsafe_function( .callback = if (call_js_cb) |c| .{ .c = .{ .napi_threadsafe_function_call_js = c, - .js = if (func == .zero) .empty else JSC.Strong.create(func.withAsyncContextIfNeeded(env.toJS()), vm.global), + .js = if (func == .zero) .empty else JSC.Strong.Optional.create(func.withAsyncContextIfNeeded(env.toJS()), vm.global), }, } else .{ - .js = if (func == .zero) .empty else JSC.Strong.create(func.withAsyncContextIfNeeded(env.toJS()), vm.global), + .js = if (func == .zero) .empty else JSC.Strong.Optional.create(func.withAsyncContextIfNeeded(env.toJS()), vm.global), }, .ctx = context, .queue = ThreadSafeFunction.Queue.init(max_queue_size, bun.default_allocator), diff --git a/src/shell/Builtin.zig b/src/shell/Builtin.zig index 7c7b44157c..bd0a91bf1b 100644 --- a/src/shell/Builtin.zig +++ b/src/shell/Builtin.zig @@ -395,7 +395,7 @@ pub fn init( if (interpreter.jsobjs[file.jsbuf.idx].asArrayBuffer(globalObject)) |buf| { const arraybuf: BuiltinIO.ArrayBuf = .{ .buf = JSC.ArrayBuffer.Strong{ .array_buffer = buf, - .held = JSC.Strong.create(buf.value, globalObject), + .held = .create(buf.value, globalObject), }, .i = 0 }; if (node.redirect.stdin) { diff --git a/src/shell/interpreter.zig b/src/shell/interpreter.zig index cb677823ee..0ee43b62bb 100644 --- a/src/shell/interpreter.zig +++ b/src/shell/interpreter.zig @@ -4434,7 +4434,7 @@ pub const Interpreter = struct { if (this.base.interpreter.jsobjs[val.idx].asArrayBuffer(global)) |buf| { const stdio: bun.shell.subproc.Stdio = .{ .array_buffer = JSC.ArrayBuffer.Strong{ .array_buffer = buf, - .held = JSC.Strong.create(buf.value, global), + .held = .create(buf.value, global), } }; setStdioFromRedirect(&spawn_args.stdio, this.node.redirect, stdio); diff --git a/src/sql/postgres.zig b/src/sql/postgres.zig index c325ea5858..f4ba220df3 100644 --- a/src/sql/postgres.zig +++ b/src/sql/postgres.zig @@ -237,8 +237,8 @@ const SocketMonitor = struct { pub const PostgresSQLContext = struct { tcp: ?*uws.SocketContext = null, - onQueryResolveFn: JSC.Strong = .empty, - onQueryRejectFn: JSC.Strong = .empty, + onQueryResolveFn: JSC.Strong.Optional = .empty, + onQueryRejectFn: JSC.Strong.Optional = .empty, pub fn init(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue { var ctx = &globalObject.bunVM().rareData().postgresql_context; @@ -2847,7 +2847,7 @@ pub const PostgresSQLConnection = struct { }; pub const PostgresCachedStructure = struct { - structure: JSC.Strong = .empty, + structure: JSC.Strong.Optional = .empty, // only populated if more than JSC.JSC__JSObject__maxInlineCapacity fields otherwise the structure will contain all fields inlined fields: ?[]JSC.JSObject.ExternColumnIdentifier = null,