Add trace stitching.

This commit is contained in:
Mike Pall
2013-12-25 02:55:25 +01:00
parent 6e02c210c4
commit b5d741fa7e
17 changed files with 422 additions and 69 deletions

View File

@@ -96,28 +96,81 @@ static ptrdiff_t results_wanted(jit_State *J)
return -1;
}
/* Throw error for unsupported variant of fast function. */
LJ_NORET static void recff_nyiu(jit_State *J)
/* Trace stitching: add continuation below frame to start a new trace. */
static void recff_stitch(jit_State *J)
{
setfuncV(J->L, &J->errinfo, J->fn);
lj_trace_err_info(J, LJ_TRERR_NYIFFU);
ASMFunction cont = lj_cont_stitch;
TraceNo traceno = J->cur.traceno;
lua_State *L = J->L;
TValue *base = L->base;
const BCIns *pc = frame_pc(base-1);
TValue *pframe = frame_prevl(base-1);
TRef trcont;
/* Move func + args up in Lua stack and insert continuation. */
memmove(&base[1], &base[-1], sizeof(TValue)*(J->maxslot+1));
setframe_ftsz(base+1, (int)((char *)(base+1) - (char *)pframe) + FRAME_CONT);
setcont(base, cont);
setframe_pc(base, pc);
if (LJ_DUALNUM) setintV(base-1, traceno); else base[-1].u64 = traceno;
L->base += 2;
L->top += 2;
/* Ditto for the IR. */
memmove(&J->base[1], &J->base[-1], sizeof(TRef)*(J->maxslot+1));
#if LJ_64
trcont = lj_ir_kptr(J, (void *)((int64_t)cont-(int64_t)lj_vm_asm_begin));
#else
trcont = lj_ir_kptr(J, (void *)cont);
#endif
J->base[0] = trcont | TREF_CONT;
J->base[-1] = LJ_DUALNUM ? lj_ir_kint(J,traceno) : lj_ir_knum_u64(J,traceno);
J->maxslot += 2;
J->framedepth++;
lj_record_stop(J, LJ_TRLINK_STITCH, 0);
/* Undo Lua stack changes. */
memmove(&base[-1], &base[1], sizeof(TValue)*(J->maxslot+1));
setframe_pc(base-1, pc);
L->base -= 2;
L->top -= 2;
}
/* Fallback handler for all fast functions that are not recorded (yet). */
/* Fallback handler for fast functions that are not recorded (yet). */
static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd)
{
setfuncV(J->L, &J->errinfo, J->fn);
lj_trace_err_info(J, LJ_TRERR_NYIFF);
UNUSED(rd);
if (J->cur.nins < (IRRef)J->param[JIT_P_minstitch] + REF_BASE) {
lj_trace_err_info(J, LJ_TRERR_TRACEUV);
} else {
/* Can only stitch from Lua call. */
if (J->framedepth && frame_islua(J->L->base-1)) {
BCOp op = bc_op(*frame_pc(J->L->base-1));
/* Stitched trace cannot start with *M op with variable # of args. */
if (!(op == BC_CALLM || op == BC_RETM || op == BC_TSETM)) {
switch (J->fn->c.ffid) {
case FF_error:
case FF_debug_sethook:
case FF_jit_flush:
break; /* Don't stitch across special builtins. */
default:
recff_stitch(J); /* Use trace stitching. */
rd->nres = -1;
return;
}
}
}
/* Otherwise stop trace and return to interpreter. */
lj_record_stop(J, LJ_TRLINK_RETURN, 0);
rd->nres = -1;
}
}
/* C functions can have arbitrary side-effects and are not recorded (yet). */
static void LJ_FASTCALL recff_c(jit_State *J, RecordFFData *rd)
{
setfuncV(J->L, &J->errinfo, J->fn);
lj_trace_err_info(J, LJ_TRERR_NYICF);
UNUSED(rd);
}
/* Fallback handler for unsupported variants of fast functions. */
#define recff_nyiu recff_nyi
/* Must stop the trace for classic C functions with arbitrary side-effects. */
#define recff_c recff_nyi
/* Emit BUFHDR for the global temporary buffer. */
static TRef recff_bufhdr(jit_State *J)
@@ -268,7 +321,8 @@ static void LJ_FASTCALL recff_select(jit_State *J, RecordFFData *rd)
J->base[i] = J->base[start+i];
} /* else: Interpreter will throw. */
} else {
recff_nyiu(J);
recff_nyiu(J, rd);
return;
}
} /* else: Interpreter will throw. */
}
@@ -279,14 +333,18 @@ static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd)
TRef base = J->base[1];
if (tr && !tref_isnil(base)) {
base = lj_opt_narrow_toint(J, base);
if (!tref_isk(base) || IR(tref_ref(base))->i != 10)
recff_nyiu(J);
if (!tref_isk(base) || IR(tref_ref(base))->i != 10) {
recff_nyiu(J, rd);
return;
}
}
if (tref_isnumber_str(tr)) {
if (tref_isstr(tr)) {
TValue tmp;
if (!lj_strscan_num(strV(&rd->argv[0]), &tmp))
recff_nyiu(J); /* Would need an inverted STRTO for this case. */
if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) {
recff_nyiu(J, rd); /* Would need an inverted STRTO for this case. */
return;
}
tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0);
}
#if LJ_HASFFI
@@ -348,7 +406,8 @@ static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd)
} else if (tref_ispri(tr)) {
J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0]));
} else {
recff_nyiu(J);
recff_nyiu(J, rd);
return;
}
}
}
@@ -370,14 +429,14 @@ static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd)
} /* else: Interpreter will throw. */
}
static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd)
static void LJ_FASTCALL recff_xpairs(jit_State *J, RecordFFData *rd)
{
if (!(LJ_52 && recff_metacall(J, rd, MM_ipairs))) {
TRef tab = J->base[0];
if (tref_istab(tab)) {
J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0]));
J->base[1] = tab;
J->base[2] = lj_ir_kint(J, 0);
J->base[2] = rd->data ? lj_ir_kint(J, 0) : TREF_NIL;
rd->nres = 3;
} /* else: Interpreter will throw. */
}
@@ -431,8 +490,7 @@ static void LJ_FASTCALL recff_getfenv(jit_State *J, RecordFFData *rd)
J->base[0] = emitir(IRT(IR_FLOAD, IRT_TAB), trl, IRFL_THREAD_ENV);
return;
}
recff_nyiu(J);
UNUSED(rd);
recff_nyiu(J, rd);
}
/* -- Math library fast functions ----------------------------------------- */
@@ -672,8 +730,7 @@ static void LJ_FASTCALL recff_bit_tohex(jit_State *J, RecordFFData *rd)
TRef tr = recff_bit64_tohex(J, rd, hdr);
J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
#else
UNUSED(rd);
recff_nyiu(J); /* Don't bother working around this NYI. */
recff_nyiu(J, rd); /* Don't bother working around this NYI. */
#endif
}
@@ -891,7 +948,8 @@ static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd)
J->base[0] = TREF_NIL;
}
} else { /* Search for pattern. */
recff_nyiu(J);
recff_nyiu(J, rd);
return;
}
}
@@ -931,7 +989,8 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra);
lj_needsplit(J);
#else
recff_nyiu(J); /* Don't bother working around this NYI. */
recff_nyiu(J, rd); /* Don't bother working around this NYI. */
return;
#endif
}
break;
@@ -946,8 +1005,10 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
if (LJ_SOFTFP) lj_needsplit(J);
break;
case STRFMT_STR:
if (!tref_isstr(tra))
recff_nyiu(J); /* NYI: __tostring and non-string types for %s. */
if (!tref_isstr(tra)) {
recff_nyiu(J, rd); /* NYI: __tostring and non-string types for %s. */
return;
}
if (sf == STRFMT_STR) /* Shortcut for plain %s. */
tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, tra);
else if ((sf & STRFMT_T_QUOTED))
@@ -966,8 +1027,8 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
case STRFMT_PTR: /* NYI */
case STRFMT_ERR:
default:
recff_nyiu(J);
break;
recff_nyiu(J, rd);
return;
}
}
J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
@@ -991,7 +1052,8 @@ static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
ix.idxchain = 0;
lj_record_idx(J, &ix); /* Set new value. */
} else { /* Complex case: insert in the middle. */
recff_nyiu(J);
recff_nyiu(J, rd);
return;
}
} /* else: Interpreter will throw. */
}