From 93cdb9f80fa6a7e00de642a0b7d045226a60ec76 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Mon, 27 Dec 2021 13:29:59 +0100 Subject: [PATCH] :art: Use prepared bytecode --- include/instr.h | 3 +- include/vm.h | 6 +- src/emit/emit.c | 3 +- src/lib/array.c | 15 +- src/lib/instr.c | 16 ++- src/vm/vm.c | 359 +++++++++++++++++++++++++++++++++++++++++++++-- src/vm/vm_code.c | 12 +- 7 files changed, 383 insertions(+), 31 deletions(-) diff --git a/include/instr.h b/include/instr.h index e6192120..03a10109 100644 --- a/include/instr.h +++ b/include/instr.h @@ -33,8 +33,7 @@ struct Instr_ { }; void (*execute)(const VM_Shred shred, const Instr instr); }; -#define BYTECODE_SZ \ - ((2 * sizeof(unsigned)) + sizeof(struct Instr_) - SZ_INT * 2) +#define BYTECODE_SZ (SZ_INT * 4) ANN void free_instr(const Gwion, const Instr); INSTR(EOC); diff --git a/include/vm.h b/include/vm.h index c5ff5ac6..869559ec 100644 --- a/include/vm.h +++ b/include/vm.h @@ -26,6 +26,7 @@ struct VM_Code_ { struct M_Vector_ live_values; uint16_t stack_depth; uint16_t ref; + bool is_prepared; bool builtin; bool callback; bool is_memoize; @@ -122,7 +123,10 @@ vm_shred_exit(const VM_Shred shred) { } void free_vm_shred(const VM_Shred shred) __attribute__((hot, nonnull)); -ANN void vm_run(const VM *vm) __attribute__((hot)); +void vm_prepare(const VM *vm, m_bit*) __attribute__((hot)); +ANN static inline void vm_run(const VM *vm) { + vm_prepare(vm, NULL); +} ANEW VM * new_vm(MemPool, const bool); ANN void vm_lock(VM const *); ANN void vm_unlock(VM const *); diff --git a/src/emit/emit.c b/src/emit/emit.c index ea2ea831..22c2ff2a 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -2843,7 +2843,8 @@ ANN static void me_ret(MemoizeEmitter *me) { const Instr instr = emit_regpushmem(me->emit, me->fdef->base->ret_type->size, false); instr->m_val = (me->offset + SZ_INT) * 2; - emit_add_instr(me->emit, FuncReturn); +// emit_add_instr(me->emit, FuncReturn); +vector_add(&me->emit->code->stack_return, (vtype)emit_add_instr(me->emit, Goto)); } ANN static m_bool me_run(MemoizeEmitter *me, const m_uint pc) { diff --git a/src/lib/array.c b/src/lib/array.c index b26d4a27..2c5a9a89 100644 --- a/src/lib/array.c +++ b/src/lib/array.c @@ -373,27 +373,27 @@ static OP_EMIT(opem_array_access) { return exp ? emit_array_access(emit, info) : GW_ERROR; } -static m_bit map_byte[BYTECODE_SZ * 4]; +static m_bit map_byte[BYTECODE_SZ * 5]; static const struct VM_Code_ map_run_code = {.name = "map_run_code", .bytecode = map_byte}; -static m_bit compactmap_byte[BYTECODE_SZ * 4]; +static m_bit compactmap_byte[BYTECODE_SZ * 5]; static const struct VM_Code_ compactmap_run_code = { .name = "compactmap_run_code", .bytecode = compactmap_byte}; -static m_bit filter_byte[BYTECODE_SZ * 4]; +static m_bit filter_byte[BYTECODE_SZ * 5]; static const struct VM_Code_ filter_run_code = {.name = "filter_run_code", .bytecode = filter_byte}; -static m_bit count_byte[BYTECODE_SZ * 4]; +static m_bit count_byte[BYTECODE_SZ * 5]; static const struct VM_Code_ count_run_code = {.name = "count_run_code", .bytecode = count_byte}; -static m_bit foldl_byte[BYTECODE_SZ * 4]; +static m_bit foldl_byte[BYTECODE_SZ * 5]; static const struct VM_Code_ foldl_run_code = {.name = "foldl_run_code", .bytecode = foldl_byte}; -static m_bit foldr_byte[BYTECODE_SZ * 4]; +static m_bit foldr_byte[BYTECODE_SZ * 5]; static const struct VM_Code_ foldr_run_code = {.name = "foldr_run_code", .bytecode = foldr_byte}; @@ -779,14 +779,17 @@ ANN static void prepare_run(m_bit *const byte, const f_instr ini, *(unsigned *)(byte + BYTECODE_SZ * 2) = eOverflow; *(unsigned *)(byte + BYTECODE_SZ * 3) = eOP_MAX; *(f_instr *)(byte + BYTECODE_SZ * 3 + SZ_INT * 2) = end; + *(unsigned *)(byte + BYTECODE_SZ * 4) = eEOC; } ANN static void prepare_map_run(m_bit *const byte, const f_instr end) { prepare_run(byte, map_run_ini, end); + vm_prepare(NULL, byte); } ANN static void prepare_fold_run(m_bit *const byte, const f_instr ini) { prepare_run(byte, ini, fold_run_end); + vm_prepare(NULL, byte); } GWION_IMPORT(array) { diff --git a/src/lib/instr.c b/src/lib/instr.c index 7d32b2dd..7af2fd00 100644 --- a/src/lib/instr.c +++ b/src/lib/instr.c @@ -122,17 +122,21 @@ INSTR(DotTmpl) { #define FVAL (*(m_float *)(byte + SZ_INT)) #define VAL2 (*(m_uint *)(byte + SZ_INT * 2)) #define BYTE(a) \ - m_bit *byte = shred->code->bytecode + (shred->pc - 1) * SZ_INT * 3; \ - *(m_bit *)byte = a; + m_bit *byte = shred->code->bytecode + (shred->pc - 1) * BYTECODE_SZ; \ + *(m_uint *)byte = a; INSTR(SetFunc) { - BYTE(eRegPushImm) +// BYTE(eRegPushImm) + m_bit *byte = shred->code->bytecode + (shred->pc - 1) * BYTECODE_SZ; \ + *(m_uint *)byte = instr->opcode; + instr->opcode = eRegPushImm; const Func f = (Func)instr->m_val; VAL = *(m_uint *)(shred->reg) = (m_uint)f->code; shred->reg += SZ_INT; } INSTR(SetRecurs) { +exit(4); BYTE(eRegPushImm) VAL = *(m_uint *)(shred->reg) = (m_uint)shred->code; shred->reg += SZ_INT; @@ -146,8 +150,12 @@ INSTR(SetCtor) { } INSTR(fast_except) { +puts("here!!!!!!!!!!!!!!"); if(*(m_uint*)REG((m_int)instr->m_val)) { - BYTE(eNoOp) +// BYTE(eNoOp) + m_bit *byte = shred->code->bytecode + (shred->pc - 1) * BYTECODE_SZ; \ + *(m_uint *)byte = instr->opcode; + instr->opcode = eNoOp; } else handle(shred, "NullPtrException"); } diff --git a/src/vm/vm.c b/src/vm/vm.c index 507dfab0..39097406 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -276,14 +276,15 @@ ANN static VM_Shred init_fork_shred(const VM_Shred shred, const VM_Code code, #define handle(a, b) VM_OUT handle(a, b); #define TEST0(t, pos) \ if (!*(t *)(reg - pos)) { \ -/* shred->pc = PC;*/ \ handle(shred, "ZeroDivideException"); \ break; \ } -#define ADVANCE() byte += BYTECODE_SZ; +#define ADVANCE() { byte += BYTECODE_SZ; shred->pc++;} +//#define ADVANCE() byte += BYTECODE_SZ -#define SDISPATCH() goto *dispatch[*(m_bit *)byte]; +//#define SDISPATCH() goto *dispatch[*(m_bit *)byte]; +#define SDISPATCH() goto **(void***)byte; #define IDISPATCH() \ { \ VM_INFO; \ @@ -292,23 +293,23 @@ ANN static VM_Shred init_fork_shred(const VM_Shred shred, const VM_Code code, #define SET_BYTE(pc) (byte = bytecode + (pc)*BYTECODE_SZ) -#define PC_DISPATCH(pc) \ - SET_BYTE((pc)); \ +#define PC_DISPATCH(_pc) \ + SET_BYTE((_pc)); \ +/* shred->pc = _pc + 1;*/\ IDISPATCH(); #define DISPATCH() \ ADVANCE(); \ IDISPATCH(); -#define ADVANCE() byte += BYTECODE_SZ; - #define ADISPATCH() \ { \ ADVANCE(); \ SDISPATCH(); \ } -#define PC (*(unsigned *)(byte + 1)) +#define PC (*(m_uint *)(byte + SZ_INT*3)) +//#define PC (shred->pc) #define OP(t, sz, op, ...) \ reg -= sz; \ @@ -426,9 +427,10 @@ _Pragma(STRINGIFY(COMPILER diagnostic ignored UNINITIALIZED) #define SVAL2 (*(uint16_t *)(byte + SZ_INT + SZ_INT + sizeof(uint16_t))) #define BRANCH_DISPATCH(check) \ - if (check) \ + if (check) { \ SET_BYTE(VAL); \ - else \ + shred->pc = VAL + 1;\ + } else \ ADVANCE(); \ IDISPATCH(); @@ -438,8 +440,8 @@ _Pragma(STRINGIFY(COMPILER diagnostic ignored UNINITIALIZED) shred->mem = mem; \ shred->pc = PC; -__attribute__((hot)) ANN void -vm_run(const VM *vm) { // lgtm [cpp/use-of-goto] +__attribute__((hot)) void +vm_prepare(const VM *vm, m_bit *prepare_code) { // lgtm [cpp/use-of-goto] static const void *dispatch[] = { &®setimm, &®pushimm, &®pushfloat, &®pushother, &®pushaddr, &®pushmem, &®pushmemfloat, &®pushmemother, &®pushmemaddr, @@ -488,10 +490,14 @@ vm_run(const VM *vm) { // lgtm [cpp/use-of-goto] &&try_end, &&handleeffect, &&performeffect, &&noop, &&debugline, &&debugvalue, &&debugpush, &&debugpop, &&eoc, &&unroll2, &&other, &®pushimm}; +// const Shreduler s = vm->shreduler; +// register VM_Shred shred; +// register m_bit next; + + if(!prepare_code) { const Shreduler s = vm->shreduler; register VM_Shred shred; register m_bit next; - while ((shred = shreduler_get(s))) { register VM_Code code = shred->code; register m_bit * bytecode = code->bytecode; @@ -943,7 +949,6 @@ vm_run(const VM *vm) { // lgtm [cpp/use-of-goto] DISPATCH() overflow: if (overflow_(mem + VAL2, shred)) { -// shred->pc = PC; handle(shred, "StackOverflow"); continue; } @@ -1289,6 +1294,332 @@ vm_run(const VM *vm) { // lgtm [cpp/use-of-goto] } while (s->curr); // MUTEX_UNLOCK(s->mutex); } +//} +} else { +//exit(3); +//return; +static void *_dispatch[] = { + &&_regsetimm, &&_regpushimm, &&_regpushfloat, &&_regpushother, &&_regpushaddr, + &&_regpushmem, &&_regpushmemfloat, &&_regpushmemother, &&_regpushmemaddr, + &&_regpushmemderef, &&_pushnow, &&_baseint, &&_basefloat, &&_baseother, + &&_baseaddr, &&_regtoreg, &&_regtoregother, &&_regtoregother2, &&_regtoregaddr, &&_regtoregderef, + &&_structmember, &&_structmemberfloat, &&_structmemberother, + &&_structmemberaddr, &&_memsetimm, &&_memaddimm, &&_repeatidx, &&_repeat, + &&_regpushme, &&_regpushmaybe, &&_funcreturn, &&__goto, &&_allocint, + &&_allocfloat, &&_allocother, + &&_intplus, &&_intminus, &&_intmul, &&_intdiv, &&_intmod, + &&_intplusimm, &&_intminusimm, &&_intmulimm, &&_intdivimm, &&_intmodimm, + // int relationnal + &&_inteq, &&_intne, &&_intand, &&_intor, + &&_intgt, &&_intge, &&_intlt, &&_intle, + &&_intgtimm, &&_intgeimm, &&_intltimm, &&_intleimm, + &&_intsl, &&_intsr, &&_intsand, &&_intsor, &&_intxor, &&_intnegate, &&_intnot, + &&_intcmp, &&_intrassign, &&_intradd, &&_intrsub, &&_intrmul, &&_intrdiv, + &&_intrmod, &&_intrsl, &&_intrsr, &&_intrsand, &&_intrsor, &&_intrxor, &&_preinc, + &&_predec, &&_postinc, &&_postdec, + &&_floatadd, &&_floatsub, &&_floatmul, &&_floatdiv, + &&_floataddimm, &&_floatsubimm, &&_floatmulimm, &&_floatdivimm, + // logical + &&_floatand, &&_floator, &&_floateq, &&_floatne, + &&_floatgt, &&_floatge, &&_floatlt, &&_floatle, + &&_floatgtimm, &&_floatgeimm, &&_floatltimm, &&_floatleimm, + &&_floatneg, &&_floatnot, &&_floatrassign, &&_floatradd, + &&_floatrsub, &&_floatrmul, &&_floatrdiv, &&_ifadd, &&_ifsub, &&_ifmul, &&_ifdiv, + &&_ifand, &&_ifor, &&_ifeq, &&_ifne, &&_ifgt, &&_ifge, &&_iflt, &&_ifle, + &&_ifrassign, &&_ifradd, &&_ifrsub, &&_ifrmul, &&_ifrdiv, &&_fiadd, &&_fisub, + &&_fimul, &&_fidiv, &&_fiand, &&_fior, &&_fieq, &&_fine, &&_figt, &&_fige, &&_filt, + &&_file, &&_firassign, &&_firadd, &&_firsub, &&_firmul, &&_firdiv, &&_itof, + &&_ftoi, &&_timeadv, &&_recurs, &&_setcode, &&_regmove, + &&_regtomem, &&_regtomemother, + &&_overflow, + &&_funcusrend, &&_funcusrend2, &&_funcmemberend, + &&_sporkini, &&_forkini, &&_sporkfunc, &&_sporkmemberfptr, &&_sporkexp, + &&_sporkend, &&_brancheqint, &&_branchneint, &&_brancheqfloat, + &&_branchnefloat, &&_unroll, &&_arrayappend, &&_autounrollinit, &&_autoloop, + &&_arraytop, &&_arrayaccess, &&_arrayget, &&_arrayaddr, &&_newobj, &&_addref, + &&_addrefaddr, &&_structaddref, &&_structaddrefaddr, &&_objassign, &&_assign, + &&_remref, &&_remref2, &&_except, &&_allocmemberaddr, &&_dotmember, &&_dotfloat, + &&_dotother, &&_dotaddr, &&_unioncheck, &&_unionint, &&_unionfloat, + &&_unionother, &&_unionaddr, &&_staticint, &&_staticfloat, &&_staticother, + &&_upvalueint, &&_upvaluefloat, &&_upvalueother, &&_upvalueaddr, &&_dotfunc, + &&_gacktype, &&_gackend, &&_gack, &&_try_ini, + &&_try_end, &&_handleeffect, &&_performeffect, &&_noop, &&_debugline, + &&_debugvalue, &&_debugpush, &&_debugpop, &&_eoc, &&_unroll2, &&_other, + &&_regpushimm}; + +#define PREPARE(a) \ +_##a: \ + *(void**)prepare_code = &&a;\ +prepare_code += BYTECODE_SZ;\ +goto *_dispatch[*(m_bit*)prepare_code]; + +goto *_dispatch[*(m_bit*)prepare_code]; + PREPARE(regsetimm); + PREPARE(regpushimm); + PREPARE(regpushfloat); + PREPARE(regpushother); + PREPARE(regpushaddr); + PREPARE(regpushmem); + PREPARE(regpushmemfloat); + PREPARE(regpushmemother); + PREPARE(regpushmemaddr); + PREPARE(regpushmemderef); + PREPARE(pushnow); + PREPARE(baseint); + PREPARE(basefloat); + PREPARE(baseother); + PREPARE(baseaddr); + PREPARE(regtoreg); + PREPARE(regtoregother); + PREPARE(regtoregother2); + PREPARE(regtoregaddr); + PREPARE(regtoregderef); + PREPARE(structmember); + PREPARE(structmemberfloat); + PREPARE(structmemberother); + PREPARE(structmemberaddr) + PREPARE(memsetimm); + PREPARE(memaddimm); + PREPARE(repeatidx); + PREPARE(repeat); + PREPARE(regpushme); + PREPARE(regpushmaybe); +// PREPARE(funcreturn); +_funcreturn: + *(void**)prepare_code = &&funcreturn; +return; + + PREPARE(_goto); + PREPARE(allocint); + PREPARE(allocfloat); + PREPARE(allocother) + PREPARE(intplus); + PREPARE(intminus); + PREPARE(intmul); + PREPARE(intdiv); + PREPARE(intmod); + PREPARE(intplusimm); + PREPARE(intminusimm); + PREPARE(intmulimm); + PREPARE(intdivimm); + PREPARE(intmodimm); + + PREPARE(inteq); + PREPARE(intne); + PREPARE(intand); + PREPARE(intor); + PREPARE(intgt); + PREPARE(intge); + PREPARE(intlt); + PREPARE(intle); + PREPARE(intgtimm); + PREPARE(intgeimm); + PREPARE(intltimm); + PREPARE(intleimm); + PREPARE(intsl); + PREPARE(intsr); + PREPARE(intsand); + PREPARE(intsor); + PREPARE(intxor); + + PREPARE(intnegate); + PREPARE(intnot); + PREPARE(intcmp); + + PREPARE(intrassign); + + PREPARE(intradd); + PREPARE(intrsub); + PREPARE(intrmul); + PREPARE(intrdiv); + PREPARE(intrmod); + PREPARE(intrsl); + PREPARE(intrsr); + PREPARE(intrsand); + PREPARE(intrsor); + PREPARE(intrxor) + + PREPARE(preinc); + PREPARE(predec); + PREPARE(postinc); + PREPARE(postdec); + + PREPARE(floatadd); + PREPARE(floatsub); + PREPARE(floatmul); + PREPARE(floatdiv); + PREPARE(floataddimm); + PREPARE(floatsubimm); + PREPARE(floatmulimm); + PREPARE(floatdivimm); + + PREPARE(floatand); + PREPARE(floator); + PREPARE(floateq); + PREPARE(floatne); + PREPARE(floatgt); + PREPARE(floatge); + PREPARE(floatlt); + PREPARE(floatle); + PREPARE(floatgtimm); + PREPARE(floatgeimm); + PREPARE(floatltimm); + PREPARE(floatleimm); + + PREPARE(floatneg); + PREPARE(floatnot); + + PREPARE(floatrassign); + + PREPARE(floatradd); + PREPARE(floatrsub); + PREPARE(floatrmul); + PREPARE(floatrdiv); + + PREPARE(ifadd); + PREPARE(ifsub); + PREPARE(ifmul); + PREPARE(ifdiv); + + PREPARE(ifand); + PREPARE(ifor); + PREPARE(ifeq); + PREPARE(ifne); + PREPARE(ifgt); + PREPARE(ifge); + PREPARE(iflt); + PREPARE(ifle); + + PREPARE(ifrassign); + PREPARE(ifradd); + PREPARE(ifrsub); + PREPARE(ifrmul); + PREPARE(ifrdiv); + + PREPARE(fiadd); + PREPARE(fisub); + PREPARE(fimul); + PREPARE(fidiv); + + PREPARE(fiand); + PREPARE(fior); + PREPARE(fieq); + PREPARE(fine); + PREPARE(figt); + PREPARE(fige); + PREPARE(filt); + PREPARE(file); + + PREPARE(firassign); + + PREPARE(firadd); + PREPARE(firsub); + PREPARE(firmul); + PREPARE(firdiv); + + PREPARE(itof); + PREPARE(ftoi); + + PREPARE(timeadv); + + PREPARE(recurs); + + PREPARE(setcode); + PREPARE(regmove); + PREPARE(regtomem); + PREPARE(regtomemother); + PREPARE(overflow); + PREPARE(funcusrend); + PREPARE(funcusrend2); + PREPARE(funcmemberend); + PREPARE(sporkini); + PREPARE(forkini); + PREPARE(sporkfunc); + PREPARE(sporkmemberfptr); + PREPARE(sporkexp); + PREPARE(sporkend); + PREPARE(brancheqint); + PREPARE(branchneint); + PREPARE(brancheqfloat); + PREPARE(branchnefloat); + PREPARE(unroll); + PREPARE(arrayappend); + PREPARE(autounrollinit); + PREPARE(autoloop); + PREPARE(arraytop); + PREPARE(arrayaccess); + PREPARE(arrayget); + PREPARE(arrayaddr); + PREPARE(newobj); + PREPARE(addref); + PREPARE(addrefaddr); + PREPARE(structaddref); + PREPARE(structaddrefaddr); + PREPARE(objassign); + PREPARE(assign); + PREPARE(remref); + PREPARE(remref2); + PREPARE(except); + PREPARE(allocmemberaddr); + PREPARE(dotmember); + PREPARE(dotfloat); + PREPARE(dotother); + PREPARE(dotaddr); + PREPARE(unioncheck); + PREPARE(unionint); + PREPARE(unionfloat); + PREPARE(unionother); + PREPARE(unionaddr); + PREPARE(staticint); + PREPARE(staticfloat); + PREPARE(staticother); + PREPARE(upvalueint); + PREPARE(upvaluefloat); + PREPARE(upvalueother); + PREPARE(upvalueaddr); + PREPARE(dotfunc); + PREPARE(gacktype); + PREPARE(gackend); + PREPARE(gack); + PREPARE(try_ini); + PREPARE(try_end); + PREPARE(handleeffect); + PREPARE(performeffect); + PREPARE(noop); +// PREPARE(other); +_other: + *(void**)prepare_code = &&other; +if(*(void**)(prepare_code + SZ_INT *2) == DTOR_EOC)return; +if(*(void**)(prepare_code + SZ_INT *2) == fast_except) { +// find the instr +// set instr opcode to addr +const Instr instr = *(Instr*)(prepare_code + SZ_INT); +instr->opcode = (m_uint)&&noop; +//*(void**)(prepare_code +//exit(3); +} +if(*(void**)(prepare_code + SZ_INT *2) == SetFunc) { +// find the instr +// set instr opcode to addr +const Instr instr = *(Instr*)(prepare_code + SZ_INT); +instr->opcode = (m_uint)&®pushimm; +//*(void**)(prepare_code +//exit(3); +} +//return; +prepare_code += BYTECODE_SZ;\ +goto *_dispatch[*(m_bit*)prepare_code]; + + PREPARE(unroll2); + PREPARE(debugline); + PREPARE(debugvalue); + PREPARE(debugpush); + PREPARE(debugpop); +// PREPARE(eoc); +_eoc: + *(void**)prepare_code = &&eoc; +return; +} } // remove me diff --git a/src/vm/vm_code.c b/src/vm/vm_code.c index 1f8906b6..ae8a41ed 100644 --- a/src/vm/vm_code.c +++ b/src/vm/vm_code.c @@ -53,7 +53,7 @@ static inline uint isgoto(const unsigned opcode) { } ANN static inline void setpc(const m_bit *data, const m_uint i) { - *(unsigned *)(data + 1) = i + 1; + *(m_uint *)(data + SZ_INT*3) = i + 1; } ANN static m_bit *tobytecode(MemPool p, const VM_Code code) { @@ -78,7 +78,11 @@ ANN static m_bit *tobytecode(MemPool p, const VM_Code code) { next->opcode = eNoOp; } if ((instr->m_val = move)) { +// *(m_uint*)data = instr->opcode; +// memcpy(data, instr, SZ_INT); +// memcpy(data + SZ_INT*2, instr + SZ_INT, SZ_INT*2); memcpy(data, instr, BYTECODE_SZ); + setpc(data, i); } else { vector_add(&nop, i); @@ -108,9 +112,9 @@ ANN static m_bit *tobytecode(MemPool p, const VM_Code code) { if (instr->opcode == eGoto && instr->m_val == i + 1) { instr->opcode = eNoOp; vector_add(&nop, i); - } else if (instr->opcode != eNoOp) + } else if (instr->opcode != eNoOp) { memcpy(data, instr, BYTECODE_SZ); - else + } else vector_add(&nop, i); } else { *(m_bit *)(data) = instr->opcode; @@ -121,6 +125,7 @@ ANN static m_bit *tobytecode(MemPool p, const VM_Code code) { } if (!vector_size(&nop)) { vector_release(&nop); + vm_prepare(NULL, ptr); return ptr; } m_bit *const final = @@ -154,6 +159,7 @@ ANN static m_bit *tobytecode(MemPool p, const VM_Code code) { } vector_release(&nop); mp_free2(p, sz * BYTECODE_SZ, ptr); + vm_prepare(NULL, final); return final; } -- 2.43.0