Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bun.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
72 changes: 35 additions & 37 deletions src/codegen/cppbind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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!${fn.tag === "false_is_throw" ? "void" : 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 ${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;`,
...(fn.tag === "false_is_throw" ? [] : [` return value;`]),
` }`,
`}`,
);
return;
}
Expand All @@ -729,9 +729,8 @@ async function readFileOrEmpty(file: string): Promise<string> {

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`
_ _ _
Expand All @@ -744,7 +743,7 @@ async function main() {
|_| |_|
`.slice(1),
);
console.error("Usage: bun src/codegen/cppbind <rootDir> <dstDir>");
console.error("Usage: bun src/codegen/cppbind src build/debug/codegen");
process.exit(1);
}
await mkdir(dstDir, { recursive: true });
Expand All @@ -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[] = [];
Expand All @@ -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);
Expand Down
24 changes: 20 additions & 4 deletions src/ptr/shared.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 .initNull()
else
self.getData();
data.incrementWeak();
return .{ .#pointer = &data.value };
}
}.cloneWeak;

Expand Down Expand Up @@ -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 };
}
Expand Down Expand Up @@ -232,6 +238,16 @@ pub fn WithOptions(comptime Pointer: type, comptime options: Options) type {
fn getData(self: Self) if (info.isOptional()) ?*Data else *Data {
return .fromValuePtr(self.#pointer);
}

/// 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 {
const temp: Self = .{ .#pointer = pointer };
return temp.clone();
}
};
}

Expand Down Expand Up @@ -263,7 +279,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 };
}

Expand Down