Lift only the handled event in handle-event
The generated export lifted the whole Event variant, which pulls in code for every event there is. A plugin now only compiles the cases it handles, the example builds in about 6s instead of 75s.
This commit is contained in:
parent
00bae41ebd
commit
60bb3cd429
33
src/abi.zig
33
src/abi.zig
@ -97,7 +97,7 @@ pub fn stats() Stats {
|
||||
|
||||
/// Drops the handles nobody kept. This calls into the host, which is not
|
||||
/// allowed from a post-return function, so it can't be left to `endCall`.
|
||||
fn releaseHandles() void {
|
||||
pub fn releaseHandles() void {
|
||||
while (tracked.pop()) |item| item.drop(@bitCast(item.handle));
|
||||
}
|
||||
|
||||
@ -419,6 +419,37 @@ pub fn liftFlat(comptime T: type, slots: []const u64) T {
|
||||
}
|
||||
}
|
||||
|
||||
// A plugin only ever looks at a few cases of the big variants (there are
|
||||
// hundreds of events). These let it lift and lower one case without pulling
|
||||
// in code for all the others.
|
||||
|
||||
pub fn loadTag(comptime U: type, ptr: [*]const u8) std.meta.Tag(U) {
|
||||
return @enumFromInt(get(Discriminant(caseCount(U)), ptr));
|
||||
}
|
||||
|
||||
pub fn loadCase(comptime U: type, comptime tag: std.meta.Tag(U), ptr: [*]const u8) @FieldType(U, @tagName(tag)) {
|
||||
return load(@FieldType(U, @tagName(tag)), ptr + payloadOffset(U));
|
||||
}
|
||||
|
||||
pub fn storeCase(comptime U: type, comptime tag: std.meta.Tag(U), value: @FieldType(U, @tagName(tag)), ptr: [*]u8) void {
|
||||
put(Discriminant(caseCount(U)), ptr, @intFromEnum(tag));
|
||||
store(@FieldType(U, @tagName(tag)), value, ptr + payloadOffset(U));
|
||||
}
|
||||
|
||||
/// Offset of field `index` inside the record `T` in linear memory.
|
||||
pub fn offsetOf(comptime T: type, comptime index: usize) comptime_int {
|
||||
return fieldOffset(T, index);
|
||||
}
|
||||
|
||||
/// Whether parameters of this shape arrive as a pointer instead of flat values.
|
||||
pub fn passedInMemory(comptime Args: type) bool {
|
||||
return flatten(Args).len > max_flat_params;
|
||||
}
|
||||
|
||||
pub fn alloc(comptime T: type) [*]u8 {
|
||||
return scratch(T);
|
||||
}
|
||||
|
||||
fn put(comptime Int: type, ptr: [*]u8, value: Int) void {
|
||||
std.mem.writeInt(Int, ptr[0..@sizeOf(Int)], value, .little);
|
||||
}
|
||||
|
||||
@ -122,15 +122,25 @@ pub fn on(
|
||||
comptime handler: fn (Server, *EventData(event_type)) void,
|
||||
options: EventOptions,
|
||||
) void {
|
||||
const tag = comptime std.meta.stringToEnum(std.meta.Tag(Event), @tagName(event_type)).?;
|
||||
const glue = struct {
|
||||
fn dispatch(srv: Server, ev: *Event) void {
|
||||
handler(srv, &@field(ev, @tagName(event_type)));
|
||||
// Only this event's payload gets lifted. Going through the whole
|
||||
// `Event` union would compile code for every event there is.
|
||||
fn dispatch(srv: Server, in: [*]const u8, out: [*]u8) void {
|
||||
if (abi.loadTag(Event, in) != tag) {
|
||||
@memcpy(out[0..abi.sizeOf(Event)], in[0..abi.sizeOf(Event)]);
|
||||
return;
|
||||
}
|
||||
var data = abi.loadCase(Event, tag, in);
|
||||
handler(srv, &data);
|
||||
abi.storeCase(Event, tag, data, out);
|
||||
}
|
||||
};
|
||||
ctx.registerEvent(handlerId(&glue.dispatch), event_type, options.priority, options.blocking);
|
||||
}
|
||||
|
||||
pub const EventHandler = fn (Server, *Event) void;
|
||||
const EventDispatch = fn (Server, in: [*]const u8, out: [*]u8) void;
|
||||
|
||||
pub const CommandHandler = fn (CommandSender, Server, ConsumedArgs) CommandResult;
|
||||
pub const SuggestionHandler = fn (CommandSender, Server, command.SuggestionRequest) command.CommandSuggestions;
|
||||
pub const TaskHandler = fn (Server) void;
|
||||
@ -223,10 +233,23 @@ pub fn register(comptime Plugin: type) void {
|
||||
return .ok;
|
||||
}
|
||||
|
||||
fn handleEvent(id: u32, srv: Server, ev: Event) Event {
|
||||
var out = ev;
|
||||
handlerFromId(EventHandler, id)(srv, &out);
|
||||
return out;
|
||||
// Written by hand instead of going through `exports.handleEvent`, see `on`.
|
||||
fn handleEvent(raw_args: i32) callconv(.c) i32 {
|
||||
const Args = struct { u32, Server, Event };
|
||||
comptime std.debug.assert(abi.passedInMemory(Args));
|
||||
|
||||
const args: [*]const u8 = @ptrFromInt(@as(u32, @bitCast(raw_args)));
|
||||
const id = abi.load(u32, args + abi.offsetOf(Args, 0));
|
||||
const srv = abi.load(Server, args + abi.offsetOf(Args, 1));
|
||||
const out = abi.alloc(Event);
|
||||
|
||||
handlerFromId(EventDispatch, id)(srv, args + abi.offsetOf(Args, 2), out);
|
||||
abi.releaseHandles();
|
||||
return @bitCast(@as(u32, @intFromPtr(out)));
|
||||
}
|
||||
|
||||
fn postHandleEvent(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
|
||||
fn handleCommand(id: u32, sender: CommandSender, srv: Server, args: ConsumedArgs) CommandResult {
|
||||
@ -281,7 +304,8 @@ pub fn register(comptime Plugin: type) void {
|
||||
exports.getMetadata(glue.getMetadata);
|
||||
exports.onLoad(glue.onLoad);
|
||||
exports.onUnload(glue.onUnload);
|
||||
exports.handleEvent(glue.handleEvent);
|
||||
@export(&glue.handleEvent, .{ .name = "handle-event" });
|
||||
@export(&glue.postHandleEvent, .{ .name = "cabi_post_handle-event" });
|
||||
exports.handleCommand(glue.handleCommand);
|
||||
exports.handleCommandSuggestion(glue.handleCommandSuggestion);
|
||||
exports.handleTask(glue.handleTask);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user