Skip to content

Commit 18ca3bf

Browse files
committed
Optimize ret fast path: skip defers/type-check for plain returns
Cache has_typed_returns in Frame so the common ret case (no defers, no typed returns) avoids pushTempRoot, popTempRoot, frameFuncSig, and enforceFuncReturnTypes. fib(35) release: 2.44s -> 2.17s (~11%).
1 parent 98b454c commit 18ca3bf

2 files changed

Lines changed: 26 additions & 7 deletions

File tree

src/lang/vm.zig

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ fn performCall(argc: u8) !void {
107107
.closure = null,
108108
.func_obj = obj,
109109
.defer_base = vmState().defer_top,
110+
.has_typed_returns = f.has_typed_returns,
110111
};
111112
vmState().frame_top += 1;
112113
vmState().ip = f.ip;
@@ -125,6 +126,7 @@ fn performCall(argc: u8) !void {
125126
.closure = obj,
126127
.func_obj = cl.func,
127128
.defer_base = vmState().defer_top,
129+
.has_typed_returns = f.has_typed_returns,
128130
};
129131
vmState().frame_top += 1;
130132
vmState().ip = f.ip;
@@ -817,7 +819,7 @@ fn runInner() !void {
817819
const proto = f.object.function;
818820
const ups = heap.bump(*Object, proto.capture_slots.len) orelse return error.OutOfMemory;
819821
if (vmState().frame_top == 0 and proto.capture_slots.len != 0) return error.TypeError;
820-
const frame = if (vmState().frame_top == 0) vms.Frame{ .ret_ip = 0, .base = 0, .closure = null, .func_obj = f.object, .defer_base = 0 } else vmState().frames[vmState().frame_top - 1];
822+
const frame = if (vmState().frame_top == 0) vms.Frame{ .ret_ip = 0, .base = 0, .closure = null, .func_obj = f.object, .defer_base = 0, .has_typed_returns = false } else vmState().frames[vmState().frame_top - 1];
821823
var i: usize = 0;
822824
while (i < proto.capture_slots.len) : (i += 1) {
823825
const enc = proto.capture_slots[i];
@@ -979,9 +981,24 @@ fn runInner() !void {
979981
.ret => {
980982
if (vmState().frame_top == 0) return error.ReturnAtTopLevel;
981983
const retval = try vmPop();
982-
const frame_defer_base = vmState().frames[vmState().frame_top - 1].defer_base;
984+
const fi = vmState().frame_top - 1;
985+
const frame = &vmState().frames[fi];
986+
987+
// Fast path: no defers pending, no return-type checks (the common case).
988+
if (vmState().defer_top == frame.defer_base and !frame.has_typed_returns) {
989+
vmState().frame_top = fi;
990+
vmState().stack_top = frame.base - 1;
991+
vmState().ip = frame.ret_ip;
992+
try vmPush(retval);
993+
if (vmState().call_depth_target) |d| {
994+
if (vmState().frame_top == d) return;
995+
}
996+
continue;
997+
}
998+
999+
// Slow path: run defers and/or enforce return types.
9831000
try pushTempRoot(retval);
984-
while (vmState().defer_top > frame_defer_base) {
1001+
while (vmState().defer_top > frame.defer_base) {
9851002
vmState().defer_top -= 1;
9861003
const deferred = vmState().defer_stack[vmState().defer_top];
9871004
try pushTempRoot(deferred);
@@ -1003,10 +1020,11 @@ fn runInner() !void {
10031020
popTempRoot();
10041021
}
10051022
popTempRoot();
1006-
vmState().frame_top -= 1;
1007-
const frame = vmState().frames[vmState().frame_top];
1008-
const fsig = try vmtyp.frameFuncSig(frame.func_obj);
1009-
try vmtyp.enforceFuncReturnTypes(fsig, retval);
1023+
vmState().frame_top = fi;
1024+
if (frame.has_typed_returns) {
1025+
const fsig = try vmtyp.frameFuncSig(frame.func_obj);
1026+
try vmtyp.enforceFuncReturnTypes(fsig, retval);
1027+
}
10101028
vmState().stack_top = frame.base - 1;
10111029
vmState().ip = frame.ret_ip;
10121030
try vmPush(retval);

src/lang/vm_state.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub const Frame = struct {
2828
closure: ?*Object,
2929
func_obj: *Object,
3030
defer_base: usize,
31+
has_typed_returns: bool,
3132
};
3233

3334
pub const PanicFrame = struct { line: u16, name: []const u8 };

0 commit comments

Comments
 (0)