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