2009-12-08 18:46:35 +00:00
|
|
|
/*
|
|
|
|
** Snapshot handling.
|
2011-01-09 16:12:53 +00:00
|
|
|
** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
|
2009-12-08 18:46:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define lj_snap_c
|
|
|
|
#define LUA_CORE
|
|
|
|
|
|
|
|
#include "lj_obj.h"
|
|
|
|
|
|
|
|
#if LJ_HASJIT
|
|
|
|
|
|
|
|
#include "lj_gc.h"
|
|
|
|
#include "lj_state.h"
|
|
|
|
#include "lj_frame.h"
|
|
|
|
#include "lj_ir.h"
|
|
|
|
#include "lj_jit.h"
|
|
|
|
#include "lj_iropt.h"
|
|
|
|
#include "lj_trace.h"
|
|
|
|
#include "lj_snap.h"
|
|
|
|
#include "lj_target.h"
|
|
|
|
|
|
|
|
/* Some local macros to save typing. Undef'd at the end. */
|
|
|
|
#define IR(ref) (&J->cur.ir[(ref)])
|
|
|
|
|
2010-01-26 20:49:04 +00:00
|
|
|
/* -- Snapshot buffer allocation ------------------------------------------ */
|
|
|
|
|
|
|
|
/* Grow snapshot buffer. */
|
|
|
|
void lj_snap_grow_buf_(jit_State *J, MSize need)
|
|
|
|
{
|
|
|
|
MSize maxsnap = (MSize)J->param[JIT_P_maxsnap];
|
|
|
|
if (need > maxsnap)
|
|
|
|
lj_trace_err(J, LJ_TRERR_SNAPOV);
|
|
|
|
lj_mem_growvec(J->L, J->snapbuf, J->sizesnap, maxsnap, SnapShot);
|
|
|
|
J->cur.snap = J->snapbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Grow snapshot map buffer. */
|
|
|
|
void lj_snap_grow_map_(jit_State *J, MSize need)
|
|
|
|
{
|
|
|
|
if (need < 2*J->sizesnapmap)
|
|
|
|
need = 2*J->sizesnapmap;
|
|
|
|
else if (need < 64)
|
|
|
|
need = 64;
|
|
|
|
J->snapmapbuf = (SnapEntry *)lj_mem_realloc(J->L, J->snapmapbuf,
|
|
|
|
J->sizesnapmap*sizeof(SnapEntry), need*sizeof(SnapEntry));
|
|
|
|
J->cur.snapmap = J->snapmapbuf;
|
|
|
|
J->sizesnapmap = need;
|
|
|
|
}
|
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
/* -- Snapshot generation ------------------------------------------------- */
|
|
|
|
|
|
|
|
/* Add all modified slots to the snapshot. */
|
2010-01-25 18:51:52 +00:00
|
|
|
static MSize snapshot_slots(jit_State *J, SnapEntry *map, BCReg nslots)
|
2009-12-08 18:46:35 +00:00
|
|
|
{
|
2010-02-23 02:08:49 +00:00
|
|
|
IRRef retf = J->chain[IR_RETF]; /* Limits SLOAD restore elimination. */
|
2009-12-08 18:46:35 +00:00
|
|
|
BCReg s;
|
2010-01-26 20:49:04 +00:00
|
|
|
MSize n = 0;
|
2009-12-08 18:46:35 +00:00
|
|
|
for (s = 0; s < nslots; s++) {
|
2010-01-27 01:17:56 +00:00
|
|
|
TRef tr = J->slot[s];
|
|
|
|
IRRef ref = tref_ref(tr);
|
2009-12-08 18:46:35 +00:00
|
|
|
if (ref) {
|
2010-02-23 02:08:49 +00:00
|
|
|
SnapEntry sn = SNAP_TR(s, tr);
|
2009-12-08 18:46:35 +00:00
|
|
|
IRIns *ir = IR(ref);
|
2010-02-23 02:08:49 +00:00
|
|
|
if (ir->o == IR_SLOAD && ir->op1 == s && ref > retf) {
|
|
|
|
/* No need to snapshot unmodified non-inherited slots. */
|
|
|
|
if (!(ir->op2 & IRSLOAD_INHERIT))
|
|
|
|
continue;
|
|
|
|
/* No need to restore readonly slots and unmodified non-parent slots. */
|
|
|
|
if ((ir->op2 & (IRSLOAD_READONLY|IRSLOAD_PARENT)) != IRSLOAD_PARENT)
|
|
|
|
sn |= SNAP_NORESTORE;
|
|
|
|
}
|
|
|
|
map[n++] = sn;
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-26 20:49:04 +00:00
|
|
|
return n;
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
|
2010-02-18 02:19:46 +00:00
|
|
|
/* Add frame links at the end of the snapshot. */
|
|
|
|
static void snapshot_framelinks(jit_State *J, SnapEntry *map)
|
|
|
|
{
|
|
|
|
cTValue *frame = J->L->base - 1;
|
|
|
|
cTValue *lim = J->L->base - J->baseslot;
|
|
|
|
MSize f = 0;
|
|
|
|
map[f++] = SNAP_MKPC(J->pc); /* The current PC is always the first entry. */
|
|
|
|
while (frame > lim) { /* Backwards traversal of all frames above base. */
|
|
|
|
if (frame_islua(frame)) {
|
|
|
|
map[f++] = SNAP_MKPC(frame_pc(frame));
|
|
|
|
frame = frame_prevl(frame);
|
|
|
|
} else if (frame_iscont(frame)) {
|
|
|
|
map[f++] = SNAP_MKFTSZ(frame_ftsz(frame));
|
|
|
|
map[f++] = SNAP_MKPC(frame_contpc(frame));
|
|
|
|
frame = frame_prevd(frame);
|
|
|
|
} else {
|
2010-09-11 23:37:02 +00:00
|
|
|
lua_assert(!frame_isc(frame));
|
|
|
|
map[f++] = SNAP_MKFTSZ(frame_ftsz(frame));
|
|
|
|
frame = frame_prevd(frame);
|
2010-02-18 02:19:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_assert(f == (MSize)(1 + J->framedepth));
|
|
|
|
}
|
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
/* Take a snapshot of the current stack. */
|
|
|
|
static void snapshot_stack(jit_State *J, SnapShot *snap, MSize nsnapmap)
|
|
|
|
{
|
|
|
|
BCReg nslots = J->baseslot + J->maxslot;
|
2010-02-04 02:08:29 +00:00
|
|
|
MSize nent;
|
2010-01-25 18:51:52 +00:00
|
|
|
SnapEntry *p;
|
2010-02-04 02:08:29 +00:00
|
|
|
/* Conservative estimate. */
|
|
|
|
lj_snap_grow_map(J, nsnapmap + nslots + (MSize)J->framedepth+1);
|
2009-12-08 18:46:35 +00:00
|
|
|
p = &J->cur.snapmap[nsnapmap];
|
2010-01-26 20:49:04 +00:00
|
|
|
nent = snapshot_slots(J, p, nslots);
|
2010-02-18 02:19:46 +00:00
|
|
|
snapshot_framelinks(J, p + nent);
|
2009-12-08 18:46:35 +00:00
|
|
|
snap->mapofs = (uint16_t)nsnapmap;
|
|
|
|
snap->ref = (IRRef1)J->cur.nins;
|
2010-01-26 20:49:04 +00:00
|
|
|
snap->nent = (uint8_t)nent;
|
2010-02-04 02:08:29 +00:00
|
|
|
snap->depth = (uint8_t)J->framedepth;
|
2010-01-26 20:49:04 +00:00
|
|
|
snap->nslots = (uint8_t)nslots;
|
2009-12-08 18:46:35 +00:00
|
|
|
snap->count = 0;
|
2010-02-04 02:08:29 +00:00
|
|
|
J->cur.nsnapmap = (uint16_t)(nsnapmap + nent + 1 + J->framedepth);
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add or merge a snapshot. */
|
|
|
|
void lj_snap_add(jit_State *J)
|
|
|
|
{
|
|
|
|
MSize nsnap = J->cur.nsnap;
|
|
|
|
MSize nsnapmap = J->cur.nsnapmap;
|
|
|
|
/* Merge if no ins. inbetween or if requested and no guard inbetween. */
|
|
|
|
if (J->mergesnap ? !irt_isguard(J->guardemit) :
|
|
|
|
(nsnap > 0 && J->cur.snap[nsnap-1].ref == J->cur.nins)) {
|
|
|
|
nsnapmap = J->cur.snap[--nsnap].mapofs;
|
|
|
|
} else {
|
2010-01-26 20:49:04 +00:00
|
|
|
lj_snap_grow_buf(J, nsnap+1);
|
2009-12-08 18:46:35 +00:00
|
|
|
J->cur.nsnap = (uint16_t)(nsnap+1);
|
|
|
|
}
|
|
|
|
J->mergesnap = 0;
|
|
|
|
J->guardemit.irt = 0;
|
|
|
|
snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Shrink last snapshot. */
|
|
|
|
void lj_snap_shrink(jit_State *J)
|
|
|
|
{
|
|
|
|
BCReg nslots = J->baseslot + J->maxslot;
|
|
|
|
SnapShot *snap = &J->cur.snap[J->cur.nsnap-1];
|
2010-01-26 20:49:04 +00:00
|
|
|
SnapEntry *map = &J->cur.snapmap[snap->mapofs];
|
|
|
|
MSize nent = snap->nent;
|
2009-12-08 18:46:35 +00:00
|
|
|
lua_assert(nslots < snap->nslots);
|
|
|
|
snap->nslots = (uint8_t)nslots;
|
2010-01-26 20:49:04 +00:00
|
|
|
if (nent > 0 && snap_slot(map[nent-1]) >= nslots) {
|
2010-02-04 02:08:29 +00:00
|
|
|
MSize s, delta, depth = snap->depth;
|
2010-02-18 02:19:46 +00:00
|
|
|
lua_assert(depth == (MSize)J->framedepth);
|
2010-01-26 20:49:04 +00:00
|
|
|
for (nent--; nent > 0 && snap_slot(map[nent-1]) >= nslots; nent--)
|
|
|
|
;
|
|
|
|
delta = snap->nent - nent;
|
|
|
|
snap->nent = (uint8_t)nent;
|
2010-02-04 02:08:29 +00:00
|
|
|
J->cur.nsnapmap = (uint16_t)(snap->mapofs + nent + 1 + depth);
|
2010-01-26 20:49:04 +00:00
|
|
|
map += nent;
|
2010-02-04 02:08:29 +00:00
|
|
|
for (s = 0; s <= depth; s++) /* Move PC + frame links down. */
|
2010-01-26 20:49:04 +00:00
|
|
|
map[s] = map[s+delta];
|
|
|
|
}
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -- Snapshot access ----------------------------------------------------- */
|
|
|
|
|
|
|
|
/* Initialize a Bloom Filter with all renamed refs.
|
|
|
|
** There are very few renames (often none), so the filter has
|
|
|
|
** very few bits set. This makes it suitable for negative filtering.
|
|
|
|
*/
|
2010-04-25 01:32:29 +00:00
|
|
|
static BloomFilter snap_renamefilter(GCtrace *T, SnapNo lim)
|
2009-12-08 18:46:35 +00:00
|
|
|
{
|
|
|
|
BloomFilter rfilt = 0;
|
|
|
|
IRIns *ir;
|
|
|
|
for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
|
|
|
|
if (ir->op2 <= lim)
|
|
|
|
bloomset(rfilt, ir->op1);
|
|
|
|
return rfilt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process matching renames to find the original RegSP. */
|
2010-04-25 01:32:29 +00:00
|
|
|
static RegSP snap_renameref(GCtrace *T, SnapNo lim, IRRef ref, RegSP rs)
|
2009-12-08 18:46:35 +00:00
|
|
|
{
|
|
|
|
IRIns *ir;
|
|
|
|
for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
|
|
|
|
if (ir->op1 == ref && ir->op2 <= lim)
|
|
|
|
rs = ir->prev;
|
|
|
|
return rs;
|
|
|
|
}
|
|
|
|
|
2010-01-26 20:49:04 +00:00
|
|
|
/* Convert a snapshot into a linear slot -> RegSP map.
|
|
|
|
** Note: unused slots are not initialized!
|
|
|
|
*/
|
2010-04-25 01:32:29 +00:00
|
|
|
void lj_snap_regspmap(uint16_t *rsmap, GCtrace *T, SnapNo snapno)
|
2009-12-08 18:46:35 +00:00
|
|
|
{
|
|
|
|
SnapShot *snap = &T->snap[snapno];
|
2010-01-26 20:49:04 +00:00
|
|
|
MSize n, nent = snap->nent;
|
2010-01-25 18:51:52 +00:00
|
|
|
SnapEntry *map = &T->snapmap[snap->mapofs];
|
2009-12-08 18:46:35 +00:00
|
|
|
BloomFilter rfilt = snap_renamefilter(T, snapno);
|
2010-01-26 20:49:04 +00:00
|
|
|
for (n = 0; n < nent; n++) {
|
|
|
|
SnapEntry sn = map[n];
|
|
|
|
IRRef ref = snap_ref(sn);
|
2009-12-08 18:46:35 +00:00
|
|
|
if (!irref_isk(ref)) {
|
|
|
|
IRIns *ir = &T->ir[ref];
|
|
|
|
uint32_t rs = ir->prev;
|
|
|
|
if (bloomtest(rfilt, ref))
|
|
|
|
rs = snap_renameref(T, snapno, ref, rs);
|
2010-01-26 20:49:04 +00:00
|
|
|
rsmap[snap_slot(sn)] = (uint16_t)rs;
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore interpreter state from exit state with the help of a snapshot. */
|
2010-02-15 15:41:52 +00:00
|
|
|
const BCIns *lj_snap_restore(jit_State *J, void *exptr)
|
2009-12-08 18:46:35 +00:00
|
|
|
{
|
|
|
|
ExitState *ex = (ExitState *)exptr;
|
|
|
|
SnapNo snapno = J->exitno; /* For now, snapno == exitno. */
|
2010-04-25 01:32:29 +00:00
|
|
|
GCtrace *T = traceref(J, J->parent);
|
2009-12-08 18:46:35 +00:00
|
|
|
SnapShot *snap = &T->snap[snapno];
|
2010-01-26 20:49:04 +00:00
|
|
|
MSize n, nent = snap->nent;
|
2010-01-25 18:51:52 +00:00
|
|
|
SnapEntry *map = &T->snapmap[snap->mapofs];
|
2010-02-18 02:19:46 +00:00
|
|
|
SnapEntry *flinks = map + nent + snap->depth;
|
2010-01-27 02:50:29 +00:00
|
|
|
int32_t ftsz0;
|
2010-01-26 20:49:04 +00:00
|
|
|
BCReg nslots = snap->nslots;
|
|
|
|
TValue *frame;
|
2009-12-08 18:46:35 +00:00
|
|
|
BloomFilter rfilt = snap_renamefilter(T, snapno);
|
2010-02-19 02:13:48 +00:00
|
|
|
const BCIns *pc = snap_pc(map[nent]);
|
2009-12-08 18:46:35 +00:00
|
|
|
lua_State *L = J->L;
|
|
|
|
|
2010-02-19 02:13:48 +00:00
|
|
|
/* Set interpreter PC to the next PC to get correct error messages. */
|
|
|
|
setcframe_pc(cframe_raw(L->cframe), pc+1);
|
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
/* Make sure the stack is big enough for the slots from the snapshot. */
|
2010-09-09 10:28:17 +00:00
|
|
|
if (LJ_UNLIKELY(L->base + nslots > tvref(L->maxstack))) {
|
2009-12-08 18:46:35 +00:00
|
|
|
L->top = curr_topL(L);
|
|
|
|
lj_state_growstack(L, nslots - curr_proto(L)->framesize);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fill stack slots with data from the registers and spill slots. */
|
2010-01-26 20:49:04 +00:00
|
|
|
frame = L->base-1;
|
2010-01-27 02:50:29 +00:00
|
|
|
ftsz0 = frame_ftsz(frame); /* Preserve link to previous frame in slot #0. */
|
2010-01-26 20:49:04 +00:00
|
|
|
for (n = 0; n < nent; n++) {
|
2010-01-27 01:17:56 +00:00
|
|
|
SnapEntry sn = map[n];
|
|
|
|
IRRef ref = snap_ref(sn);
|
|
|
|
BCReg s = snap_slot(sn);
|
2010-01-26 20:49:04 +00:00
|
|
|
TValue *o = &frame[s]; /* Stack slots are relative to start frame. */
|
|
|
|
IRIns *ir = &T->ir[ref];
|
|
|
|
if (irref_isk(ref)) { /* Restore constant slot. */
|
|
|
|
lj_ir_kvalue(L, o, ir);
|
2010-01-27 02:50:29 +00:00
|
|
|
if ((sn & (SNAP_CONT|SNAP_FRAME))) {
|
|
|
|
/* Overwrite tag with frame link. */
|
2010-02-18 02:19:46 +00:00
|
|
|
o->fr.tp.ftsz = s != 0 ? (int32_t)*flinks-- : ftsz0;
|
2010-01-27 02:50:29 +00:00
|
|
|
if ((sn & SNAP_FRAME)) {
|
|
|
|
GCfunc *fn = ir_kfunc(ir);
|
|
|
|
if (isluafunc(fn)) {
|
|
|
|
MSize framesize = funcproto(fn)->framesize;
|
|
|
|
L->base = ++o;
|
2010-09-09 10:28:17 +00:00
|
|
|
if (LJ_UNLIKELY(o + framesize > tvref(L->maxstack))) {
|
2010-01-27 02:50:29 +00:00
|
|
|
ptrdiff_t fsave = savestack(L, frame);
|
|
|
|
L->top = o;
|
2010-09-09 10:28:17 +00:00
|
|
|
lj_state_growstack(L, framesize); /* Grow again. */
|
2010-01-27 02:50:29 +00:00
|
|
|
frame = restorestack(L, fsave);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-04-07 23:28:51 +00:00
|
|
|
} else if (!(sn & SNAP_NORESTORE)) {
|
2010-01-26 20:49:04 +00:00
|
|
|
IRType1 t = ir->t;
|
|
|
|
RegSP rs = ir->prev;
|
2010-01-27 02:50:29 +00:00
|
|
|
lua_assert(!(sn & (SNAP_CONT|SNAP_FRAME)));
|
2010-01-26 20:49:04 +00:00
|
|
|
if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
|
|
|
|
rs = snap_renameref(T, snapno, ref, rs);
|
|
|
|
if (ra_hasspill(regsp_spill(rs))) { /* Restore from spill slot. */
|
|
|
|
int32_t *sps = &ex->spill[regsp_spill(rs)];
|
|
|
|
if (irt_isinteger(t)) {
|
|
|
|
setintV(o, *sps);
|
|
|
|
} else if (irt_isnum(t)) {
|
|
|
|
o->u64 = *(uint64_t *)sps;
|
2010-02-24 06:09:34 +00:00
|
|
|
#if LJ_64
|
|
|
|
} else if (irt_islightud(t)) {
|
|
|
|
/* 64 bit lightuserdata which may escape already has the tag bits. */
|
|
|
|
o->u64 = *(uint64_t *)sps;
|
|
|
|
#endif
|
2010-01-26 20:49:04 +00:00
|
|
|
} else {
|
|
|
|
lua_assert(!irt_ispri(t)); /* PRI refs never have a spill slot. */
|
|
|
|
setgcrefi(o->gcr, *sps);
|
|
|
|
setitype(o, irt_toitype(t));
|
|
|
|
}
|
2010-01-27 02:50:29 +00:00
|
|
|
} else { /* Restore from register. */
|
2010-01-26 20:49:04 +00:00
|
|
|
Reg r = regsp_reg(rs);
|
2010-01-27 02:50:29 +00:00
|
|
|
lua_assert(ra_hasreg(r));
|
2010-01-26 20:49:04 +00:00
|
|
|
if (irt_isinteger(t)) {
|
|
|
|
setintV(o, ex->gpr[r-RID_MIN_GPR]);
|
|
|
|
} else if (irt_isnum(t)) {
|
|
|
|
setnumV(o, ex->fpr[r-RID_MIN_FPR]);
|
2010-02-24 06:09:34 +00:00
|
|
|
#if LJ_64
|
|
|
|
} else if (irt_islightud(t)) {
|
|
|
|
/* 64 bit lightuserdata which may escape already has the tag bits. */
|
|
|
|
o->u64 = ex->gpr[r-RID_MIN_GPR];
|
|
|
|
#endif
|
2010-01-26 20:49:04 +00:00
|
|
|
} else {
|
|
|
|
if (!irt_ispri(t))
|
|
|
|
setgcrefi(o->gcr, ex->gpr[r-RID_MIN_GPR]);
|
|
|
|
setitype(o, irt_toitype(t));
|
|
|
|
}
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-03-13 16:45:09 +00:00
|
|
|
switch (bc_op(*pc)) {
|
|
|
|
case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM:
|
|
|
|
L->top = frame + nslots;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
L->top = curr_topL(L);
|
|
|
|
break;
|
|
|
|
}
|
2010-02-18 02:19:46 +00:00
|
|
|
lua_assert(map + nent == flinks);
|
2010-02-19 02:13:48 +00:00
|
|
|
return pc;
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef IR
|
|
|
|
|
|
|
|
#endif
|