summaryrefslogtreecommitdiff
path: root/src/lj_snap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_snap.c')
-rw-r--r--src/lj_snap.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/lj_snap.c b/src/lj_snap.c
new file mode 100644
index 00000000..09cd095c
--- /dev/null
+++ b/src/lj_snap.c
@@ -0,0 +1,286 @@
1/*
2** Snapshot handling.
3** Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lj_snap_c
7#define LUA_CORE
8
9#include "lj_obj.h"
10
11#if LJ_HASJIT
12
13#include "lj_gc.h"
14#include "lj_state.h"
15#include "lj_frame.h"
16#include "lj_ir.h"
17#include "lj_jit.h"
18#include "lj_iropt.h"
19#include "lj_trace.h"
20#include "lj_snap.h"
21#include "lj_target.h"
22
23/* Some local macros to save typing. Undef'd at the end. */
24#define IR(ref) (&J->cur.ir[(ref)])
25
26/* -- Snapshot generation ------------------------------------------------- */
27
28/* NYI: Snapshots are in need of a redesign. The current storage model for
29** snapshot maps is too wasteful. They could be compressed (1D or 2D) and
30** made more flexible at the same time. Iterators should no longer need to
31** skip unmodified slots. IR_FRAME should be eliminated, too.
32*/
33
34/* Add all modified slots to the snapshot. */
35static void snapshot_slots(jit_State *J, IRRef2 *map, BCReg nslots)
36{
37 BCReg s;
38 for (s = 0; s < nslots; s++) {
39 IRRef ref = tref_ref(J->slot[s]);
40 if (ref) {
41 IRIns *ir = IR(ref);
42 if (ir->o == IR_SLOAD && ir->op1 == s && !(ir->op2 & IRSLOAD_INHERIT))
43 ref = 0;
44 }
45 map[s] = (IRRef2)ref;
46 }
47}
48
49/* Add frame links at the end of the snapshot. */
50static MSize snapshot_framelinks(jit_State *J, IRRef2 *map)
51{
52 cTValue *frame = J->L->base - 1;
53 cTValue *lim = J->L->base - J->baseslot;
54 MSize f = 0;
55 map[f++] = u32ptr(J->pc);
56 while (frame > lim) {
57 if (frame_islua(frame)) {
58 map[f++] = u32ptr(frame_pc(frame));
59 frame = frame_prevl(frame);
60 } else if (frame_ispcall(frame)) {
61 map[f++] = (uint32_t)frame_ftsz(frame);
62 frame = frame_prevd(frame);
63 } else if (frame_iscont(frame)) {
64 map[f++] = (uint32_t)frame_ftsz(frame);
65 map[f++] = u32ptr(frame_contpc(frame));
66 frame = frame_prevd(frame);
67 } else {
68 lua_assert(0);
69 }
70 }
71 return f;
72}
73
74/* Take a snapshot of the current stack. */
75static void snapshot_stack(jit_State *J, SnapShot *snap, MSize nsnapmap)
76{
77 BCReg nslots = J->baseslot + J->maxslot;
78 MSize nsm, nframelinks;
79 IRRef2 *p;
80 /* Conservative estimate. Continuation frames need 2 slots. */
81 nsm = nsnapmap + nslots + (uint32_t)J->framedepth*2+1;
82 if (LJ_UNLIKELY(nsm > J->sizesnapmap)) { /* Need to grow snapshot map? */
83 if (nsm < 2*J->sizesnapmap)
84 nsm = 2*J->sizesnapmap;
85 else if (nsm < 64)
86 nsm = 64;
87 J->snapmapbuf = (IRRef2 *)lj_mem_realloc(J->L, J->snapmapbuf,
88 J->sizesnapmap*sizeof(IRRef2), nsm*sizeof(IRRef2));
89 J->cur.snapmap = J->snapmapbuf;
90 J->sizesnapmap = nsm;
91 }
92 p = &J->cur.snapmap[nsnapmap];
93 snapshot_slots(J, p, nslots);
94 nframelinks = snapshot_framelinks(J, p + nslots);
95 J->cur.nsnapmap = (uint16_t)(nsnapmap + nslots + nframelinks);
96 snap->mapofs = (uint16_t)nsnapmap;
97 snap->ref = (IRRef1)J->cur.nins;
98 snap->nslots = (uint8_t)nslots;
99 snap->nframelinks = (uint8_t)nframelinks;
100 snap->count = 0;
101}
102
103/* Add or merge a snapshot. */
104void lj_snap_add(jit_State *J)
105{
106 MSize nsnap = J->cur.nsnap;
107 MSize nsnapmap = J->cur.nsnapmap;
108 /* Merge if no ins. inbetween or if requested and no guard inbetween. */
109 if (J->mergesnap ? !irt_isguard(J->guardemit) :
110 (nsnap > 0 && J->cur.snap[nsnap-1].ref == J->cur.nins)) {
111 nsnapmap = J->cur.snap[--nsnap].mapofs;
112 } else {
113 /* Need to grow snapshot buffer? */
114 if (LJ_UNLIKELY(nsnap >= J->sizesnap)) {
115 MSize maxsnap = (MSize)J->param[JIT_P_maxsnap];
116 if (nsnap >= maxsnap)
117 lj_trace_err(J, LJ_TRERR_SNAPOV);
118 lj_mem_growvec(J->L, J->snapbuf, J->sizesnap, maxsnap, SnapShot);
119 J->cur.snap = J->snapbuf;
120 }
121 J->cur.nsnap = (uint16_t)(nsnap+1);
122 }
123 J->mergesnap = 0;
124 J->guardemit.irt = 0;
125 snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap);
126}
127
128/* Shrink last snapshot. */
129void lj_snap_shrink(jit_State *J)
130{
131 BCReg nslots = J->baseslot + J->maxslot;
132 SnapShot *snap = &J->cur.snap[J->cur.nsnap-1];
133 IRRef2 *oflinks = &J->cur.snapmap[snap->mapofs + snap->nslots];
134 IRRef2 *nflinks = &J->cur.snapmap[snap->mapofs + nslots];
135 uint32_t s, nframelinks = snap->nframelinks;
136 lua_assert(nslots < snap->nslots);
137 snap->nslots = (uint8_t)nslots;
138 J->cur.nsnapmap = (uint16_t)(snap->mapofs + nslots + nframelinks);
139 for (s = 0; s < nframelinks; s++) /* Move frame links down. */
140 nflinks[s] = oflinks[s];
141}
142
143/* -- Snapshot access ----------------------------------------------------- */
144
145/* Initialize a Bloom Filter with all renamed refs.
146** There are very few renames (often none), so the filter has
147** very few bits set. This makes it suitable for negative filtering.
148*/
149static BloomFilter snap_renamefilter(Trace *T, SnapNo lim)
150{
151 BloomFilter rfilt = 0;
152 IRIns *ir;
153 for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
154 if (ir->op2 <= lim)
155 bloomset(rfilt, ir->op1);
156 return rfilt;
157}
158
159/* Process matching renames to find the original RegSP. */
160static RegSP snap_renameref(Trace *T, SnapNo lim, IRRef ref, RegSP rs)
161{
162 IRIns *ir;
163 for (ir = &T->ir[T->nins-1]; ir->o == IR_RENAME; ir--)
164 if (ir->op1 == ref && ir->op2 <= lim)
165 rs = ir->prev;
166 return rs;
167}
168
169/* Convert a snapshot into a linear slot -> RegSP map. */
170void lj_snap_regspmap(uint16_t *rsmap, Trace *T, SnapNo snapno)
171{
172 SnapShot *snap = &T->snap[snapno];
173 BCReg s, nslots = snap->nslots;
174 IRRef2 *map = &T->snapmap[snap->mapofs];
175 BloomFilter rfilt = snap_renamefilter(T, snapno);
176 for (s = 0; s < nslots; s++) {
177 IRRef ref = snap_ref(map[s]);
178 if (!irref_isk(ref)) {
179 IRIns *ir = &T->ir[ref];
180 uint32_t rs = ir->prev;
181 if (bloomtest(rfilt, ref))
182 rs = snap_renameref(T, snapno, ref, rs);
183 rsmap[s] = (uint16_t)rs;
184 }
185 }
186}
187
188/* Restore interpreter state from exit state with the help of a snapshot. */
189void lj_snap_restore(jit_State *J, void *exptr)
190{
191 ExitState *ex = (ExitState *)exptr;
192 SnapNo snapno = J->exitno; /* For now, snapno == exitno. */
193 Trace *T = J->trace[J->parent];
194 SnapShot *snap = &T->snap[snapno];
195 BCReg s, nslots = snap->nslots;
196 IRRef2 *map = &T->snapmap[snap->mapofs];
197 IRRef2 *flinks = map + nslots + snap->nframelinks;
198 TValue *o, *newbase, *ntop;
199 BloomFilter rfilt = snap_renamefilter(T, snapno);
200 lua_State *L = J->L;
201
202 /* Make sure the stack is big enough for the slots from the snapshot. */
203 if (L->base + nslots >= L->maxstack) {
204 L->top = curr_topL(L);
205 lj_state_growstack(L, nslots - curr_proto(L)->framesize);
206 }
207
208 /* Fill stack slots with data from the registers and spill slots. */
209 newbase = NULL;
210 ntop = L->base;
211 for (s = 0, o = L->base-1; s < nslots; s++, o++) {
212 IRRef ref = snap_ref(map[s]);
213 if (ref) {
214 IRIns *ir = &T->ir[ref];
215 if (irref_isk(ref)) { /* Restore constant slot. */
216 lj_ir_kvalue(L, o, ir);
217 } else {
218 IRType1 t = ir->t;
219 RegSP rs = ir->prev;
220 if (LJ_UNLIKELY(bloomtest(rfilt, ref)))
221 rs = snap_renameref(T, snapno, ref, rs);
222 if (ra_hasspill(regsp_spill(rs))) { /* Restore from spill slot. */
223 int32_t *sps = &ex->spill[regsp_spill(rs)];
224 if (irt_isinteger(t)) {
225 setintV(o, *sps);
226 } else if (irt_isnum(t)) {
227 o->u64 = *(uint64_t *)sps;
228 } else {
229 lua_assert(!irt_ispri(t)); /* PRI refs never have a spill slot. */
230 setgcrefi(o->gcr, *sps);
231 setitype(o, irt_toitype(t));
232 }
233 } else if (ra_hasreg(regsp_reg(rs))) { /* Restore from register. */
234 Reg r = regsp_reg(rs);
235 if (irt_isinteger(t)) {
236 setintV(o, ex->gpr[r-RID_MIN_GPR]);
237 } else if (irt_isnum(t)) {
238 setnumV(o, ex->fpr[r-RID_MIN_FPR]);
239 } else {
240 if (!irt_ispri(t))
241 setgcrefi(o->gcr, ex->gpr[r-RID_MIN_GPR]);
242 setitype(o, irt_toitype(t));
243 }
244 } else { /* Restore frame slot. */
245 lua_assert(ir->o == IR_FRAME);
246 /* This works for both PTR and FUNC IR_FRAME. */
247 setgcrefp(o->fr.func, mref(T->ir[ir->op2].ptr, void));
248 if (s != 0) /* Do not overwrite link to previous frame. */
249 o->fr.tp.ftsz = (int32_t)*--flinks;
250 if (irt_isfunc(ir->t)) {
251 GCfunc *fn = gco2func(gcref(T->ir[ir->op2].gcr));
252 if (isluafunc(fn)) {
253 TValue *fs;
254 newbase = o+1;
255 fs = newbase + funcproto(fn)->framesize;
256 if (fs > ntop) ntop = fs; /* Update top for newly added frames. */
257 }
258 }
259 }
260 }
261 } else if (newbase) {
262 setnilV(o); /* Clear unreferenced slots of newly added frames. */
263 }
264 }
265 if (newbase) { /* Clear remainder of newly added frames. */
266 L->base = newbase;
267 if (ntop >= L->maxstack) { /* Need to grow the stack again. */
268 MSize need = (MSize)(ntop - o);
269 L->top = o;
270 lj_state_growstack(L, need);
271 o = L->top;
272 ntop = o + need;
273 }
274 L->top = curr_topL(L);
275 for (; o < ntop; o++)
276 setnilV(o);
277 } else { /* Must not clear slots of existing frame. */
278 L->top = curr_topL(L);
279 }
280 lua_assert(map + nslots == flinks-1);
281 J->pc = (const BCIns *)(uintptr_t)(*--flinks);
282}
283
284#undef IR
285
286#endif