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
|
/// 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`.
|
/// 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));
|
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 {
|
fn put(comptime Int: type, ptr: [*]u8, value: Int) void {
|
||||||
std.mem.writeInt(Int, ptr[0..@sizeOf(Int)], value, .little);
|
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,
|
comptime handler: fn (Server, *EventData(event_type)) void,
|
||||||
options: EventOptions,
|
options: EventOptions,
|
||||||
) void {
|
) void {
|
||||||
|
const tag = comptime std.meta.stringToEnum(std.meta.Tag(Event), @tagName(event_type)).?;
|
||||||
const glue = struct {
|
const glue = struct {
|
||||||
fn dispatch(srv: Server, ev: *Event) void {
|
// Only this event's payload gets lifted. Going through the whole
|
||||||
handler(srv, &@field(ev, @tagName(event_type)));
|
// `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);
|
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 CommandHandler = fn (CommandSender, Server, ConsumedArgs) CommandResult;
|
||||||
pub const SuggestionHandler = fn (CommandSender, Server, command.SuggestionRequest) command.CommandSuggestions;
|
pub const SuggestionHandler = fn (CommandSender, Server, command.SuggestionRequest) command.CommandSuggestions;
|
||||||
pub const TaskHandler = fn (Server) void;
|
pub const TaskHandler = fn (Server) void;
|
||||||
@ -223,10 +233,23 @@ pub fn register(comptime Plugin: type) void {
|
|||||||
return .ok;
|
return .ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleEvent(id: u32, srv: Server, ev: Event) Event {
|
// Written by hand instead of going through `exports.handleEvent`, see `on`.
|
||||||
var out = ev;
|
fn handleEvent(raw_args: i32) callconv(.c) i32 {
|
||||||
handlerFromId(EventHandler, id)(srv, &out);
|
const Args = struct { u32, Server, Event };
|
||||||
return out;
|
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 {
|
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.getMetadata(glue.getMetadata);
|
||||||
exports.onLoad(glue.onLoad);
|
exports.onLoad(glue.onLoad);
|
||||||
exports.onUnload(glue.onUnload);
|
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.handleCommand(glue.handleCommand);
|
||||||
exports.handleCommandSuggestion(glue.handleCommandSuggestion);
|
exports.handleCommandSuggestion(glue.handleCommandSuggestion);
|
||||||
exports.handleTask(glue.handleTask);
|
exports.handleTask(glue.handleTask);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user