Turn traces into true GC objects (GCtrace).

This commit is contained in:
Mike Pall 2010-04-25 03:32:29 +02:00
parent 3a32bbc7cb
commit 721b73fecb
24 changed files with 193 additions and 201 deletions

View File

@ -138,11 +138,11 @@ of a module to turn off JIT compilation for the whole module for
debugging purposes. debugging purposes.
</p> </p>
<h3 id="jit_flush_tr"><tt>status = jit.flush(tr)</tt></h3> <h3 id="jit_flush_tr"><tt>jit.flush(tr)</tt></h3>
<p> <p>
Tries to flush the code for the specified trace and all of its Flushes the specified root trace and all of its side traces from the cache.
side traces from the cache. Returns <tt>true</tt> on success. The code for the trace will be retained as long as there are any other
Returns <tt>false</tt> if there are still links to this trace. traces which link to it.
</p> </p>
<h3 id="jit_status"><tt>status, ... = jit.status()</tt></h3> <h3 id="jit_status"><tt>status, ... = jit.status()</tt></h3>
@ -262,8 +262,9 @@ applies recursively to all sub-functions of the function with
<h3 id="mode_engine"><tt>luaJIT_setmode(L, trace,<br> <h3 id="mode_engine"><tt>luaJIT_setmode(L, trace,<br>
&nbsp;&nbsp;LUAJIT_MODE_TRACE|LUAJIT_MODE_FLUSH)</tt></h3> &nbsp;&nbsp;LUAJIT_MODE_TRACE|LUAJIT_MODE_FLUSH)</tt></h3>
<p> <p>
Tries to flush the code for the specified trace and all of its Flushes the specified root trace and all of its side traces from the cache.
side traces from the cache. The code for the trace will be retained as long as there are any other
traces which link to it.
</p> </p>
<h3 id="mode_engine"><tt>luaJIT_setmode(L, idx, LUAJIT_MODE_WRAPCFUNC|flag)</tt></h3> <h3 id="mode_engine"><tt>luaJIT_setmode(L, idx, LUAJIT_MODE_WRAPCFUNC|flag)</tt></h3>

View File

@ -674,7 +674,7 @@ static const unsigned char build_actionlist[14075] = {
255,248,3,102,15,46,193,252,233,244,1,255,141,12,202,139,105,4,129,252,253, 255,248,3,102,15,46,193,252,233,244,1,255,141,12,202,139,105,4,129,252,253,
239,15,132,244,247,255,137,105,252,252,139,41,137,105,252,248,252,233,245, 239,15,132,244,247,255,137,105,252,252,139,41,137,105,252,248,252,233,245,
255,141,156,253,131,233,139,1,137,105,252,252,137,65,252,248,255,65,139,142, 255,141,156,253,131,233,139,1,137,105,252,252,137,65,252,248,255,65,139,142,
233,139,4,193,72,139,128,233,139,108,36,24,65,137,150,233,65,137,174,233, 233,139,4,129,72,139,128,233,139,108,36,24,65,137,150,233,65,137,174,233,
76,137,36,36,76,137,108,36,8,72,131,252,236,16,252,255,224,255,141,156,253, 76,137,36,36,76,137,108,36,8,72,131,252,236,16,252,255,224,255,141,156,253,
131,233,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252, 131,233,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,
238,255,137,221,209,252,237,129,229,239,102,65,131,172,253,46,233,1,15,132, 238,255,137,221,209,252,237,129,229,239,102,65,131,172,253,46,233,1,15,132,
@ -1048,7 +1048,7 @@ static const char *const extnames[] = {
#define DtA(_V) (int)(ptrdiff_t)&(((GCupval *)0)_V) #define DtA(_V) (int)(ptrdiff_t)&(((GCupval *)0)_V)
#define DtB(_V) (int)(ptrdiff_t)&(((Node *)0)_V) #define DtB(_V) (int)(ptrdiff_t)&(((Node *)0)_V)
#define DtC(_V) (int)(ptrdiff_t)&(((int *)0)_V) #define DtC(_V) (int)(ptrdiff_t)&(((int *)0)_V)
#define DtD(_V) (int)(ptrdiff_t)&(((Trace *)0)_V) #define DtD(_V) (int)(ptrdiff_t)&(((GCtrace *)0)_V)
#define DtE(_V) (int)(ptrdiff_t)&(((ExitInfo *)0)_V) #define DtE(_V) (int)(ptrdiff_t)&(((ExitInfo *)0)_V)
#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) #define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field))
#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) #define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field))

View File

@ -671,7 +671,7 @@ static const unsigned char build_actionlist[14023] = {
180,253,134,233,255,248,3,102,15,46,193,252,233,244,1,255,141,12,202,139, 180,253,134,233,255,248,3,102,15,46,193,252,233,244,1,255,141,12,202,139,
105,4,129,252,253,239,15,132,244,247,255,137,105,252,252,139,41,137,105,252, 105,4,129,252,253,239,15,132,244,247,255,137,105,252,252,139,41,137,105,252,
248,252,233,245,255,141,180,253,134,233,139,1,137,105,252,252,137,65,252, 248,252,233,245,255,141,180,253,134,233,139,1,137,105,252,252,137,65,252,
248,255,139,139,233,139,4,193,72,139,128,233,139,108,36,96,137,147,233,137, 248,255,139,139,233,139,4,129,72,139,128,233,139,108,36,96,137,147,233,137,
171,233,76,137,100,36,80,76,137,108,36,32,76,137,116,36,24,76,137,124,36, 171,233,76,137,100,36,80,76,137,108,36,32,76,137,116,36,24,76,137,124,36,
16,72,137,225,72,129,252,236,239,102,15,127,49,102,15,127,185,233,102,68, 16,72,137,225,72,129,252,236,239,102,15,127,49,102,15,127,185,233,102,68,
15,127,129,233,102,68,15,127,137,233,102,68,15,127,145,233,102,68,15,127, 15,127,129,233,102,68,15,127,137,233,102,68,15,127,145,233,102,68,15,127,
@ -1048,7 +1048,7 @@ static const char *const extnames[] = {
#define DtA(_V) (int)(ptrdiff_t)&(((GCupval *)0)_V) #define DtA(_V) (int)(ptrdiff_t)&(((GCupval *)0)_V)
#define DtB(_V) (int)(ptrdiff_t)&(((Node *)0)_V) #define DtB(_V) (int)(ptrdiff_t)&(((Node *)0)_V)
#define DtC(_V) (int)(ptrdiff_t)&(((int *)0)_V) #define DtC(_V) (int)(ptrdiff_t)&(((int *)0)_V)
#define DtD(_V) (int)(ptrdiff_t)&(((Trace *)0)_V) #define DtD(_V) (int)(ptrdiff_t)&(((GCtrace *)0)_V)
#define DtE(_V) (int)(ptrdiff_t)&(((ExitInfo *)0)_V) #define DtE(_V) (int)(ptrdiff_t)&(((ExitInfo *)0)_V)
#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) #define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field))
#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) #define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field))

View File

@ -107,7 +107,7 @@
|.type UPVAL, GCupval |.type UPVAL, GCupval
|.type NODE, Node |.type NODE, Node
|.type NARGS, int |.type NARGS, int
|.type TRACE, Trace |.type TRACE, GCtrace
|.type EXITINFO, ExitInfo |.type EXITINFO, ExitInfo
| |
|// Stack layout while in interpreter. Must match with lj_frame.h. |// Stack layout while in interpreter. Must match with lj_frame.h.
@ -4746,11 +4746,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop, int cmov, int sse)
#if LJ_HASJIT #if LJ_HASJIT
| ins_AD // RA = base (ignored), RD = traceno | ins_AD // RA = base (ignored), RD = traceno
| mov RA, [DISPATCH+DISPATCH_J(trace)] | mov RA, [DISPATCH+DISPATCH_J(trace)]
|.if X64
| mov TRACE:RD, [RA+RD*8]
|.else
| mov TRACE:RD, [RA+RD*4] | mov TRACE:RD, [RA+RD*4]
|.endif
| mov RDa, TRACE:RD->mcode | mov RDa, TRACE:RD->mcode
| mov L:RB, SAVE_L | mov L:RB, SAVE_L
| mov [DISPATCH+DISPATCH_GL(jit_base)], BASE | mov [DISPATCH+DISPATCH_GL(jit_base)], BASE

View File

@ -1102,7 +1102,7 @@ static const char *const extnames[] = {
#define DtA(_V) (int)(ptrdiff_t)&(((GCupval *)0)_V) #define DtA(_V) (int)(ptrdiff_t)&(((GCupval *)0)_V)
#define DtB(_V) (int)(ptrdiff_t)&(((Node *)0)_V) #define DtB(_V) (int)(ptrdiff_t)&(((Node *)0)_V)
#define DtC(_V) (int)(ptrdiff_t)&(((int *)0)_V) #define DtC(_V) (int)(ptrdiff_t)&(((int *)0)_V)
#define DtD(_V) (int)(ptrdiff_t)&(((Trace *)0)_V) #define DtD(_V) (int)(ptrdiff_t)&(((GCtrace *)0)_V)
#define DtE(_V) (int)(ptrdiff_t)&(((ExitInfo *)0)_V) #define DtE(_V) (int)(ptrdiff_t)&(((ExitInfo *)0)_V)
#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field)) #define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field))
#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field)) #define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field))

View File

@ -54,7 +54,7 @@ LJLIB_PUSH("upval")
LJLIB_PUSH("thread") LJLIB_PUSH("thread")
LJLIB_PUSH("proto") LJLIB_PUSH("proto")
LJLIB_PUSH("function") LJLIB_PUSH("function")
LJLIB_PUSH("") /* Unused. */ LJLIB_PUSH("trace")
LJLIB_PUSH("table") LJLIB_PUSH("table")
LJLIB_PUSH(top-8) /* userdata */ LJLIB_PUSH(top-8) /* userdata */
LJLIB_PUSH("number") LJLIB_PUSH("number")

View File

@ -72,9 +72,8 @@ LJLIB_CF(jit_flush)
#if LJ_HASJIT #if LJ_HASJIT
if (L->base < L->top && (tvisnum(L->base) || tvisstr(L->base))) { if (L->base < L->top && (tvisnum(L->base) || tvisstr(L->base))) {
int traceno = lj_lib_checkint(L, 1); int traceno = lj_lib_checkint(L, 1);
setboolV(L->top-1, luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE);
luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE)); return 0;
return 1;
} }
#endif #endif
return setjitmode(L, LUAJIT_MODE_FLUSH); return setjitmode(L, LUAJIT_MODE_FLUSH);
@ -260,19 +259,19 @@ LJLIB_CF(jit_util_funcuvname)
#if LJ_HASJIT #if LJ_HASJIT
/* Check trace argument. Must not throw for non-existent trace numbers. */ /* Check trace argument. Must not throw for non-existent trace numbers. */
static Trace *jit_checktrace(lua_State *L) static GCtrace *jit_checktrace(lua_State *L)
{ {
TraceNo tr = (TraceNo)lj_lib_checkint(L, 1); TraceNo tr = (TraceNo)lj_lib_checkint(L, 1);
jit_State *J = L2J(L); jit_State *J = L2J(L);
if (tr > 0 && tr < J->sizetrace) if (tr > 0 && tr < J->sizetrace)
return J->trace[tr]; return traceref(J, tr);
return NULL; return NULL;
} }
/* local info = jit.util.traceinfo(tr) */ /* local info = jit.util.traceinfo(tr) */
LJLIB_CF(jit_util_traceinfo) LJLIB_CF(jit_util_traceinfo)
{ {
Trace *T = jit_checktrace(L); GCtrace *T = jit_checktrace(L);
if (T) { if (T) {
GCtab *t; GCtab *t;
lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */ lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */
@ -290,7 +289,7 @@ LJLIB_CF(jit_util_traceinfo)
/* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */ /* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */
LJLIB_CF(jit_util_traceir) LJLIB_CF(jit_util_traceir)
{ {
Trace *T = jit_checktrace(L); GCtrace *T = jit_checktrace(L);
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS; IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
if (T && ref >= REF_BIAS && ref < T->nins) { if (T && ref >= REF_BIAS && ref < T->nins) {
IRIns *ir = &T->ir[ref]; IRIns *ir = &T->ir[ref];
@ -308,7 +307,7 @@ LJLIB_CF(jit_util_traceir)
/* local k, t [, slot] = jit.util.tracek(tr, idx) */ /* local k, t [, slot] = jit.util.tracek(tr, idx) */
LJLIB_CF(jit_util_tracek) LJLIB_CF(jit_util_tracek)
{ {
Trace *T = jit_checktrace(L); GCtrace *T = jit_checktrace(L);
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS; IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
if (T && ref >= T->nk && ref < REF_BIAS) { if (T && ref >= T->nk && ref < REF_BIAS) {
IRIns *ir = &T->ir[ref]; IRIns *ir = &T->ir[ref];
@ -330,7 +329,7 @@ LJLIB_CF(jit_util_tracek)
/* local snap = jit.util.tracesnap(tr, sn) */ /* local snap = jit.util.tracesnap(tr, sn) */
LJLIB_CF(jit_util_tracesnap) LJLIB_CF(jit_util_tracesnap)
{ {
Trace *T = jit_checktrace(L); GCtrace *T = jit_checktrace(L);
SnapNo sn = (SnapNo)lj_lib_checkint(L, 2); SnapNo sn = (SnapNo)lj_lib_checkint(L, 2);
if (T && sn < T->nsnap) { if (T && sn < T->nsnap) {
SnapShot *snap = &T->snap[sn]; SnapShot *snap = &T->snap[sn];
@ -352,7 +351,7 @@ LJLIB_CF(jit_util_tracesnap)
/* local mcode, addr, loop = jit.util.tracemc(tr) */ /* local mcode, addr, loop = jit.util.tracemc(tr) */
LJLIB_CF(jit_util_tracemc) LJLIB_CF(jit_util_tracemc)
{ {
Trace *T = jit_checktrace(L); GCtrace *T = jit_checktrace(L);
if (T && T->mcode != NULL) { if (T && T->mcode != NULL) {
setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode)); setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode));
setnumV(L->top++, cast_num((intptr_t)T->mcode)); setnumV(L->top++, cast_num((intptr_t)T->mcode));

View File

@ -67,8 +67,8 @@ typedef struct ASMState {
BCReg topslot; /* Number of slots for stack check (unless 0). */ BCReg topslot; /* Number of slots for stack check (unless 0). */
MSize gcsteps; /* Accumulated number of GC steps (per section). */ MSize gcsteps; /* Accumulated number of GC steps (per section). */
Trace *T; /* Trace to assemble. */ GCtrace *T; /* Trace to assemble. */
Trace *parent; /* Parent trace (or NULL). */ GCtrace *parent; /* Parent trace (or NULL). */
MCode *mcbot; /* Bottom of reserved MCode. */ MCode *mcbot; /* Bottom of reserved MCode. */
MCode *mctop; /* Top of generated MCode. */ MCode *mctop; /* Top of generated MCode. */
@ -3228,7 +3228,7 @@ static void asm_tail_link(ASMState *as)
const BCIns *pc = snap_pc(as->T->snapmap[snap->mapofs + snap->nent]); const BCIns *pc = snap_pc(as->T->snapmap[snap->mapofs + snap->nent]);
int32_t mres; int32_t mres;
if (bc_op(*pc) == BC_JLOOP) { /* NYI: find a better way to do this. */ if (bc_op(*pc) == BC_JLOOP) { /* NYI: find a better way to do this. */
BCIns *retpc = &as->J->trace[bc_d(*pc)]->startins; BCIns *retpc = &traceref(as->J, bc_d(*pc))->startins;
if (bc_isret(bc_op(*retpc))) if (bc_isret(bc_op(*retpc)))
pc = retpc; pc = retpc;
} }
@ -3294,7 +3294,7 @@ static void asm_tail_fixup(ASMState *as, TraceNo lnk)
} }
/* Patch exit branch. */ /* Patch exit branch. */
target = lnk == TRACE_INTERP ? (MCode *)lj_vm_exit_interp : target = lnk == TRACE_INTERP ? (MCode *)lj_vm_exit_interp :
as->J->trace[lnk]->mcode; traceref(as->J, lnk)->mcode;
*(int32_t *)(p-4) = jmprel(p, target); *(int32_t *)(p-4) = jmprel(p, target);
p[-5] = XI_JMP; p[-5] = XI_JMP;
/* Drop unused mcode tail. Fill with NOPs to make the prefetcher happy. */ /* Drop unused mcode tail. Fill with NOPs to make the prefetcher happy. */
@ -3437,7 +3437,7 @@ static void asm_trace(ASMState *as)
/* -- Trace setup --------------------------------------------------------- */ /* -- Trace setup --------------------------------------------------------- */
/* Clear reg/sp for all instructions and add register hints. */ /* Clear reg/sp for all instructions and add register hints. */
static void asm_setup_regsp(ASMState *as, Trace *T) static void asm_setup_regsp(ASMState *as, GCtrace *T)
{ {
IRRef i, nins; IRRef i, nins;
int inloop; int inloop;
@ -3577,7 +3577,7 @@ static void asm_setup_regsp(ASMState *as, Trace *T)
#endif #endif
/* Assemble a trace. */ /* Assemble a trace. */
void lj_asm_trace(jit_State *J, Trace *T) void lj_asm_trace(jit_State *J, GCtrace *T)
{ {
ASMState as_; ASMState as_;
ASMState *as = &as_; ASMState *as = &as_;
@ -3591,7 +3591,7 @@ void lj_asm_trace(jit_State *J, Trace *T)
as->realign = NULL; as->realign = NULL;
as->loopinv = 0; as->loopinv = 0;
if (J->parent) { if (J->parent) {
as->parent = J->trace[J->parent]; as->parent = traceref(J, J->parent);
lj_snap_regspmap(as->parentmap, as->parent, J->exitno); lj_snap_regspmap(as->parentmap, as->parent, J->exitno);
} else { } else {
as->parent = NULL; as->parent = NULL;
@ -3667,7 +3667,7 @@ void lj_asm_trace(jit_State *J, Trace *T)
} }
/* Patch exit jumps of existing machine code to a new target. */ /* Patch exit jumps of existing machine code to a new target. */
void lj_asm_patchexit(jit_State *J, Trace *T, ExitNo exitno, MCode *target) void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
{ {
MCode *p = T->mcode; MCode *p = T->mcode;
MCode *mcarea = lj_mcode_patch(J, p, 0); MCode *mcarea = lj_mcode_patch(J, p, 0);

View File

@ -9,8 +9,8 @@
#include "lj_jit.h" #include "lj_jit.h"
#if LJ_HASJIT #if LJ_HASJIT
LJ_FUNC void lj_asm_trace(jit_State *J, Trace *T); LJ_FUNC void lj_asm_trace(jit_State *J, GCtrace *T);
LJ_FUNC void lj_asm_patchexit(jit_State *J, Trace *T, ExitNo exitno, LJ_FUNC void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno,
MCode *target); MCode *target);
#endif #endif

View File

@ -239,7 +239,8 @@ int luaJIT_setmode(lua_State *L, int idx, int mode)
case LUAJIT_MODE_TRACE: case LUAJIT_MODE_TRACE:
if (!(mode & LUAJIT_MODE_FLUSH)) if (!(mode & LUAJIT_MODE_FLUSH))
return 0; /* Failed. */ return 0; /* Failed. */
return lj_trace_flush(G2J(g), idx); lj_trace_flush(G2J(g), idx);
break;
#else #else
case LUAJIT_MODE_ENGINE: case LUAJIT_MODE_ENGINE:
case LUAJIT_MODE_FUNC: case LUAJIT_MODE_FUNC:

View File

@ -19,7 +19,6 @@
void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt) void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt)
{ {
lj_trace_freeproto(g, pt);
lj_mem_free(g, pt, pt->sizept); lj_mem_free(g, pt, pt->sizept);
} }

View File

@ -214,8 +214,21 @@ static void gc_traverse_func(global_State *g, GCfunc *fn)
} }
#if LJ_HASJIT #if LJ_HASJIT
/* Mark a trace. */
static void gc_marktrace(global_State *g, TraceNo traceno)
{
if (traceno && traceno != G2J(g)->curtrace) {
GCobj *o = obj2gco(traceref(G2J(g), traceno));
if (iswhite(o)) {
white2gray(o);
setgcrefr(o->gch.gclist, g->gc.gray);
setgcref(g->gc.gray, o);
}
}
}
/* Traverse a trace. */ /* Traverse a trace. */
static void gc_traverse_trace(global_State *g, Trace *T) static void gc_traverse_trace(global_State *g, GCtrace *T)
{ {
IRRef ref; IRRef ref;
for (ref = T->nk; ref < REF_TRUE; ref++) { for (ref = T->nk; ref < REF_TRUE; ref++) {
@ -223,31 +236,23 @@ static void gc_traverse_trace(global_State *g, Trace *T)
if (ir->o == IR_KGC) if (ir->o == IR_KGC)
gc_markobj(g, ir_kgc(ir)); gc_markobj(g, ir_kgc(ir));
} }
gc_marktrace(g, T->link);
gc_marktrace(g, T->nextroot);
gc_marktrace(g, T->nextside);
gc_markobj(g, gcref(T->startpt));
} }
/* The current trace is a GC root while not anchored in the prototype (yet). */ /* The current trace is a GC root while not anchored in the prototype (yet). */
#define gc_mark_curtrace(g) \ #define gc_traverse_curtrace(g) \
{ if (G2J(g)->curtrace != 0) gc_traverse_trace(g, &G2J(g)->cur); } { if (G2J(g)->curtrace != 0) gc_traverse_trace(g, &G2J(g)->cur); }
#else #else
#define gc_mark_curtrace(g) UNUSED(g) #define gc_traverse_curtrace(g) UNUSED(g)
#endif #endif
/* Traverse a prototype. */ /* Traverse a prototype. */
static void gc_traverse_proto(global_State *g, GCproto *pt) static void gc_traverse_proto(global_State *g, GCproto *pt)
{ {
ptrdiff_t i; ptrdiff_t i;
#if LJ_HASJIT
jit_State *J = G2J(g);
TraceNo root, side;
/* Mark all root traces and attached side traces. */
for (root = pt->trace; root != 0; root = J->trace[root]->nextroot) {
for (side = J->trace[root]->nextside; side != 0;
side = J->trace[side]->nextside)
gc_traverse_trace(g, J->trace[side]);
gc_traverse_trace(g, J->trace[root]);
}
#endif
/* GC during prototype creation could cause NULL fields. */
gc_mark_str(proto_chunkname(pt)); gc_mark_str(proto_chunkname(pt));
for (i = -(ptrdiff_t)pt->sizekgc; i < 0; i++) /* Mark collectable consts. */ for (i = -(ptrdiff_t)pt->sizekgc; i < 0; i++) /* Mark collectable consts. */
gc_markobj(g, proto_kgc(pt, i)); gc_markobj(g, proto_kgc(pt, i));
@ -255,6 +260,9 @@ static void gc_traverse_proto(global_State *g, GCproto *pt)
gc_mark_str(proto_uvname(pt, i)); gc_mark_str(proto_uvname(pt, i));
for (i = 0; i < (ptrdiff_t)pt->sizevarinfo; i++) /* Mark names of locals. */ for (i = 0; i < (ptrdiff_t)pt->sizevarinfo; i++) /* Mark names of locals. */
gc_mark_str(gco2str(gcref(proto_varinfo(pt)[i].name))); gc_mark_str(gco2str(gcref(proto_varinfo(pt)[i].name)));
#if LJ_HASJIT
gc_marktrace(g, pt->trace);
#endif
} }
/* Traverse the frame structure of a stack. */ /* Traverse the frame structure of a stack. */
@ -311,13 +319,23 @@ static size_t propagatemark(global_State *g)
GCproto *pt = gco2pt(o); GCproto *pt = gco2pt(o);
gc_traverse_proto(g, pt); gc_traverse_proto(g, pt);
return pt->sizept; return pt->sizept;
} else { } else if (LJ_LIKELY(o->gch.gct == ~LJ_TTHREAD)) {
lua_State *th = gco2th(o); lua_State *th = gco2th(o);
setgcrefr(th->gclist, g->gc.grayagain); setgcrefr(th->gclist, g->gc.grayagain);
setgcref(g->gc.grayagain, o); setgcref(g->gc.grayagain, o);
black2gray(o); /* Threads are never black. */ black2gray(o); /* Threads are never black. */
gc_traverse_thread(g, th); gc_traverse_thread(g, th);
return sizeof(lua_State) + sizeof(TValue) * th->stacksize; return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
} else {
#if LJ_HASJIT
GCtrace *T = gco2trace(o);
gc_traverse_trace(g, T);
return ((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) +
T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry);
#else
lua_assert(0);
return 0;
#endif
} }
} }
@ -351,7 +369,11 @@ static const GCFreeFunc gc_freefunc[] = {
(GCFreeFunc)lj_state_free, (GCFreeFunc)lj_state_free,
(GCFreeFunc)lj_func_freeproto, (GCFreeFunc)lj_func_freeproto,
(GCFreeFunc)lj_func_free, (GCFreeFunc)lj_func_free,
#if LJ_HASJIT
(GCFreeFunc)lj_trace_free,
#else
(GCFreeFunc)0, (GCFreeFunc)0,
#endif
(GCFreeFunc)lj_tab_free, (GCFreeFunc)lj_tab_free,
(GCFreeFunc)lj_udata_free (GCFreeFunc)lj_udata_free
}; };
@ -502,7 +524,7 @@ static void atomic(global_State *g, lua_State *L)
setgcrefnull(g->gc.weak); setgcrefnull(g->gc.weak);
lua_assert(!iswhite(obj2gco(mainthread(g)))); lua_assert(!iswhite(obj2gco(mainthread(g))));
gc_markobj(g, L); /* Mark running thread. */ gc_markobj(g, L); /* Mark running thread. */
gc_mark_curtrace(g); /* Mark current trace. */ gc_traverse_curtrace(g); /* Traverse current trace. */
gc_mark_gcroot(g); /* Mark GC roots (again). */ gc_mark_gcroot(g); /* Mark GC roots (again). */
gc_propagate_gray(g); /* Propagate all of the above. */ gc_propagate_gray(g); /* Propagate all of the above. */
@ -681,7 +703,7 @@ void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v)
lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause); lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause);
lua_assert(o->gch.gct != ~LJ_TTAB); lua_assert(o->gch.gct != ~LJ_TTAB);
/* Preserve invariant during propagation. Otherwise it doesn't matter. */ /* Preserve invariant during propagation. Otherwise it doesn't matter. */
if (g->gc.state == GCSpropagate) if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic)
gc_mark(g, v); /* Move frontier forward. */ gc_mark(g, v); /* Move frontier forward. */
else else
makewhite(g, o); /* Make it white to avoid the following barrier. */ makewhite(g, o); /* Make it white to avoid the following barrier. */
@ -692,7 +714,7 @@ void LJ_FASTCALL lj_gc_barrieruv(global_State *g, TValue *tv)
{ {
#define TV2MARKED(x) \ #define TV2MARKED(x) \
(*((uint8_t *)(x) - offsetof(GCupval, tv) + offsetof(GCupval, marked))) (*((uint8_t *)(x) - offsetof(GCupval, tv) + offsetof(GCupval, marked)))
if (g->gc.state == GCSpropagate) if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic)
gc_mark(g, gcV(tv)); gc_mark(g, gcV(tv));
else else
TV2MARKED(tv) = (TV2MARKED(tv) & cast_byte(~LJ_GC_COLORS)) | curwhite(g); TV2MARKED(tv) = (TV2MARKED(tv) & cast_byte(~LJ_GC_COLORS)) | curwhite(g);
@ -710,7 +732,7 @@ void lj_gc_closeuv(global_State *g, GCupval *uv)
setgcrefr(o->gch.nextgc, g->gc.root); setgcrefr(o->gch.nextgc, g->gc.root);
setgcref(g->gc.root, o); setgcref(g->gc.root, o);
if (isgray(o)) { /* A closed upvalue is never gray, so fix this. */ if (isgray(o)) { /* A closed upvalue is never gray, so fix this. */
if (g->gc.state == GCSpropagate) { if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) {
gray2black(o); /* Make it black and preserve invariant. */ gray2black(o); /* Make it black and preserve invariant. */
if (tviswhite(&uv->tv)) if (tviswhite(&uv->tv))
lj_gc_barrierf(g, o, gcV(&uv->tv)); lj_gc_barrierf(g, o, gcV(&uv->tv));
@ -723,10 +745,10 @@ void lj_gc_closeuv(global_State *g, GCupval *uv)
#if LJ_HASJIT #if LJ_HASJIT
/* Mark a trace if it's saved during the propagation phase. */ /* Mark a trace if it's saved during the propagation phase. */
void lj_gc_barriertrace(global_State *g, void *T) void lj_gc_barriertrace(global_State *g, uint32_t traceno)
{ {
if (g->gc.state == GCSpropagate) if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic)
gc_traverse_trace(g, (Trace *)T); gc_marktrace(g, traceno);
} }
#endif #endif

View File

@ -65,7 +65,7 @@ LJ_FUNC void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v);
LJ_FUNCA void LJ_FASTCALL lj_gc_barrieruv(global_State *g, TValue *tv); LJ_FUNCA void LJ_FASTCALL lj_gc_barrieruv(global_State *g, TValue *tv);
LJ_FUNC void lj_gc_closeuv(global_State *g, GCupval *uv); LJ_FUNC void lj_gc_closeuv(global_State *g, GCupval *uv);
#if LJ_HASJIT #if LJ_HASJIT
LJ_FUNC void lj_gc_barriertrace(global_State *g, void *T); LJ_FUNC void lj_gc_barriertrace(global_State *g, uint32_t traceno);
#endif #endif
/* Barrier for stores to table objects. TValue and GCobj variant. */ /* Barrier for stores to table objects. TValue and GCobj variant. */

View File

@ -378,7 +378,7 @@ static const ELFheader elfhdr_template = {
typedef struct GDBJITctx { typedef struct GDBJITctx {
uint8_t *p; /* Pointer to next address in obj.space. */ uint8_t *p; /* Pointer to next address in obj.space. */
uint8_t *startp; /* Pointer to start address in obj.space. */ uint8_t *startp; /* Pointer to start address in obj.space. */
Trace *T; /* Generate symbols for this trace. */ GCtrace *T; /* Generate symbols for this trace. */
uintptr_t mcaddr; /* Machine code address. */ uintptr_t mcaddr; /* Machine code address. */
MSize szmcode; /* Size of machine code. */ MSize szmcode; /* Size of machine code. */
MSize spadjp; /* Stack adjustment for parent trace or interpreter. */ MSize spadjp; /* Stack adjustment for parent trace or interpreter. */
@ -698,7 +698,7 @@ static void gdbjit_newentry(lua_State *L, GDBJITctx *ctx)
} }
/* Add debug info for newly compiled trace and notify GDB. */ /* Add debug info for newly compiled trace and notify GDB. */
void lj_gdbjit_addtrace(jit_State *J, Trace *T, TraceNo traceno) void lj_gdbjit_addtrace(jit_State *J, GCtrace *T, TraceNo traceno)
{ {
GDBJITctx ctx; GDBJITctx ctx;
lua_State *L = J->L; lua_State *L = J->L;
@ -709,7 +709,8 @@ void lj_gdbjit_addtrace(jit_State *J, Trace *T, TraceNo traceno)
ctx.T = T; ctx.T = T;
ctx.mcaddr = (uintptr_t)T->mcode; ctx.mcaddr = (uintptr_t)T->mcode;
ctx.szmcode = T->szmcode; ctx.szmcode = T->szmcode;
ctx.spadjp = CFRAME_SIZE_JIT + (MSize)(parent?J->trace[parent]->spadjust:0); ctx.spadjp = CFRAME_SIZE_JIT +
(MSize)(parent ? traceref(J, parent)->spadjust : 0);
ctx.spadj = CFRAME_SIZE_JIT + T->spadjust; ctx.spadj = CFRAME_SIZE_JIT + T->spadjust;
if (startpc >= proto_bc(pt) && startpc < proto_bc(pt) + pt->sizebc) if (startpc >= proto_bc(pt) && startpc < proto_bc(pt) + pt->sizebc)
ctx.lineno = proto_line(pt, proto_bcpos(pt, startpc)); ctx.lineno = proto_line(pt, proto_bcpos(pt, startpc));
@ -727,7 +728,7 @@ void lj_gdbjit_addtrace(jit_State *J, Trace *T, TraceNo traceno)
} }
/* Delete debug info for trace and notify GDB. */ /* Delete debug info for trace and notify GDB. */
void lj_gdbjit_deltrace(jit_State *J, Trace *T) void lj_gdbjit_deltrace(jit_State *J, GCtrace *T)
{ {
GDBJITentryobj *eo = (GDBJITentryobj *)T->gdbjit_entry; GDBJITentryobj *eo = (GDBJITentryobj *)T->gdbjit_entry;
if (eo) { if (eo) {

View File

@ -11,8 +11,8 @@
#if LJ_HASJIT && defined(LUAJIT_USE_GDBJIT) #if LJ_HASJIT && defined(LUAJIT_USE_GDBJIT)
LJ_FUNC void lj_gdbjit_addtrace(jit_State *J, Trace *T, TraceNo traceno); LJ_FUNC void lj_gdbjit_addtrace(jit_State *J, GCtrace *T, TraceNo traceno);
LJ_FUNC void lj_gdbjit_deltrace(jit_State *J, Trace *T); LJ_FUNC void lj_gdbjit_deltrace(jit_State *J, GCtrace *T);
#else #else
#define lj_gdbjit_addtrace(J, T, tn) UNUSED(T) #define lj_gdbjit_addtrace(J, T, tn) UNUSED(T)

View File

@ -317,7 +317,7 @@ typedef enum {
IRT_THREAD, IRT_THREAD,
IRT_PROTO, IRT_PROTO,
IRT_FUNC, IRT_FUNC,
IRT_9, /* Never used in the IR. */ IRT_9, /* Unused (map of LJ_TTRACE). */
IRT_TAB, IRT_TAB,
IRT_UDATA, IRT_UDATA,
/* ... until here. */ /* ... until here. */

View File

@ -152,34 +152,42 @@ typedef uint16_t TraceNo1; /* Stored trace number. */
#define TRACE_INTERP 0 /* Fallback to interpreter. */ #define TRACE_INTERP 0 /* Fallback to interpreter. */
/* Trace anchor. */ /* Trace object. */
typedef struct Trace { typedef struct GCtrace {
IRIns *ir; /* IR instructions/constants. Biased with REF_BIAS. */ GCHeader;
uint8_t topslot; /* Top stack slot already checked to be allocated. */
uint8_t unused1;
IRRef nins; /* Next IR instruction. Biased with REF_BIAS. */ IRRef nins; /* Next IR instruction. Biased with REF_BIAS. */
GCRef gclist;
IRIns *ir; /* IR instructions/constants. Biased with REF_BIAS. */
IRRef nk; /* Lowest IR constant. Biased with REF_BIAS. */ IRRef nk; /* Lowest IR constant. Biased with REF_BIAS. */
SnapShot *snap; /* Snapshot array. */
SnapEntry *snapmap; /* Snapshot map. */
uint16_t nsnap; /* Number of snapshots. */ uint16_t nsnap; /* Number of snapshots. */
uint16_t nsnapmap; /* Number of snapshot map elements. */ uint16_t nsnapmap; /* Number of snapshot map elements. */
SnapShot *snap; /* Snapshot array. */
SnapEntry *snapmap; /* Snapshot map. */
GCRef startpt; /* Starting prototype. */ GCRef startpt; /* Starting prototype. */
BCIns startins; /* Original bytecode of starting instruction. */ BCIns startins; /* Original bytecode of starting instruction. */
MCode *mcode; /* Start of machine code. */ MCode *mcode; /* Start of machine code. */
MSize szmcode; /* Size of machine code. */ MSize szmcode; /* Size of machine code. */
MSize mcloop; /* Offset of loop start in machine code. */ MSize mcloop; /* Offset of loop start in machine code. */
uint16_t nchild; /* Number of child traces (root trace only). */
uint16_t spadjust; /* Stack pointer adjustment (offset in bytes). */
TraceNo1 traceno; /* Trace number. */
TraceNo1 link; /* Linked trace (or self for loops). */ TraceNo1 link; /* Linked trace (or self for loops). */
TraceNo1 root; /* Root trace of side trace (or 0 for root traces). */ TraceNo1 root; /* Root trace of side trace (or 0 for root traces). */
TraceNo1 nextroot; /* Next root trace for same prototype. */ TraceNo1 nextroot; /* Next root trace for same prototype. */
TraceNo1 nextside; /* Next side trace of same root trace. */ TraceNo1 nextside; /* Next side trace of same root trace. */
uint16_t nchild; /* Number of child traces (root trace only). */ uint16_t unused2;
uint16_t spadjust; /* Stack pointer adjustment (offset in bytes). */
uint8_t topslot; /* Top stack slot already checked to be allocated. */
uint8_t unused1;
uint8_t unused2;
uint8_t unused3;
#ifdef LUAJIT_USE_GDBJIT #ifdef LUAJIT_USE_GDBJIT
void *gdbjit_entry; /* GDB JIT entry. */ void *gdbjit_entry; /* GDB JIT entry. */
#endif #endif
} Trace; } GCtrace;
#define gco2trace(o) check_exp((o)->gch.gct == ~LJ_TTRACE, (GCtrace *)(o))
#define traceref(J, n) \
check_exp((n)>0 && (MSize)(n)<J->sizetrace, (GCtrace *)gcref(J->trace[(n)]))
LJ_STATIC_ASSERT(offsetof(GChead, gclist) == offsetof(GCtrace, gclist));
/* Round-robin penalty cache for bytecodes leading to aborted traces. */ /* Round-robin penalty cache for bytecodes leading to aborted traces. */
typedef struct HotPenalty { typedef struct HotPenalty {
@ -233,7 +241,7 @@ typedef struct FoldState {
/* JIT compiler state. */ /* JIT compiler state. */
typedef struct jit_State { typedef struct jit_State {
Trace cur; /* Current trace. */ GCtrace cur; /* Current trace. */
lua_State *L; /* Current Lua state. */ lua_State *L; /* Current Lua state. */
const BCIns *pc; /* Current PC. */ const BCIns *pc; /* Current PC. */
@ -277,7 +285,7 @@ typedef struct jit_State {
MSize sizesnapmap; /* Size of temp. snapshot map buffer. */ MSize sizesnapmap; /* Size of temp. snapshot map buffer. */
TraceNo curtrace; /* Current trace number (if not 0). Kept in J->cur. */ TraceNo curtrace; /* Current trace number (if not 0). Kept in J->cur. */
Trace **trace; /* Array of traces. */ GCRef *trace; /* Array of traces. */
TraceNo freetrace; /* Start of scan for next free trace. */ TraceNo freetrace; /* Start of scan for next free trace. */
MSize sizetrace; /* Size of trace array. */ MSize sizetrace; /* Size of trace array. */

View File

@ -16,7 +16,7 @@ LJ_DATADEF const char *const lj_obj_typename[] = { /* ORDER LUA_T */
LJ_DATADEF const char *const lj_obj_itypename[] = { /* ORDER LJ_T */ LJ_DATADEF const char *const lj_obj_itypename[] = { /* ORDER LJ_T */
"nil", "boolean", "boolean", "userdata", "string", "upval", "thread", "nil", "boolean", "boolean", "userdata", "string", "upval", "thread",
"proto", "function", "" /* Unused */, "table", "userdata", "number" "proto", "function", "trace", "table", "userdata", "number"
}; };
/* Compare two objects without calling metamethods. */ /* Compare two objects without calling metamethods. */

View File

@ -195,7 +195,7 @@ typedef const TValue cTValue;
#define LJ_TTHREAD (-7) #define LJ_TTHREAD (-7)
#define LJ_TPROTO (-8) #define LJ_TPROTO (-8)
#define LJ_TFUNC (-9) #define LJ_TFUNC (-9)
/* Unused (-10) */ #define LJ_TTRACE (-10)
#define LJ_TTAB (-11) #define LJ_TTAB (-11)
#define LJ_TUDATA (-12) #define LJ_TUDATA (-12)
/* This is just the canonical number type used in some places. */ /* This is just the canonical number type used in some places. */

View File

@ -265,7 +265,7 @@ static TRef find_kinit(jit_State *J, const BCIns *endpc, BCReg slot, IRType t)
if (op == BC_KSHORT || op == BC_KNUM) { /* Found const. initializer. */ if (op == BC_KSHORT || op == BC_KNUM) { /* Found const. initializer. */
/* Now try to verify there's no forward jump across it. */ /* Now try to verify there's no forward jump across it. */
const BCIns *kpc = pc; const BCIns *kpc = pc;
for ( ; pc > startpc; pc--) for (; pc > startpc; pc--)
if (bc_op(*pc) == BC_JMP) { if (bc_op(*pc) == BC_JMP) {
const BCIns *target = pc+bc_j(*pc)+1; const BCIns *target = pc+bc_j(*pc)+1;
if (target > kpc && target <= endpc) if (target > kpc && target <= endpc)
@ -2237,10 +2237,10 @@ void lj_record_ins(jit_State *J)
break; break;
case BC_JFORL: case BC_JFORL:
rec_loop_jit(J, rc, rec_for(J, pc+bc_j(J->trace[rc]->startins), 1)); rec_loop_jit(J, rc, rec_for(J, pc+bc_j(traceref(J, rc)->startins), 1));
break; break;
case BC_JITERL: case BC_JITERL:
rec_loop_jit(J, rc, rec_iterl(J, J->trace[rc]->startins)); rec_loop_jit(J, rc, rec_iterl(J, traceref(J, rc)->startins));
break; break;
case BC_JLOOP: case BC_JLOOP:
rec_loop_jit(J, rc, rec_loop(J, ra)); rec_loop_jit(J, rc, rec_loop(J, ra));
@ -2412,7 +2412,7 @@ static const BCIns *rec_setup_root(jit_State *J)
} }
/* Setup recording for a side trace. */ /* Setup recording for a side trace. */
static void rec_setup_side(jit_State *J, Trace *T) static void rec_setup_side(jit_State *J, GCtrace *T)
{ {
SnapShot *snap = &T->snap[J->exitno]; SnapShot *snap = &T->snap[J->exitno];
SnapEntry *map = &T->snapmap[snap->mapofs]; SnapEntry *map = &T->snapmap[snap->mapofs];
@ -2500,10 +2500,9 @@ void lj_record_setup(jit_State *J)
} }
J->cur.nk = REF_TRUE; J->cur.nk = REF_TRUE;
setgcref(J->cur.startpt, obj2gco(J->pt));
J->startpc = J->pc; J->startpc = J->pc;
if (J->parent) { /* Side trace. */ if (J->parent) { /* Side trace. */
Trace *T = J->trace[J->parent]; GCtrace *T = traceref(J, J->parent);
TraceNo root = T->root ? T->root : J->parent; TraceNo root = T->root ? T->root : J->parent;
J->cur.root = (uint16_t)root; J->cur.root = (uint16_t)root;
J->cur.startins = BCINS_AD(BC_JMP, 0, 0); J->cur.startins = BCINS_AD(BC_JMP, 0, 0);
@ -2521,7 +2520,7 @@ void lj_record_setup(jit_State *J)
} }
rec_setup_side(J, T); rec_setup_side(J, T);
sidecheck: sidecheck:
if (J->trace[J->cur.root]->nchild >= J->param[JIT_P_maxside] || if (traceref(J, J->cur.root)->nchild >= J->param[JIT_P_maxside] ||
T->snap[J->exitno].count >= J->param[JIT_P_hotexit] + T->snap[J->exitno].count >= J->param[JIT_P_hotexit] +
J->param[JIT_P_tryside]) J->param[JIT_P_tryside])
rec_stop(J, TRACE_INTERP); rec_stop(J, TRACE_INTERP);

View File

@ -168,7 +168,7 @@ void lj_snap_shrink(jit_State *J)
** There are very few renames (often none), so the filter has ** There are very few renames (often none), so the filter has
** very few bits set. This makes it suitable for negative filtering. ** very few bits set. This makes it suitable for negative filtering.
*/ */
static BloomFilter snap_renamefilter(Trace *T, SnapNo lim) static BloomFilter snap_renamefilter(GCtrace *T, SnapNo lim)
{ {
BloomFilter rfilt = 0; BloomFilter rfilt = 0;
IRIns *ir; IRIns *ir;
@ -179,7 +179,7 @@ static BloomFilter snap_renamefilter(Trace *T, SnapNo lim)
} }
/* Process matching renames to find the original RegSP. */ /* Process matching renames to find the original RegSP. */
static RegSP snap_renameref(Trace *T, SnapNo lim, IRRef ref, RegSP rs) static RegSP snap_renameref(GCtrace *T, SnapNo lim, IRRef ref, RegSP rs)
{ {
IRIns *ir; IRIns *ir;
for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--) for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
@ -191,7 +191,7 @@ static RegSP snap_renameref(Trace *T, SnapNo lim, IRRef ref, RegSP rs)
/* Convert a snapshot into a linear slot -> RegSP map. /* Convert a snapshot into a linear slot -> RegSP map.
** Note: unused slots are not initialized! ** Note: unused slots are not initialized!
*/ */
void lj_snap_regspmap(uint16_t *rsmap, Trace *T, SnapNo snapno) void lj_snap_regspmap(uint16_t *rsmap, GCtrace *T, SnapNo snapno)
{ {
SnapShot *snap = &T->snap[snapno]; SnapShot *snap = &T->snap[snapno];
MSize n, nent = snap->nent; MSize n, nent = snap->nent;
@ -215,7 +215,7 @@ const BCIns *lj_snap_restore(jit_State *J, void *exptr)
{ {
ExitState *ex = (ExitState *)exptr; ExitState *ex = (ExitState *)exptr;
SnapNo snapno = J->exitno; /* For now, snapno == exitno. */ SnapNo snapno = J->exitno; /* For now, snapno == exitno. */
Trace *T = J->trace[J->parent]; GCtrace *T = traceref(J, J->parent);
SnapShot *snap = &T->snap[snapno]; SnapShot *snap = &T->snap[snapno];
MSize n, nent = snap->nent; MSize n, nent = snap->nent;
SnapEntry *map = &T->snapmap[snap->mapofs]; SnapEntry *map = &T->snapmap[snap->mapofs];

View File

@ -12,7 +12,7 @@
#if LJ_HASJIT #if LJ_HASJIT
LJ_FUNC void lj_snap_add(jit_State *J); LJ_FUNC void lj_snap_add(jit_State *J);
LJ_FUNC void lj_snap_shrink(jit_State *J); LJ_FUNC void lj_snap_shrink(jit_State *J);
LJ_FUNC void lj_snap_regspmap(uint16_t *rsmap, Trace *T, SnapNo snapno); LJ_FUNC void lj_snap_regspmap(uint16_t *rsmap, GCtrace *T, SnapNo snapno);
LJ_FUNC const BCIns *lj_snap_restore(jit_State *J, void *exptr); LJ_FUNC const BCIns *lj_snap_restore(jit_State *J, void *exptr);
LJ_FUNC void lj_snap_grow_buf_(jit_State *J, MSize need); LJ_FUNC void lj_snap_grow_buf_(jit_State *J, MSize need);
LJ_FUNC void lj_snap_grow_map_(jit_State *J, MSize need); LJ_FUNC void lj_snap_grow_map_(jit_State *J, MSize need);

View File

@ -52,7 +52,7 @@ void lj_trace_err_info(jit_State *J, TraceError e)
/* The current trace is first assembled in J->cur. The variable length /* The current trace is first assembled in J->cur. The variable length
** arrays point to shared, growable buffers (J->irbuf etc.). The trace is ** arrays point to shared, growable buffers (J->irbuf etc.). The trace is
** kept in this state until a new trace needs to be created. Then the current ** kept in this state until a new trace needs to be created. Then the current
** trace and its data structures are copied to a new (compact) Trace object. ** trace and its data structures are copied to a new (compact) GCtrace object.
*/ */
/* Find a free trace number. */ /* Find a free trace number. */
@ -62,7 +62,7 @@ static TraceNo trace_findfree(jit_State *J)
if (J->freetrace == 0) if (J->freetrace == 0)
J->freetrace = 1; J->freetrace = 1;
for (; J->freetrace < J->sizetrace; J->freetrace++) for (; J->freetrace < J->sizetrace; J->freetrace++)
if (J->trace[J->freetrace] == NULL) if (traceref(J, J->freetrace) == NULL)
return J->freetrace++; return J->freetrace++;
/* Need to grow trace array. */ /* Need to grow trace array. */
lim = (MSize)J->param[JIT_P_maxtrace] + 1; lim = (MSize)J->param[JIT_P_maxtrace] + 1;
@ -70,9 +70,9 @@ static TraceNo trace_findfree(jit_State *J)
osz = J->sizetrace; osz = J->sizetrace;
if (osz >= lim) if (osz >= lim)
return 0; /* Too many traces. */ return 0; /* Too many traces. */
lj_mem_growvec(J->L, J->trace, J->sizetrace, lim, Trace *); lj_mem_growvec(J->L, J->trace, J->sizetrace, lim, GCRef);
while (osz < J->sizetrace) for (; osz < J->sizetrace; osz++)
J->trace[osz++] = NULL; setgcrefnull(J->trace[osz]);
return J->freetrace; return J->freetrace;
} }
@ -82,64 +82,40 @@ static TraceNo trace_findfree(jit_State *J)
p += T->szfield*sizeof(tp); p += T->szfield*sizeof(tp);
/* Save a trace by copying and compacting it. */ /* Save a trace by copying and compacting it. */
static Trace *trace_save(jit_State *J, Trace *T) static GCtrace *trace_save(jit_State *J, GCtrace *T)
{ {
size_t sztr = ((sizeof(Trace)+7)&~7); size_t sztr = ((sizeof(GCtrace)+7)&~7);
size_t szins = (T->nins-T->nk)*sizeof(IRIns); size_t szins = (T->nins-T->nk)*sizeof(IRIns);
size_t sz = sztr + szins + size_t sz = sztr + szins +
T->nsnap*sizeof(SnapShot) + T->nsnap*sizeof(SnapShot) +
T->nsnapmap*sizeof(SnapEntry); T->nsnapmap*sizeof(SnapEntry);
Trace *T2 = lj_mem_newt(J->L, (MSize)sz, Trace); GCtrace *T2 = lj_mem_newt(J->L, (MSize)sz, GCtrace);
char *p = (char *)T2 + sztr; char *p = (char *)T2 + sztr;
memcpy(T2, T, sizeof(Trace)); memcpy(T2, T, sizeof(GCtrace));
setgcrefr(T2->nextgc, J2G(J)->gc.root);
setgcrefp(J2G(J)->gc.root, T2);
newwhite(J2G(J), T2);
T2->gct = ~LJ_TTRACE;
T2->ir = (IRIns *)p - T->nk; T2->ir = (IRIns *)p - T->nk;
memcpy(p, T->ir+T->nk, szins); memcpy(p, T->ir+T->nk, szins);
p += szins; p += szins;
TRACE_COPYELEM(snap, nsnap, SnapShot) TRACE_COPYELEM(snap, nsnap, SnapShot)
TRACE_COPYELEM(snapmap, nsnapmap, SnapEntry) TRACE_COPYELEM(snapmap, nsnapmap, SnapEntry)
lj_gc_barriertrace(J2G(J), T);
return T2; return T2;
} }
/* Free a trace. */ void LJ_FASTCALL lj_trace_free(global_State *g, GCtrace *T)
static void trace_free(jit_State *J, TraceNo traceno)
{
lua_assert(traceno != 0);
if (traceno < J->freetrace)
J->freetrace = traceno;
lj_gdbjit_deltrace(J, J->trace[traceno]);
if (traceno == J->curtrace) {
lua_assert(J->trace[traceno] == &J->cur);
J->trace[traceno] = NULL;
J->curtrace = 0;
} else {
Trace *T = J->trace[traceno];
lua_assert(T != NULL && T != &J->cur);
J->trace[traceno] = NULL;
lj_mem_free(J2G(J), T,
((sizeof(Trace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) +
T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry));
}
}
/* Free all traces associated with a prototype. No unpatching needed. */
void lj_trace_freeproto(global_State *g, GCproto *pt)
{ {
jit_State *J = G2J(g); jit_State *J = G2J(g);
TraceNo traceno; if (T->traceno) {
/* Free all root traces. */ lj_gdbjit_deltrace(J, T);
for (traceno = pt->trace; traceno != 0; ) { if (T->traceno < J->freetrace)
TraceNo side, nextroot = J->trace[traceno]->nextroot; J->freetrace = T->traceno;
/* Free all side traces. */ setgcrefnull(J->trace[T->traceno]);
for (side = J->trace[traceno]->nextside; side != 0; ) {
TraceNo next = J->trace[side]->nextside;
trace_free(J, side);
side = next;
}
/* Now free the trace itself. */
trace_free(J, traceno);
traceno = nextroot;
} }
lj_mem_free(g, T,
((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) +
T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry));
} }
/* Re-enable compiling a prototype by unpatching any modified bytecode. */ /* Re-enable compiling a prototype by unpatching any modified bytecode. */
@ -160,7 +136,7 @@ void lj_trace_reenableproto(GCproto *pt)
} }
/* Unpatch the bytecode modified by a root trace. */ /* Unpatch the bytecode modified by a root trace. */
static void trace_unpatch(jit_State *J, Trace *T) static void trace_unpatch(jit_State *J, GCtrace *T)
{ {
BCOp op = bc_op(T->startins); BCOp op = bc_op(T->startins);
MSize pcofs = T->snap[0].mapofs + T->snap[0].nent; MSize pcofs = T->snap[0].mapofs + T->snap[0].nent;
@ -171,21 +147,21 @@ static void trace_unpatch(jit_State *J, Trace *T)
lua_assert(bc_op(*pc) == BC_JFORI); lua_assert(bc_op(*pc) == BC_JFORI);
setbc_op(pc, BC_FORI); /* Unpatch JFORI, too. */ setbc_op(pc, BC_FORI); /* Unpatch JFORI, too. */
pc += bc_j(*pc); pc += bc_j(*pc);
lua_assert(bc_op(*pc) == BC_JFORL && J->trace[bc_d(*pc)] == T); lua_assert(bc_op(*pc) == BC_JFORL && traceref(J, bc_d(*pc)) == T);
*pc = T->startins; *pc = T->startins;
break; break;
case BC_LOOP: case BC_LOOP:
lua_assert(bc_op(*pc) == BC_JLOOP && J->trace[bc_d(*pc)] == T); lua_assert(bc_op(*pc) == BC_JLOOP && traceref(J, bc_d(*pc)) == T);
*pc = T->startins; *pc = T->startins;
break; break;
case BC_ITERL: case BC_ITERL:
lua_assert(bc_op(*pc) == BC_JMP); lua_assert(bc_op(*pc) == BC_JMP);
pc += bc_j(*pc)+2; pc += bc_j(*pc)+2;
lua_assert(bc_op(*pc) == BC_JITERL && J->trace[bc_d(*pc)] == T); lua_assert(bc_op(*pc) == BC_JITERL && traceref(J, bc_d(*pc)) == T);
*pc = T->startins; *pc = T->startins;
break; break;
case BC_FUNCF: case BC_FUNCF:
lua_assert(bc_op(*pc) == BC_JFUNCF && J->trace[bc_d(*pc)] == T); lua_assert(bc_op(*pc) == BC_JFUNCF && traceref(J, bc_d(*pc)) == T);
*pc = T->startins; *pc = T->startins;
break; break;
case BC_JMP: /* No need to unpatch branches in parent traces (yet). */ case BC_JMP: /* No need to unpatch branches in parent traces (yet). */
@ -195,58 +171,41 @@ static void trace_unpatch(jit_State *J, Trace *T)
} }
} }
/* Free a root trace and any attached side traces. */ /* Flush a root trace. */
static void trace_freeroot(jit_State *J, Trace *T, TraceNo traceno) static void trace_flushroot(jit_State *J, GCtrace *T)
{ {
GCproto *pt = &gcref(T->startpt)->pt; GCproto *pt = &gcref(T->startpt)->pt;
TraceNo side;
lua_assert(T->root == 0 && pt != NULL); lua_assert(T->root == 0 && pt != NULL);
/* First unpatch any modified bytecode. */ /* First unpatch any modified bytecode. */
trace_unpatch(J, T); trace_unpatch(J, T);
/* Unlink root trace from chain anchored in prototype. */ /* Unlink root trace from chain anchored in prototype. */
if (pt->trace == traceno) { /* Trace is first in chain. Easy. */ if (pt->trace == T->traceno) { /* Trace is first in chain. Easy. */
pt->trace = T->nextroot; pt->trace = T->nextroot;
} else { /* Otherwise search in chain of root traces. */ } else { /* Otherwise search in chain of root traces. */
Trace *T2 = J->trace[pt->trace]; GCtrace *T2 = traceref(J, pt->trace);
while (T2->nextroot != traceno) { while (T2->nextroot != T->traceno) {
lua_assert(T2->nextroot != 0); lua_assert(T2->nextroot != 0);
T2 = J->trace[T2->nextroot]; T2 = traceref(J, T2->nextroot);
} }
T2->nextroot = T->nextroot; /* Unlink from chain. */ T2->nextroot = T->nextroot; /* Unlink from chain. */
} }
/* Free all side traces. */
for (side = T->nextside; side != 0; ) {
TraceNo next = J->trace[side]->nextside;
trace_free(J, side);
side = next;
}
/* Now free the trace itself. */
trace_free(J, traceno);
} }
/* Flush a root trace + side traces, if there are no links to it. */ /* Flush a trace. Only root traces are considered. */
int lj_trace_flush(jit_State *J, TraceNo traceno) void lj_trace_flush(jit_State *J, TraceNo traceno)
{ {
if (traceno > 0 && traceno < J->sizetrace) { if (traceno > 0 && traceno < J->sizetrace) {
Trace *T = J->trace[traceno]; GCtrace *T = traceref(J, traceno);
if (T && T->root == 0) { if (T && T->root == 0)
ptrdiff_t i; trace_flushroot(J, T);
for (i = (ptrdiff_t)J->sizetrace-1; i > 0; i--)
if (i != (ptrdiff_t)traceno && J->trace[i] &&
J->trace[i]->root != traceno && J->trace[i]->link == traceno)
return 0; /* Failed: existing link to trace. */
trace_freeroot(J, T, traceno);
return 1; /* Ok. */
} }
}
return 0; /* Failed. */
} }
/* Flush all traces associated with a prototype. */ /* Flush all traces associated with a prototype. */
void lj_trace_flushproto(global_State *g, GCproto *pt) void lj_trace_flushproto(global_State *g, GCproto *pt)
{ {
while (pt->trace != 0) while (pt->trace != 0)
trace_freeroot(G2J(g), G2J(g)->trace[pt->trace], pt->trace); trace_flushroot(G2J(g), traceref(G2J(g), pt->trace));
} }
/* Flush all traces. */ /* Flush all traces. */
@ -257,14 +216,16 @@ int lj_trace_flushall(lua_State *L)
if ((J2G(J)->hookmask & HOOK_GC)) if ((J2G(J)->hookmask & HOOK_GC))
return 1; return 1;
for (i = (ptrdiff_t)J->sizetrace-1; i > 0; i--) { for (i = (ptrdiff_t)J->sizetrace-1; i > 0; i--) {
Trace *T = J->trace[i]; GCtrace *T = traceref(J, i);
if (T && T->root == 0) if (T) {
trace_freeroot(J, T, (TraceNo)i); if (T->root == 0)
trace_flushroot(J, T);
lj_gdbjit_deltrace(J, T);
T->traceno = 0;
setgcrefnull(J->trace[i]);
} }
#ifdef LUA_USE_ASSERT }
for (i = 0; i < (ptrdiff_t)J->sizetrace; i++) J->curtrace = 0;
lua_assert(J->trace[i] == NULL);
#endif
J->freetrace = 0; J->freetrace = 0;
/* 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);
@ -293,11 +254,13 @@ void lj_trace_initstate(global_State *g)
void lj_trace_freestate(global_State *g) void lj_trace_freestate(global_State *g)
{ {
jit_State *J = G2J(g); jit_State *J = G2J(g);
if (J->curtrace)
lj_gdbjit_deltrace(J, &J->cur);
#ifdef LUA_USE_ASSERT #ifdef LUA_USE_ASSERT
{ /* This assumes all traces have already been freed. */ { /* This assumes all traces have already been freed. */
ptrdiff_t i; ptrdiff_t i;
for (i = 0; i < (ptrdiff_t)J->sizetrace; i++) for (i = 1; i < (ptrdiff_t)J->sizetrace; i++)
lua_assert(J->trace[i] == NULL); lua_assert(i == (ptrdiff_t)J->curtrace || traceref(J, i) == NULL);
} }
#endif #endif
lj_mcode_free(J); lj_mcode_free(J);
@ -305,7 +268,7 @@ void lj_trace_freestate(global_State *g)
lj_mem_freevec(g, J->snapmapbuf, J->sizesnapmap, SnapEntry); lj_mem_freevec(g, J->snapmapbuf, J->sizesnapmap, SnapEntry);
lj_mem_freevec(g, J->snapbuf, J->sizesnap, SnapShot); lj_mem_freevec(g, J->snapbuf, J->sizesnap, SnapShot);
lj_mem_freevec(g, J->irbuf + J->irbotlim, J->irtoplim - J->irbotlim, IRIns); lj_mem_freevec(g, J->irbuf + J->irbotlim, J->irtoplim - J->irbotlim, IRIns);
lj_mem_freevec(g, J->trace, J->sizetrace, Trace *); lj_mem_freevec(g, J->trace, J->sizetrace, GCRef);
} }
/* -- Penalties and blacklisting ------------------------------------------ */ /* -- Penalties and blacklisting ------------------------------------------ */
@ -349,9 +312,11 @@ static void trace_start(jit_State *J)
{ {
lua_State *L; lua_State *L;
if (J->curtrace != 0 && J->trace[J->curtrace] == &J->cur) { if (J->curtrace != 0 && traceref(J, J->curtrace) == &J->cur) {
J->trace[J->curtrace] = trace_save(J, &J->cur); /* Save current trace. */ TraceNo tr = J->curtrace; /* Save current trace. */
setgcrefp(J->trace[tr], trace_save(J, &J->cur));
J->curtrace = 0; J->curtrace = 0;
lj_gc_barriertrace(J2G(J), tr);
} }
if ((J->pt->flags & PROTO_NO_JIT)) { /* JIT disabled for this proto? */ if ((J->pt->flags & PROTO_NO_JIT)) { /* JIT disabled for this proto? */
@ -374,10 +339,11 @@ static void trace_start(jit_State *J)
J->state = LJ_TRACE_IDLE; /* Silently ignored. */ J->state = LJ_TRACE_IDLE; /* Silently ignored. */
return; return;
} }
J->trace[J->curtrace] = &J->cur; setgcrefp(J->trace[J->curtrace], &J->cur);
/* Setup enough of the current trace to be able to send the vmevent. */ /* Setup enough of the current trace to be able to send the vmevent. */
memset(&J->cur, 0, sizeof(Trace)); memset(&J->cur, 0, sizeof(GCtrace));
J->cur.traceno = J->curtrace;
J->cur.nins = J->cur.nk = REF_BASE; J->cur.nins = J->cur.nk = REF_BASE;
J->cur.ir = J->irbuf; J->cur.ir = J->irbuf;
J->cur.snap = J->snapbuf; J->cur.snap = J->snapbuf;
@ -385,6 +351,7 @@ static void trace_start(jit_State *J)
J->mergesnap = 0; J->mergesnap = 0;
J->needsnap = 0; J->needsnap = 0;
J->guardemit.irt = 0; J->guardemit.irt = 0;
setgcref(J->cur.startpt, obj2gco(J->pt));
L = J->L; L = J->L;
lj_vmevent_send(L, TRACE, lj_vmevent_send(L, TRACE,
@ -431,12 +398,12 @@ static void trace_stop(jit_State *J)
case BC_JMP: case BC_JMP:
/* Patch exit branch in parent to side trace entry. */ /* Patch exit branch in parent to side trace entry. */
lua_assert(J->parent != 0 && J->cur.root != 0); lua_assert(J->parent != 0 && J->cur.root != 0);
lj_asm_patchexit(J, J->trace[J->parent], J->exitno, J->cur.mcode); lj_asm_patchexit(J, traceref(J, J->parent), J->exitno, J->cur.mcode);
/* Avoid compiling a side trace twice (stack resizing uses parent exit). */ /* Avoid compiling a side trace twice (stack resizing uses parent exit). */
J->trace[J->parent]->snap[J->exitno].count = SNAPCOUNT_DONE; traceref(J, J->parent)->snap[J->exitno].count = SNAPCOUNT_DONE;
/* Add to side trace chain in root trace. */ /* Add to side trace chain in root trace. */
{ {
Trace *root = J->trace[J->cur.root]; GCtrace *root = traceref(J, J->cur.root);
root->nchild++; root->nchild++;
J->cur.nextside = root->nextside; J->cur.nextside = root->nextside;
root->nextside = (TraceNo1)J->curtrace; root->nextside = (TraceNo1)J->curtrace;
@ -510,7 +477,7 @@ static int trace_abort(jit_State *J)
copyTV(L, L->top++, &J->errinfo); copyTV(L, L->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). */
J->trace[J->curtrace] = NULL; setgcrefnull(J->trace[J->curtrace]);
if (J->curtrace < J->freetrace) if (J->curtrace < J->freetrace)
J->freetrace = J->curtrace; J->freetrace = J->curtrace;
J->curtrace = 0; J->curtrace = 0;
@ -631,7 +598,7 @@ void LJ_FASTCALL lj_trace_hot(jit_State *J, const BCIns *pc)
/* Check for a hot side exit. If yes, start recording a side trace. */ /* Check for a hot side exit. If yes, start recording a side trace. */
static void trace_hotside(jit_State *J, const BCIns *pc) static void trace_hotside(jit_State *J, const BCIns *pc)
{ {
SnapShot *snap = &J->trace[J->parent]->snap[J->exitno]; SnapShot *snap = &traceref(J, J->parent)->snap[J->exitno];
if (!(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT)) && if (!(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT)) &&
snap->count != SNAPCOUNT_DONE && snap->count != SNAPCOUNT_DONE &&
++snap->count >= J->param[JIT_P_hotexit]) { ++snap->count >= J->param[JIT_P_hotexit]) {
@ -699,7 +666,7 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
else else
trace_hotside(J, pc); trace_hotside(J, pc);
if (bc_op(*pc) == BC_JLOOP) { if (bc_op(*pc) == BC_JLOOP) {
BCIns *retpc = &J->trace[bc_d(*pc)]->startins; BCIns *retpc = &traceref(J, bc_d(*pc))->startins;
if (bc_isret(bc_op(*retpc))) { if (bc_isret(bc_op(*retpc))) {
if (J->state == LJ_TRACE_RECORD) { if (J->state == LJ_TRACE_RECORD) {
J->patchins = *pc; J->patchins = *pc;

View File

@ -23,10 +23,10 @@ LJ_FUNC_NORET void lj_trace_err(jit_State *J, TraceError e);
LJ_FUNC_NORET void lj_trace_err_info(jit_State *J, TraceError e); LJ_FUNC_NORET void lj_trace_err_info(jit_State *J, TraceError e);
/* Trace management. */ /* Trace management. */
LJ_FUNC void lj_trace_freeproto(global_State *g, GCproto *pt); LJ_FUNC void LJ_FASTCALL lj_trace_free(global_State *g, GCtrace *T);
LJ_FUNC void lj_trace_reenableproto(GCproto *pt); LJ_FUNC void lj_trace_reenableproto(GCproto *pt);
LJ_FUNC void lj_trace_flushproto(global_State *g, GCproto *pt); LJ_FUNC void lj_trace_flushproto(global_State *g, GCproto *pt);
LJ_FUNC int lj_trace_flush(jit_State *J, TraceNo traceno); LJ_FUNC void lj_trace_flush(jit_State *J, TraceNo traceno);
LJ_FUNC int lj_trace_flushall(lua_State *L); LJ_FUNC int lj_trace_flushall(lua_State *L);
LJ_FUNC void lj_trace_initstate(global_State *g); LJ_FUNC void lj_trace_initstate(global_State *g);
LJ_FUNC void lj_trace_freestate(global_State *g); LJ_FUNC void lj_trace_freestate(global_State *g);
@ -45,7 +45,6 @@ LJ_FUNCA int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr);
#define lj_trace_flushall(L) (UNUSED(L), 0) #define lj_trace_flushall(L) (UNUSED(L), 0)
#define lj_trace_initstate(g) UNUSED(g) #define lj_trace_initstate(g) UNUSED(g)
#define lj_trace_freestate(g) UNUSED(g) #define lj_trace_freestate(g) UNUSED(g)
#define lj_trace_freeproto(g, pt) (UNUSED(g), UNUSED(pt), (void)0)
#define lj_trace_abort(g) UNUSED(g) #define lj_trace_abort(g) UNUSED(g)
#define lj_trace_end(J) UNUSED(J) #define lj_trace_end(J) UNUSED(J)