diff --git a/src/lfunc.c b/src/lfunc.c index 39c745b..7605f4a 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -22,6 +22,9 @@ #include "lobject.h" #include "lstate.h" +#ifdef USE_YK +uint64_t global_proto_version = 0; +#endif CClosure *luaF_newCclosure (lua_State *L, int nupvals) { @@ -263,12 +266,16 @@ Proto *luaF_newproto (lua_State *L) { #ifdef USE_YK f->yklocs = NULL; f->sizeyklocs = 0; + f->proto_version = global_proto_version; #endif return f; } void luaF_freeproto (lua_State *L, Proto *f) { +#ifdef USE_YK + global_proto_version++; +#endif luaM_freearray(L, f->code, f->sizecode); luaM_freearray(L, f->p, f->sizep); luaM_freearray(L, f->k, f->sizek); diff --git a/src/lfunc.h b/src/lfunc.h index 3be265e..b9e4e55 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -10,6 +10,13 @@ #include "lobject.h" +#ifdef USE_YK +// Every time a function is deleted, we crank this integer. Thus if two +// `Proto`s are allocated -- at different times! -- at the same address, the +// idempotent `load_inst` function won't consider them to be the same function. +extern uint64_t global_proto_version; +#endif + #define sizeCclosure(n) (cast_int(offsetof(CClosure, upvalue)) + \ cast_int(sizeof(TValue)) * (n)) diff --git a/src/lobject.h b/src/lobject.h index 3be814d..f994b0b 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -571,6 +571,7 @@ typedef struct Proto { #ifdef USE_YK YkLocation *yklocs; /* One 'YkLocation' per instruction in 'code' */ int sizeyklocs; /* size of 'yklocs' */ + uint64_t proto_version; /* What 'Proto Version' was this created under? */ #endif struct Proto **p; /* functions defined inside the function */ Upvaldesc *upvalues; /* upvalue information */ diff --git a/src/lvm.c b/src/lvm.c index 6a1d8e1..0d8646f 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1169,12 +1169,14 @@ void luaV_finishOp (lua_State *L) { /* fetch an instruction and prepare its execution */ #ifdef USE_YK +#define NOOPT_VAL(X) asm volatile("" : "+r,m"(X) : : "memory"); // Elide instruction lookup. // // FIXME: return type should be `Instruction` not `uint64_t`. We only do this // because idempotent support isn't yet implemented for 32-bit return values. __attribute__((yk_idempotent)) -uint64_t yk_load_inst(const Instruction *pc) { +uint64_t load_inst(uint64_t pv, const Instruction *pc) { + NOOPT_VAL(pv); return *pc; } @@ -1184,7 +1186,8 @@ uint64_t yk_load_inst(const Instruction *pc) { updatebase(ci); /* correct stack */ \ } \ pc = (Instruction *) yk_promote((void *) pc); \ - i = (Instruction) yk_load_inst(pc); \ + uint64_t pv = yk_promote(cl->p->proto_version); \ + i = (Instruction) load_inst(pv, pc); \ pc++; \ } #else