From 15741775178dbca2b5f51a7106f0456a7d090456 Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Sun, 27 Apr 2025 09:00:52 +0100 Subject: [PATCH] Hoist proto_version load. Before this commit, we loaded a closure's `proto_version` on every iteration of the loop, which leads to a guard in every opcode in a trace. This commit hoists that load out to the only point where that value can change -- the `startfunc`/`return` label(s). These are where a new closure is dealt with (e.g. as a result of `OP_CALL`). Although we still have to call `yk_promote` for every opcode, the trace optimiser has a much easier job, because this tends to stay in a variable -- in general it can now remove 1 guard for all but the first opcode. Across several benchmarks I've looked at, this leads to a 2-6% increase. --- src/lvm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lvm.c b/src/lvm.c index 48ed281..382a66f 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1183,7 +1183,7 @@ Instruction load_inst(uint64_t pv, const Instruction *pc) { updatebase(ci); /* correct stack */ \ } \ pc = (Instruction *) yk_promote((void *) pc); \ - uint64_t pv = yk_promote(cl->p->proto_version); \ + uint64_t pv = yk_promote(cl_proto_version); \ i = load_inst(pv, pc); \ pc++; \ } @@ -1215,6 +1215,9 @@ void luaV_execute (lua_State *L, CallInfo *ci) { trap = L->hookmask; returning: /* trap already set */ cl = clLvalue(s2v(ci->func.p)); +#ifdef USE_YK + uint64_t cl_proto_version = cl->p->proto_version; +#endif k = cl->p->k; pc = ci->u.l.savedpc; if (l_unlikely(trap)) {