diff options
Diffstat (limited to 'src/lj_snap.c')
-rw-r--r-- | src/lj_snap.c | 286 |
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. */ | ||
35 | static 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. */ | ||
50 | static 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. */ | ||
75 | static 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. */ | ||
104 | void 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. */ | ||
129 | void 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 | */ | ||
149 | static 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. */ | ||
160 | static 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. */ | ||
170 | void 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. */ | ||
189 | void 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 | ||