From: Mike Pall Date: Mon, 10 Nov 2025 17:11:26 +0000 (+0100) Subject: Run VM events and finalizers in separate state. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5c647754a687a910ef40a097fbf8f7415561c8aa;p=thirdparty%2FLuaJIT.git Run VM events and finalizers in separate state. Reported by Sergey Kaplun. #1403 --- diff --git a/src/lj_gc.c b/src/lj_gc.c index d9581d20..c779d583 100644 --- a/src/lj_gc.c +++ b/src/lj_gc.c @@ -106,6 +106,7 @@ static void gc_mark_start(global_State *g) setgcrefnull(g->gc.weak); gc_markobj(g, mainthread(g)); gc_markobj(g, tabref(mainthread(g)->env)); + gc_markobj(g, vmthread(g)); gc_marktv(g, &g->registrytv); gc_mark_gcroot(g); g->gc.state = GCSpropagate; @@ -507,24 +508,25 @@ static void gc_call_finalizer(global_State *g, lua_State *L, uint8_t oldh = hook_save(g); GCSize oldt = g->gc.threshold; int errcode; + lua_State *VL = vmthread(g); TValue *top; lj_trace_abort(g); hook_entergc(g); /* Disable hooks and new traces during __gc. */ if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g); g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */ - top = L->top; - copyTV(L, top++, mo); + top = VL->top; + copyTV(VL, top++, mo); if (LJ_FR2) setnilV(top++); - setgcV(L, top, o, ~o->gch.gct); - L->top = top+1; - errcode = lj_vm_pcall(L, top, 1+0, -1); /* Stack: |mo|o| -> | */ + setgcV(VL, top, o, ~o->gch.gct); + VL->top = top+1; + errcode = lj_vm_pcall(VL, top, 1+0, -1); /* Stack: |mo|o| -> | */ + setgcref(g->cur_L, obj2gco(L)); hook_restore(g, oldh); if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g); g->gc.threshold = oldt; /* Restore GC threshold. */ if (errcode) { - ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ - lj_vmevent_send(L, ERRFIN, - copyTV(L, L->top++, restorestack(L, errobj)); + lj_vmevent_send(g, ERRFIN, + copyTV(V, V->top++, L->top-1); ); L->top--; } diff --git a/src/lj_obj.h b/src/lj_obj.h index 855727bf..73b186e2 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h @@ -647,6 +647,7 @@ typedef struct global_State { TValue tmptv, tmptv2; /* Temporary TValues. */ Node nilnode; /* Fallback 1-element hash part (nil key and value). */ TValue registrytv; /* Anchor for registry. */ + GCRef vmthref; /* Link to VM thread. */ GCupval uvhead; /* Head of double-linked list of all open upvalues. */ int32_t hookcount; /* Instruction hook countdown. */ int32_t hookcstart; /* Start count for instruction hook counter. */ @@ -663,6 +664,7 @@ typedef struct global_State { } global_State; #define mainthread(g) (&gcref(g->mainthref)->th) +#define vmthread(g) (&gcref(g->vmthref)->th) #define niltv(L) \ check_exp(tvisnil(&G(L)->nilnode.val), &G(L)->nilnode.val) #define niltvg(g) \ diff --git a/src/lj_parse.c b/src/lj_parse.c index e326432a..181ce4d7 100644 --- a/src/lj_parse.c +++ b/src/lj_parse.c @@ -1593,8 +1593,8 @@ static GCproto *fs_finish(LexState *ls, BCLine line) fs_fixup_line(fs, pt, (void *)((char *)pt + ofsli), numline); fs_fixup_var(ls, pt, (uint8_t *)((char *)pt + ofsdbg), ofsvar); - lj_vmevent_send(L, BC, - setprotoV(L, L->top++, pt); + lj_vmevent_send(G(L), BC, + setprotoV(V, V->top++, pt); ); L->top--; /* Pop table of constants. */ diff --git a/src/lj_state.c b/src/lj_state.c index fb6d41a5..9d4fdcee 100644 --- a/src/lj_state.c +++ b/src/lj_state.c @@ -202,6 +202,7 @@ static TValue *cpluaopen(lua_State *L, lua_CFunction dummy, void *ud) #endif lj_trace_initstate(g); lj_err_verify(); + setgcref(g->vmthref, obj2gco(lj_state_new(L))); return NULL; } diff --git a/src/lj_trace.c b/src/lj_trace.c index 3e2cd0b3..47d7faa5 100644 --- a/src/lj_trace.c +++ b/src/lj_trace.c @@ -296,8 +296,8 @@ int lj_trace_flushall(lua_State *L) /* Free the whole machine code and invalidate all exit stub groups. */ lj_mcode_free(J); memset(J->exitstubgroup, 0, sizeof(J->exitstubgroup)); - lj_vmevent_send(L, TRACE, - setstrV(L, L->top++, lj_str_newlit(L, "flush")); + lj_vmevent_send(J2G(J), TRACE, + setstrV(V, V->top++, lj_str_newlit(V, "flush")); ); return 0; } @@ -416,7 +416,6 @@ setpenalty: /* Start tracing. */ static void trace_start(jit_State *J) { - lua_State *L; TraceNo traceno; if ((J->pt->flags & PROTO_NOJIT)) { /* JIT disabled for this proto? */ @@ -466,20 +465,19 @@ static void trace_start(jit_State *J) J->ktrace = 0; setgcref(J->cur.startpt, obj2gco(J->pt)); - L = J->L; - lj_vmevent_send(L, TRACE, - setstrV(L, L->top++, lj_str_newlit(L, "start")); - setintV(L->top++, traceno); - setfuncV(L, L->top++, J->fn); - setintV(L->top++, proto_bcpos(J->pt, J->pc)); + lj_vmevent_send(J2G(J), TRACE, + setstrV(V, V->top++, lj_str_newlit(V, "start")); + setintV(V->top++, traceno); + setfuncV(V, V->top++, J->fn); + setintV(V->top++, proto_bcpos(J->pt, J->pc)); if (J->parent) { - setintV(L->top++, J->parent); - setintV(L->top++, J->exitno); + setintV(V->top++, J->parent); + setintV(V->top++, J->exitno); } else { BCOp op = bc_op(*J->pc); if (op == BC_CALLM || op == BC_CALL || op == BC_ITERC) { - setintV(L->top++, J->exitno); /* Parent of stitched trace. */ - setintV(L->top++, -1); + setintV(V->top++, J->exitno); /* Parent of stitched trace. */ + setintV(V->top++, -1); } } ); @@ -494,7 +492,6 @@ static void trace_stop(jit_State *J) GCproto *pt = &gcref(J->cur.startpt)->pt; TraceNo traceno = J->cur.traceno; GCtrace *T = J->curfinal; - lua_State *L; switch (op) { case BC_FORL: @@ -551,11 +548,10 @@ static void trace_stop(jit_State *J) J->postproc = LJ_POST_NONE; trace_save(J, T); - L = J->L; - lj_vmevent_send(L, TRACE, - setstrV(L, L->top++, lj_str_newlit(L, "stop")); - setintV(L->top++, traceno); - setfuncV(L, L->top++, J->fn); + lj_vmevent_send(J2G(J), TRACE, + setstrV(V, V->top++, lj_str_newlit(V, "stop")); + setintV(V->top++, traceno); + setfuncV(V, V->top++, J->fn); ); } @@ -610,18 +606,17 @@ static int trace_abort(jit_State *J) /* Is there anything to abort? */ traceno = J->cur.traceno; if (traceno) { - ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ J->cur.link = 0; J->cur.linktype = LJ_TRLINK_NONE; - lj_vmevent_send(L, TRACE, + lj_vmevent_send(J2G(J), TRACE, cTValue *bot = tvref(L->stack)+LJ_FR2; cTValue *frame; const BCIns *pc; BCPos pos = 0; - setstrV(L, L->top++, lj_str_newlit(L, "abort")); - setintV(L->top++, traceno); + setstrV(V, V->top++, lj_str_newlit(V, "abort")); + setintV(V->top++, traceno); /* Find original Lua function call to generate a better error message. */ - for (frame = J->L->base-1, pc = J->pc; ; frame = frame_prev(frame)) { + for (frame = L->base-1, pc = J->pc; ; frame = frame_prev(frame)) { if (isluafunc(frame_func(frame))) { pos = proto_bcpos(funcproto(frame_func(frame)), pc); break; @@ -633,10 +628,10 @@ static int trace_abort(jit_State *J) pc = frame_pc(frame) - 1; } } - setfuncV(L, L->top++, frame_func(frame)); - setintV(L->top++, pos); - copyTV(L, L->top++, restorestack(L, errobj)); - copyTV(L, L->top++, &J->errinfo); + setfuncV(V, V->top++, frame_func(frame)); + setintV(V->top++, pos); + copyTV(V, V->top++, L->top-1); + copyTV(V, V->top++, &J->errinfo); ); /* Drop aborted trace after the vmevent (which may still access it). */ setgcrefnull(J->trace[traceno]); @@ -692,16 +687,16 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud) case LJ_TRACE_RECORD: trace_pendpatch(J, 0); setvmstate(J2G(J), RECORD); - lj_vmevent_send_(L, RECORD, + lj_vmevent_send_(J2G(J), RECORD, /* Save/restore state for trace recorder. */ TValue savetv = J2G(J)->tmptv; TValue savetv2 = J2G(J)->tmptv2; TraceNo parent = J->parent; ExitNo exitno = J->exitno; - setintV(L->top++, J->cur.traceno); - setfuncV(L, L->top++, J->fn); - setintV(L->top++, J->pt ? (int32_t)proto_bcpos(J->pt, J->pc) : -1); - setintV(L->top++, J->framedepth); + setintV(V->top++, J->cur.traceno); + setfuncV(V, V->top++, J->fn); + setintV(V->top++, J->pt ? (int32_t)proto_bcpos(J->pt, J->pc) : -1); + setintV(V->top++, J->framedepth); , J2G(J)->tmptv = savetv; J2G(J)->tmptv2 = savetv2; @@ -839,23 +834,23 @@ static TValue *trace_exit_cp(lua_State *L, lua_CFunction dummy, void *ud) #ifndef LUAJIT_DISABLE_VMEVENT /* Push all registers from exit state. */ -static void trace_exit_regs(lua_State *L, ExitState *ex) +static void trace_exit_regs(lua_State *V, ExitState *ex) { int32_t i; - setintV(L->top++, RID_NUM_GPR); - setintV(L->top++, RID_NUM_FPR); + setintV(V->top++, RID_NUM_GPR); + setintV(V->top++, RID_NUM_FPR); for (i = 0; i < RID_NUM_GPR; i++) { if (sizeof(ex->gpr[i]) == sizeof(int32_t)) - setintV(L->top++, (int32_t)ex->gpr[i]); + setintV(V->top++, (int32_t)ex->gpr[i]); else - setnumV(L->top++, (lua_Number)ex->gpr[i]); + setnumV(V->top++, (lua_Number)ex->gpr[i]); } #if !LJ_SOFTFP for (i = 0; i < RID_NUM_FPR; i++) { - setnumV(L->top, ex->fpr[i]); - if (LJ_UNLIKELY(tvisnan(L->top))) - setnanV(L->top); - L->top++; + setnumV(V->top, ex->fpr[i]); + if (LJ_UNLIKELY(tvisnan(V->top))) + setnanV(V->top); + V->top++; } #endif } @@ -897,6 +892,8 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr) #ifdef EXITSTATE_PCREG J->parent = trace_exit_find(J, (MCode *)(intptr_t)ex->gpr[EXITSTATE_PCREG]); +#else + UNUSED(ex); #endif T = traceref(J, J->parent); UNUSED(T); #ifdef EXITSTATE_CHECKEXIT @@ -917,11 +914,11 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr) if (exitcode) copyTV(L, L->top++, &exiterr); /* Anchor the error object. */ if (!(LJ_HASPROFILE && (G(L)->hookmask & HOOK_PROFILE))) - lj_vmevent_send(L, TEXIT, - lj_state_checkstack(L, 4+RID_NUM_GPR+RID_NUM_FPR+LUA_MINSTACK); - setintV(L->top++, J->parent); - setintV(L->top++, J->exitno); - trace_exit_regs(L, ex); + lj_vmevent_send(G(L), TEXIT, + lj_state_checkstack(V, 4+RID_NUM_GPR+RID_NUM_FPR+LUA_MINSTACK); + setintV(V->top++, J->parent); + setintV(V->top++, J->exitno); + trace_exit_regs(V, ex); ); pc = exd.pc; diff --git a/src/lj_vmevent.c b/src/lj_vmevent.c index 070c6144..8913ead9 100644 --- a/src/lj_vmevent.c +++ b/src/lj_vmevent.c @@ -38,6 +38,7 @@ ptrdiff_t lj_vmevent_prepare(lua_State *L, VMEvent ev) void lj_vmevent_call(lua_State *L, ptrdiff_t argbase) { global_State *g = G(L); + lua_State *oldL = gco2th(gcref(g->cur_L)); uint8_t oldmask = g->vmevmask; uint8_t oldh = hook_save(g); int status; @@ -51,6 +52,10 @@ void lj_vmevent_call(lua_State *L, ptrdiff_t argbase) fputs(tvisstr(L->top) ? strVdata(L->top) : "?", stderr); fputc('\n', stderr); } + setgcref(g->cur_L, obj2gco(oldL)); +#if LJ_HASJIT + G2J(g)->L = oldL; +#endif hook_restore(g, oldh); if (g->vmevmask != VMEVENT_NOCACHE) g->vmevmask = oldmask; /* Restore event mask, but not if not modified. */ diff --git a/src/lj_vmevent.h b/src/lj_vmevent.h index 8a995360..cdd4f758 100644 --- a/src/lj_vmevent.h +++ b/src/lj_vmevent.h @@ -32,23 +32,25 @@ typedef enum { } VMEvent; #ifdef LUAJIT_DISABLE_VMEVENT -#define lj_vmevent_send(L, ev, args) UNUSED(L) -#define lj_vmevent_send_(L, ev, args, post) UNUSED(L) +#define lj_vmevent_send(g, ev, args) UNUSED(g) +#define lj_vmevent_send_(g, ev, args, post) UNUSED(g) #else -#define lj_vmevent_send(L, ev, args) \ - if (G(L)->vmevmask & VMEVENT_MASK(LJ_VMEVENT_##ev)) { \ - ptrdiff_t argbase = lj_vmevent_prepare(L, LJ_VMEVENT_##ev); \ +#define lj_vmevent_send(g, ev, args) \ + if ((g)->vmevmask & VMEVENT_MASK(LJ_VMEVENT_##ev)) { \ + lua_State *V = vmthread(g); \ + ptrdiff_t argbase = lj_vmevent_prepare(V, LJ_VMEVENT_##ev); \ if (argbase) { \ args \ - lj_vmevent_call(L, argbase); \ + lj_vmevent_call(V, argbase); \ } \ } -#define lj_vmevent_send_(L, ev, args, post) \ - if (G(L)->vmevmask & VMEVENT_MASK(LJ_VMEVENT_##ev)) { \ - ptrdiff_t argbase = lj_vmevent_prepare(L, LJ_VMEVENT_##ev); \ +#define lj_vmevent_send_(g, ev, args, post) \ + if ((g)->vmevmask & VMEVENT_MASK(LJ_VMEVENT_##ev)) { \ + lua_State *V = vmthread(g); \ + ptrdiff_t argbase = lj_vmevent_prepare(V, LJ_VMEVENT_##ev); \ if (argbase) { \ args \ - lj_vmevent_call(L, argbase); \ + lj_vmevent_call(V, argbase); \ post \ } \ }