Skip to content

Commit

Permalink
Use the linker for selectors instead of the runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
mjbshaw authored and slimsag committed Aug 20, 2024
1 parent 9f46353 commit 2f988dc
Show file tree
Hide file tree
Showing 10 changed files with 2,074 additions and 7,287 deletions.
1 change: 1 addition & 0 deletions avf_audio_manual.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const c = @import("c.zig");
const cf = @import("core_foundation.zig");
const ns = @import("foundation.zig");
const objc = @import("objc.zig");

// ------------------------------------------------------------------------------------------------
// Types
Expand Down
39 changes: 7 additions & 32 deletions generator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,6 @@ fn Generator(comptime WriterType: type) type {
try self.generateEnumerations();
try self.generateContainers();
try self.generateClasses();
try self.generateSelectors();
try self.generateInit();
}

Expand All @@ -1077,22 +1076,9 @@ fn Generator(comptime WriterType: type) type {
}
}

fn generateSelectors(self: *Self) !void {
var it = self.selectors.iterator();
while (it.next()) |entry| {
const method_name = entry.key_ptr.*;
try self.writer.print("var sel_", .{});
try self.generateSelectorName(method_name);
try self.writer.print(": *c.objc_selector = undefined;\n", .{});
}
try self.writer.print("\n", .{});
}

fn generateInit(self: *Self) !void {
try self.writer.print("pub fn init() void {{\n", .{});
try self.generateInitClasses();
try self.writer.print("\n", .{});
try self.generateInitSelectors();
try self.writer.print("}}\n", .{});
}

Expand All @@ -1106,16 +1092,6 @@ fn Generator(comptime WriterType: type) type {
}
}

fn generateInitSelectors(self: *Self) !void {
var it = self.selectors.iterator();
while (it.next()) |entry| {
const method_name = entry.key_ptr.*;
try self.writer.print(" sel_", .{});
try self.generateSelectorName(method_name);
try self.writer.print(" = c.sel_registerName(\"{s}\").?;\n", .{method_name});
}
}

fn generateEnumerations(self: *Self) !void {
for (self.enums.items) |e| {
try self.writer.writeAll("\n");
Expand Down Expand Up @@ -1283,9 +1259,7 @@ fn Generator(comptime WriterType: type) type {
try self.writer.print(") ", .{});
try self.generateType(method.return_type);
try self.writer.print(" {{\n", .{});
try self.writer.writeAll(" return @as(");
try self.generateObjcSignature(method);
try self.writer.writeAll(", @ptrCast(&c.objc_msgSend))(");
try self.writer.writeAll(" return objc.msgSend(");
try self.generateMethodArgs(method);
try self.writer.print(");\n", .{});
try self.writer.print(" }}\n", .{});
Expand Down Expand Up @@ -1371,13 +1345,14 @@ fn Generator(comptime WriterType: type) type {
} else {
try self.writer.print("T.class()", .{});
}
try self.writer.print(", sel_", .{});
try self.generateSelectorName(method.name);

for (method.params.items) |param| {
try self.writer.writeAll(", ");
try self.writer.print(", \"{s}\", ", .{method.name});
try self.generateType(method.return_type);
try self.writer.writeAll(", .{");
for (method.params.items, 0..) |param, i| {
if (i != 0) try self.writer.writeAll(", ");
try self.writer.print("{s}_", .{param.name});
}
try self.writer.writeAll("}");
}

fn getBlockType(param: Param) ?Type.Function {
Expand Down
1 change: 1 addition & 0 deletions metal_manual.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const c = @import("c.zig");
const cf = @import("core_foundation.zig");
const ns = @import("foundation.zig");
const objc = @import("objc.zig");

// ------------------------------------------------------------------------------------------------
// Opaque types
Expand Down
2,256 changes: 19 additions & 2,237 deletions src/app_kit.zig

Large diffs are not rendered by default.

393 changes: 98 additions & 295 deletions src/avf_audio.zig

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion src/core_midi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ const ns = @import("foundation.zig");

// ------------------------------------------------------------------------------------------------
// Types

pub fn init() void {}
1,251 changes: 321 additions & 930 deletions src/foundation.zig

Large diffs are not rendered by default.

5,247 changes: 1,538 additions & 3,709 deletions src/metal.zig

Large diffs are not rendered by default.

64 changes: 62 additions & 2 deletions src/objc.zig
Original file line number Diff line number Diff line change
@@ -1,8 +1,68 @@
const std = @import("std");
const builtin = @import("builtin");

extern fn objc_autoreleasePoolPop(pool: *anyopaque) void;
extern fn objc_autoreleasePoolPush() *anyopaque;

pub const autoreleasePoolPop = objc_autoreleasePoolPop;
pub const autoreleasePoolPush = objc_autoreleasePoolPush;

const c = @import("c.zig");
pub const Protocol = c.objc_object;
// APIs that are part of libobjc's public API.
pub const Protocol = opaque {};

/// Calls `objc_msgSend(receiver, selector, args...)` (or `objc_msgSend_stret` if needed).
///
/// Be careful. The return type and argument types *must* match the Objective-C method's signature.
/// No compile-time verification is performed.
pub fn msgSend(receiver: anytype, comptime selector: []const u8, return_type: type, args: anytype) return_type {
const n_colons = comptime std.mem.count(u8, selector, ":");
if (comptime n_colons != args.len) {
@compileError(std.fmt.comptimePrint(
"Selector `{s}` has {} argument{s}, but {} were given",
.{ selector, n_colons, (if (n_colons == 1) "" else "s"), args.len },
));
}

// TODO: Consider run-time signature verification if `builtin.mode == .Debug` (or use some other
// toggle). Register the selector, then call `class_getInstanceMethod()` or
// `class_getClassMethod()`, then call `method_getTypeEncoding()`, and then parse the string and
// validate it against `receiver` and `args`.

const fn_type = comptime init: {
var params: []const std.builtin.Type.Fn.Param = &.{
.{
.is_generic = false,
.is_noalias = false,
.type = @TypeOf(receiver),
},
.{
.is_generic = false,
.is_noalias = false,
.type = [*:0]c_char,
},
};
for (@typeInfo(@TypeOf(args)).Struct.fields) |field| {
params = params ++
.{.{
.is_generic = false,
.is_noalias = false,
.type = field.type,
}};
}
break :init std.builtin.Type{
.Fn = .{
.calling_convention = .C,
.is_generic = false,
.is_var_args = false,
.return_type = return_type,
.params = params,
},
};
};

const needs_fpret = comptime builtin.target.cpu.arch == .x86_64 and (return_type == f32 or return_type == f64);
const needs_stret = comptime builtin.target.cpu.arch == .x86_64 and @sizeOf(return_type) > 16;
const msg_send_fn_name = comptime if (needs_stret) "objc_msgSend_stret" else if (needs_fpret) "objc_msgSend_fpret" else "objc_msgSend";
const msg_send_fn = @extern(*const @Type(fn_type), .{ .name = msg_send_fn_name ++ "$" ++ selector });
return @call(.auto, msg_send_fn, .{ receiver, undefined } ++ args);
}
108 changes: 27 additions & 81 deletions src/quartz_core.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const c = @import("c.zig");
const cg = @import("core_graphics.zig");
const mtl = @import("metal.zig");
const ns = @import("foundation.zig");
const objc = @import("objc.zig");

pub const Layer = opaque {
pub fn class() *c.objc_class {
Expand All @@ -24,10 +25,10 @@ pub const MetalDrawable = opaque {
pub usingnamespace mtl.Drawable.Methods(T);

pub fn texture(self_: *T) *mtl.Texture {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) *mtl.Texture, @ptrCast(&c.objc_msgSend))(self_, sel_texture);
return objc.msgSend(self_, "texture", *mtl.Texture, .{});
}
pub fn layer(self_: *T) *MetalLayer {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) *MetalLayer, @ptrCast(&c.objc_msgSend))(self_, sel_layer);
return objc.msgSend(self_, "layer", *MetalLayer, .{});
}
};
}
Expand All @@ -44,139 +45,84 @@ pub const MetalLayer = opaque {
pub usingnamespace Layer.Methods(T);

pub fn nextDrawable(self_: *T) ?*MetalDrawable {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) ?*MetalDrawable, @ptrCast(&c.objc_msgSend))(self_, sel_nextDrawable);
return objc.msgSend(self_, "nextDrawable", ?*MetalDrawable, .{});
}
pub fn device(self_: *T) ?*mtl.Device {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) ?*mtl.Device, @ptrCast(&c.objc_msgSend))(self_, sel_device);
return objc.msgSend(self_, "device", ?*mtl.Device, .{});
}
pub fn setDevice(self_: *T, device_: ?*mtl.Device) void {
return @as(*const fn (*T, *c.objc_selector, ?*mtl.Device) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setDevice_, device_);
return objc.msgSend(self_, "setDevice:", void, .{device_});
}
pub fn preferredDevice(self_: *T) ?*mtl.Device {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) ?*mtl.Device, @ptrCast(&c.objc_msgSend))(self_, sel_preferredDevice);
return objc.msgSend(self_, "preferredDevice", ?*mtl.Device, .{});
}
pub fn pixelFormat(self_: *T) mtl.PixelFormat {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) mtl.PixelFormat, @ptrCast(&c.objc_msgSend))(self_, sel_pixelFormat);
return objc.msgSend(self_, "pixelFormat", mtl.PixelFormat, .{});
}
pub fn setPixelFormat(self_: *T, pixelFormat_: mtl.PixelFormat) void {
return @as(*const fn (*T, *c.objc_selector, mtl.PixelFormat) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setPixelFormat_, pixelFormat_);
return objc.msgSend(self_, "setPixelFormat:", void, .{pixelFormat_});
}
pub fn framebufferOnly(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_framebufferOnly);
return objc.msgSend(self_, "framebufferOnly", bool, .{});
}
pub fn setFramebufferOnly(self_: *T, framebufferOnly_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setFramebufferOnly_, framebufferOnly_);
return objc.msgSend(self_, "setFramebufferOnly:", void, .{framebufferOnly_});
}
pub fn drawableSize(self_: *T) cg.Size {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) cg.Size, @ptrCast(&c.objc_msgSend))(self_, sel_drawableSize);
return objc.msgSend(self_, "drawableSize", cg.Size, .{});
}
pub fn setDrawableSize(self_: *T, drawableSize_: cg.Size) void {
return @as(*const fn (*T, *c.objc_selector, cg.Size) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setDrawableSize_, drawableSize_);
return objc.msgSend(self_, "setDrawableSize:", void, .{drawableSize_});
}
pub fn maximumDrawableCount(self_: *T) ns.UInteger {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) ns.UInteger, @ptrCast(&c.objc_msgSend))(self_, sel_maximumDrawableCount);
return objc.msgSend(self_, "maximumDrawableCount", ns.UInteger, .{});
}
pub fn setMaximumDrawableCount(self_: *T, maximumDrawableCount_: ns.UInteger) void {
return @as(*const fn (*T, *c.objc_selector, ns.UInteger) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setMaximumDrawableCount_, maximumDrawableCount_);
return objc.msgSend(self_, "setMaximumDrawableCount:", void, .{maximumDrawableCount_});
}
pub fn presentsWithTransaction(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_presentsWithTransaction);
return objc.msgSend(self_, "presentsWithTransaction", bool, .{});
}
pub fn setPresentsWithTransaction(self_: *T, presentsWithTransaction_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setPresentsWithTransaction_, presentsWithTransaction_);
return objc.msgSend(self_, "setPresentsWithTransaction:", void, .{presentsWithTransaction_});
}
pub fn colorspace(self_: *T) cg.ColorSpaceRef {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) cg.ColorSpaceRef, @ptrCast(&c.objc_msgSend))(self_, sel_colorspace);
return objc.msgSend(self_, "colorspace", cg.ColorSpaceRef, .{});
}
pub fn setColorspace(self_: *T, colorspace_: cg.ColorSpaceRef) void {
return @as(*const fn (*T, *c.objc_selector, cg.ColorSpaceRef) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setColorspace_, colorspace_);
return objc.msgSend(self_, "setColorspace:", void, .{colorspace_});
}
pub fn wantsExtendedDynamicRangeContent(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_wantsExtendedDynamicRangeContent);
return objc.msgSend(self_, "wantsExtendedDynamicRangeContent", bool, .{});
}
pub fn setWantsExtendedDynamicRangeContent(self_: *T, wantsExtendedDynamicRangeContent_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setWantsExtendedDynamicRangeContent_, wantsExtendedDynamicRangeContent_);
return objc.msgSend(self_, "setWantsExtendedDynamicRangeContent:", void, .{wantsExtendedDynamicRangeContent_});
}
// pub fn EDRMetadata(self_: *T) ?*EDRMetadata {
// return @as(*const fn (*T, *c.objc_selector) callconv(.C) ?*EDRMetadata, @ptrCast(&c.objc_msgSend))(self_, sel_EDRMetadata);
// return objc.msgSend(self_, "EDRMetadata", ?*EDRMetadata, .{});
// }
// pub fn setEDRMetadata(self_: *T, EDRMetadata_: ?*EDRMetadata) void {
// return @as(*const fn (*T, *c.objc_selector, ?*EDRMetadata) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setEDRMetadata_, EDRMetadata_);
// return objc.msgSend(self_, "setEDRMetadata:", void, .{EDRMetadata_});
// }
pub fn displaySyncEnabled(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_displaySyncEnabled);
return objc.msgSend(self_, "displaySyncEnabled", bool, .{});
}
pub fn setDisplaySyncEnabled(self_: *T, displaySyncEnabled_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setDisplaySyncEnabled_, displaySyncEnabled_);
return objc.msgSend(self_, "setDisplaySyncEnabled:", void, .{displaySyncEnabled_});
}
pub fn allowsNextDrawableTimeout(self_: *T) bool {
return @as(*const fn (*T, *c.objc_selector) callconv(.C) bool, @ptrCast(&c.objc_msgSend))(self_, sel_allowsNextDrawableTimeout);
return objc.msgSend(self_, "allowsNextDrawableTimeout", bool, .{});
}
pub fn setAllowsNextDrawableTimeout(self_: *T, allowsNextDrawableTimeout_: bool) void {
return @as(*const fn (*T, *c.objc_selector, bool) callconv(.C) void, @ptrCast(&c.objc_msgSend))(self_, sel_setAllowsNextDrawableTimeout_, allowsNextDrawableTimeout_);
return objc.msgSend(self_, "setAllowsNextDrawableTimeout:", void, .{allowsNextDrawableTimeout_});
}
};
}
};
var class_Layer: *c.objc_class = undefined;
var class_MetalLayer: *c.objc_class = undefined;
var sel_setColorspace_: *c.objc_selector = undefined;
//var sel_EDRMetadata: *c.objc_selector = undefined;
var sel_setWantsExtendedDynamicRangeContent_: *c.objc_selector = undefined;
var sel_setDevice_: *c.objc_selector = undefined;
var sel_setPixelFormat_: *c.objc_selector = undefined;
var sel_setPresentsWithTransaction_: *c.objc_selector = undefined;
var sel_setMaximumDrawableCount_: *c.objc_selector = undefined;
var sel_setDrawableSize_: *c.objc_selector = undefined;
var sel_device: *c.objc_selector = undefined;
var sel_drawableSize: *c.objc_selector = undefined;
var sel_framebufferOnly: *c.objc_selector = undefined;
var sel_texture: *c.objc_selector = undefined;
var sel_developerHUDProperties: *c.objc_selector = undefined;
var sel_wantsExtendedDynamicRangeContent: *c.objc_selector = undefined;
var sel_preferredDevice: *c.objc_selector = undefined;
var sel_allowsNextDrawableTimeout: *c.objc_selector = undefined;
var sel_maximumDrawableCount: *c.objc_selector = undefined;
var sel_presentsWithTransaction: *c.objc_selector = undefined;
var sel_displaySyncEnabled: *c.objc_selector = undefined;
var sel_pixelFormat: *c.objc_selector = undefined;
var sel_colorspace: *c.objc_selector = undefined;
var sel_setDisplaySyncEnabled_: *c.objc_selector = undefined;
var sel_setFramebufferOnly_: *c.objc_selector = undefined;
var sel_setAllowsNextDrawableTimeout_: *c.objc_selector = undefined;
var sel_layer: *c.objc_selector = undefined;
var sel_nextDrawable: *c.objc_selector = undefined;
var sel_setEDRMetadata_: *c.objc_selector = undefined;
var sel_setDeveloperHUDProperties_: *c.objc_selector = undefined;

pub fn init() void {
class_Layer = c.objc_getClass("CALayer").?;
class_MetalLayer = c.objc_getClass("CAMetalLayer").?;

sel_setColorspace_ = c.sel_registerName("setColorspace:").?;
//sel_EDRMetadata = c.sel_registerName("EDRMetadata").?;
sel_setWantsExtendedDynamicRangeContent_ = c.sel_registerName("setWantsExtendedDynamicRangeContent:").?;
sel_setDevice_ = c.sel_registerName("setDevice:").?;
sel_setPixelFormat_ = c.sel_registerName("setPixelFormat:").?;
sel_setPresentsWithTransaction_ = c.sel_registerName("setPresentsWithTransaction:").?;
sel_setMaximumDrawableCount_ = c.sel_registerName("setMaximumDrawableCount:").?;
sel_setDrawableSize_ = c.sel_registerName("setDrawableSize:").?;
sel_device = c.sel_registerName("device").?;
sel_drawableSize = c.sel_registerName("drawableSize").?;
sel_framebufferOnly = c.sel_registerName("framebufferOnly").?;
sel_texture = c.sel_registerName("texture").?;
sel_wantsExtendedDynamicRangeContent = c.sel_registerName("wantsExtendedDynamicRangeContent").?;
sel_preferredDevice = c.sel_registerName("preferredDevice").?;
sel_allowsNextDrawableTimeout = c.sel_registerName("allowsNextDrawableTimeout").?;
sel_maximumDrawableCount = c.sel_registerName("maximumDrawableCount").?;
sel_presentsWithTransaction = c.sel_registerName("presentsWithTransaction").?;
sel_displaySyncEnabled = c.sel_registerName("displaySyncEnabled").?;
sel_pixelFormat = c.sel_registerName("pixelFormat").?;
sel_colorspace = c.sel_registerName("colorspace").?;
sel_setDisplaySyncEnabled_ = c.sel_registerName("setDisplaySyncEnabled:").?;
sel_setFramebufferOnly_ = c.sel_registerName("setFramebufferOnly:").?;
sel_setAllowsNextDrawableTimeout_ = c.sel_registerName("setAllowsNextDrawableTimeout:").?;
sel_layer = c.sel_registerName("layer").?;
sel_nextDrawable = c.sel_registerName("nextDrawable").?;
sel_setEDRMetadata_ = c.sel_registerName("setEDRMetadata:").?;
}

0 comments on commit 2f988dc

Please sign in to comment.