From 5adca95e5e251f555483f6eaa28ec95de6b52472 Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 17 Sep 2025 14:15:33 -0700 Subject: [PATCH 1/8] lazy shared ptr fixes --- src/ptr/shared.zig | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ptr/shared.zig b/src/ptr/shared.zig index c3e8adaa8aae5a..71def141235db3 100644 --- a/src/ptr/shared.zig +++ b/src/ptr/shared.zig @@ -139,7 +139,12 @@ pub fn WithOptions(comptime Pointer: type, comptime options: Options) type { /// Creates a weak clone of this shared pointer. pub const cloneWeak = if (options.allow_weak) struct { pub fn cloneWeak(self: Self) Self.Weak { - return .{ .#pointer = self.#pointer }; + const data = if (comptime info.isOptional()) + self.getData() orelse return + else + self.getData(); + data.incrementWeak(); + return .{ .#pointer = &data.value }; } }.cloneWeak; @@ -178,17 +183,18 @@ pub fn WithOptions(comptime Pointer: type, comptime options: Options) type { /// `deinit` on `self`. pub const take = if (info.isOptional()) struct { pub fn take(self: *Self) ?SharedNonOptional { + defer self.* = .initNull(); return .{ .#pointer = self.#pointer orelse return null }; } }.take; - const SharedOptional = WithOptions(?Pointer, options); + pub const Optional = WithOptions(?Pointer, options); /// Converts a `Shared(*T)` into a non-null `Shared(?*T)`. /// /// This method invalidates `self`. pub const toOptional = if (!info.isOptional()) struct { - pub fn toOptional(self: *Self) SharedOptional { + pub fn toOptional(self: *Self) Optional { defer self.* = undefined; return .{ .#pointer = self.#pointer }; } @@ -232,6 +238,10 @@ pub fn WithOptions(comptime Pointer: type, comptime options: Options) type { fn getData(self: Self) if (info.isOptional()) ?*Data else *Data { return .fromValuePtr(self.#pointer); } + + pub fn unsafeGetStrongFromPointer(pointer: Pointer) Self { + return .{ .#pointer = pointer }; + } }; } @@ -263,7 +273,7 @@ fn Weak(comptime Pointer: type, comptime options: Options) type { else self.getData(); if (!data.tryIncrementStrong()) return null; - data.incrementWeak(); + data.decrementWeak(); return .{ .#pointer = &data.value }; } From dd7a524de7fadc714ec30f6897beac70f32595b4 Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 17 Sep 2025 14:16:08 -0700 Subject: [PATCH 2/8] cppbind output order change --- src/bun.zig | 2 +- src/codegen/cppbind.ts | 72 ++++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/bun.zig b/src/bun.zig index 9091ba0f8a4a06..23722b4f4513f2 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -3755,7 +3755,7 @@ pub const highway = @import("./highway.zig"); pub const mach_port = if (Environment.isMac) std.c.mach_port_t else u32; /// Automatically generated C++ bindings for functions marked with `[[ZIG_EXPORT(...)]]` -pub const cpp = @import("cpp").bindings; +pub const cpp = @import("cpp"); pub const asan = @import("./asan.zig"); diff --git a/src/codegen/cppbind.ts b/src/codegen/cppbind.ts index 9067b0932fe7c7..cd56b26bace27c 100644 --- a/src/codegen/cppbind.ts +++ b/src/codegen/cppbind.ts @@ -471,7 +471,7 @@ function generateZigParameterList(parameters: CppParameter[], globalThisArg?: Cp function generateZigSourceComment(cfg: Cfg, resultSourceLinks: string[], fn: CppFn): string { const fileName = relative(cfg.dstDir, fn.position.file); resultSourceLinks.push(`${fn.name}:${fileName}:${fn.position.start.line}:${fn.position.start.column}`); - return ` /// Source: ${fn.name}`; + return `/// Source: ${fn.name}`; } function closest(node: SyntaxNode | null, type: string): SyntaxNode | null { @@ -644,7 +644,7 @@ function generateZigFn( resultBindings.push(generateZigSourceComment(cfg, resultSourceLinks, fn)); if (fn.tag === "nothrow") { resultBindings.push( - ` pub extern fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters)}) ${returnType};`, + `pub extern fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters)}) ${returnType};`, ); return; } @@ -667,21 +667,21 @@ function generateZigFn( ); } resultBindings.push( - ` pub inline fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) bun.JSError!${returnType} {`, - ` if (comptime Environment.ci_assert) {`, - ` var scope: jsc.CatchScope = undefined;`, - ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, - ` defer scope.deinit();`, + `pub inline fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) bun.JSError!${returnType} {`, + ` if (comptime Environment.ci_assert) {`, + ` var scope: jsc.CatchScope = undefined;`, + ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, + ` defer scope.deinit();`, ``, - ` const result = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, - ` try scope.returnIfException();`, - ` return result;`, - ` } else {`, - ` const result = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, - ` if (Bun__RETURN_IF_EXCEPTION(${formatZigName(globalThisArg.name)})) return error.JSError;`, - ` return result;`, - ` }`, + ` const result = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, + ` try scope.returnIfException();`, + ` return result;`, + ` } else {`, + ` const result = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, + ` if (Bun__RETURN_IF_EXCEPTION(${formatZigName(globalThisArg.name)})) return error.JSError;`, + ` return result;`, ` }`, + `}`, ); return; } @@ -699,21 +699,21 @@ function generateZigFn( } } else assertNever(fn.tag); resultBindings.push( - ` pub inline fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) bun.JSError!${returnType} {`, - ` if (comptime Environment.ci_assert) {`, - ` var scope: jsc.ExceptionValidationScope = undefined;`, - ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, - ` defer scope.deinit();`, + `pub inline fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) bun.JSError!${returnType} {`, + ` if (comptime Environment.ci_assert) {`, + ` var scope: jsc.ExceptionValidationScope = undefined;`, + ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, + ` defer scope.deinit();`, ``, - ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, - ` scope.assertExceptionPresenceMatches(value == ${equalsValue});`, - ` return if (value == ${equalsValue}) error.JSError else value;`, - ` } else {`, - ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, - ` if (value == ${equalsValue}) return error.JSError;`, - ` return value;`, - ` }`, + ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, + ` scope.assertExceptionPresenceMatches(value == ${equalsValue});`, + ` return if (value == ${equalsValue}) error.JSError else value;`, + ` } else {`, + ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, + ` if (value == ${equalsValue}) return error.JSError;`, + ` return value;`, ` }`, + `}`, ); return; } @@ -729,9 +729,8 @@ async function readFileOrEmpty(file: string): Promise { async function main() { const args = process.argv.slice(2); - const rootDir = args[0]; const dstDir = args[1]; - if (!rootDir || !dstDir) { + if (!dstDir) { console.error( String.raw` _ _ _ @@ -744,7 +743,7 @@ async function main() { |_| |_| `.slice(1), ); - console.error("Usage: bun src/codegen/cppbind "); + console.error("Usage: bun src/codegen/cppbind src build/debug/codegen"); process.exit(1); } await mkdir(dstDir, { recursive: true }); @@ -759,9 +758,8 @@ async function main() { .filter(q => !q.startsWith("#")); const allFunctions: CppFn[] = []; - for (const file of allCppFiles) { - await processFile(parser, file, allFunctions); - } + await Promise.all(allCppFiles.map(file => processFile(parser, file, allFunctions))); + allFunctions.sort((a, b) => (a.position.file < b.position.file ? -1 : a.position.file > b.position.file ? 1 : 0)); const resultRaw: string[] = []; const resultBindings: string[] = []; @@ -785,10 +783,10 @@ async function main() { const resultFilePath = join(dstDir, "cpp.zig"); const resultContents = typeDeclarations + - "\nconst raw = struct {\n" + - resultRaw.join("\n") + - "\n};\n\npub const bindings = struct {\n" + + "\n" + resultBindings.join("\n") + + "\n\nconst raw = struct {\n" + + resultRaw.join("\n") + "\n};\n"; if ((await readFileOrEmpty(resultFilePath)) !== resultContents) { await Bun.write(resultFilePath, resultContents); From 1a551b0959867ad15120fad767a6ba62408b6920 Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 17 Sep 2025 14:18:23 -0700 Subject: [PATCH 3/8] fixes false_is_throw --- src/codegen/cppbind.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/codegen/cppbind.ts b/src/codegen/cppbind.ts index cd56b26bace27c..ba01d3bcad118b 100644 --- a/src/codegen/cppbind.ts +++ b/src/codegen/cppbind.ts @@ -699,7 +699,7 @@ function generateZigFn( } } else assertNever(fn.tag); resultBindings.push( - `pub inline fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) bun.JSError!${returnType} {`, + `pub inline fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) bun.JSError!${fn.tag === "false_is_throw" ? "void" : returnType} {`, ` if (comptime Environment.ci_assert) {`, ` var scope: jsc.ExceptionValidationScope = undefined;`, ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, @@ -707,11 +707,11 @@ function generateZigFn( ``, ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, ` scope.assertExceptionPresenceMatches(value == ${equalsValue});`, - ` return if (value == ${equalsValue}) error.JSError else value;`, + ` return if (value == ${equalsValue}) error.JSError ${fn.tag === "false_is_throw" ? "" : "else value"};`, ` } else {`, ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, ` if (value == ${equalsValue}) return error.JSError;`, - ` return value;`, + ...(fn.tag === "false_is_throw" ? [] : [` return value;`]), ` }`, `}`, ); From e81587b1b4d5547aee60b704340147c69aaad2e5 Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 17 Sep 2025 15:30:17 -0700 Subject: [PATCH 4/8] address review --- src/ptr/shared.zig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ptr/shared.zig b/src/ptr/shared.zig index 71def141235db3..e2bdce22d330c5 100644 --- a/src/ptr/shared.zig +++ b/src/ptr/shared.zig @@ -239,8 +239,10 @@ pub fn WithOptions(comptime Pointer: type, comptime options: Options) type { return .fromValuePtr(self.#pointer); } - pub fn unsafeGetStrongFromPointer(pointer: Pointer) Self { - return .{ .#pointer = pointer }; + /// Assumes that the pointer is valid and was created by Shared.new(). + pub fn cloneFromRawUnsafe(pointer: Pointer) Self { + var raw: Self = .{ .#pointer = pointer }; + return raw.clone(); } }; } @@ -293,7 +295,7 @@ fn Weak(comptime Pointer: type, comptime options: Options) type { pub fn deinit(self: *Self) void { defer self.* = undefined; const data = if (comptime info.isOptional()) - self.getData() orelse return + self.getData() orelse return .initNull() else self.getData(); data.decrementWeak(); From c62d9f9b09dc8c65bed8869331640f766e061681 Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 17 Sep 2025 15:46:38 -0700 Subject: [PATCH 5/8] Update src/ptr/shared.zig Co-authored-by: taylor.fish --- src/ptr/shared.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ptr/shared.zig b/src/ptr/shared.zig index e2bdce22d330c5..fed877dd71467e 100644 --- a/src/ptr/shared.zig +++ b/src/ptr/shared.zig @@ -239,7 +239,11 @@ pub fn WithOptions(comptime Pointer: type, comptime options: Options) type { return .fromValuePtr(self.#pointer); } - /// Assumes that the pointer is valid and was created by Shared.new(). + /// Clones a shared pointer, given a raw pointer that originally came from a shared pointer. + /// + /// `pointer` must have come from a shared pointer (e.g., from `get` or `leak`), and the shared + /// pointer from which it came must remain valid (i.e., not be deinitialized) at least until + /// this function returns. pub fn cloneFromRawUnsafe(pointer: Pointer) Self { var raw: Self = .{ .#pointer = pointer }; return raw.clone(); From 6c07796cafb79982eb4d66ccf0759529ae6c96c9 Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 17 Sep 2025 15:47:09 -0700 Subject: [PATCH 6/8] Update src/ptr/shared.zig Co-authored-by: taylor.fish --- src/ptr/shared.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ptr/shared.zig b/src/ptr/shared.zig index fed877dd71467e..27757621dd05ee 100644 --- a/src/ptr/shared.zig +++ b/src/ptr/shared.zig @@ -245,8 +245,8 @@ pub fn WithOptions(comptime Pointer: type, comptime options: Options) type { /// pointer from which it came must remain valid (i.e., not be deinitialized) at least until /// this function returns. pub fn cloneFromRawUnsafe(pointer: Pointer) Self { - var raw: Self = .{ .#pointer = pointer }; - return raw.clone(); + const temp: Self = .{ .#pointer = pointer }; + return temp.clone(); } }; } From b6a372f5aff08ee7c66ec8321b8d097b0e7bb2e5 Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 17 Sep 2025 15:47:22 -0700 Subject: [PATCH 7/8] Update src/ptr/shared.zig Co-authored-by: taylor.fish --- src/ptr/shared.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ptr/shared.zig b/src/ptr/shared.zig index 27757621dd05ee..ee0539bef48a27 100644 --- a/src/ptr/shared.zig +++ b/src/ptr/shared.zig @@ -299,7 +299,7 @@ fn Weak(comptime Pointer: type, comptime options: Options) type { pub fn deinit(self: *Self) void { defer self.* = undefined; const data = if (comptime info.isOptional()) - self.getData() orelse return .initNull() + self.getData() orelse return else self.getData(); data.decrementWeak(); From 0867822e80bef180e50e30fe44a34d37d1edc44a Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 17 Sep 2025 15:47:37 -0700 Subject: [PATCH 8/8] Update src/ptr/shared.zig Co-authored-by: taylor.fish --- src/ptr/shared.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ptr/shared.zig b/src/ptr/shared.zig index ee0539bef48a27..208922a981e9a5 100644 --- a/src/ptr/shared.zig +++ b/src/ptr/shared.zig @@ -140,7 +140,7 @@ pub fn WithOptions(comptime Pointer: type, comptime options: Options) type { pub const cloneWeak = if (options.allow_weak) struct { pub fn cloneWeak(self: Self) Self.Weak { const data = if (comptime info.isOptional()) - self.getData() orelse return + self.getData() orelse return .initNull() else self.getData(); data.incrementWeak();