diff options
| author | Mike Pall <mike> | 2011-02-22 22:39:12 +0100 |
|---|---|---|
| committer | Mike Pall <mike> | 2011-02-22 22:39:12 +0100 |
| commit | 4c97cc773091d3a7b523283b178ab53451583ca4 (patch) | |
| tree | e4861f7359c30a5802a7f7d32277da3af0f15e79 | |
| parent | 8d0b073ff0506b94fd0586f96ae6967cf8167290 (diff) | |
| download | luajit-4c97cc773091d3a7b523283b178ab53451583ca4.tar.gz luajit-4c97cc773091d3a7b523283b178ab53451583ca4.tar.bz2 luajit-4c97cc773091d3a7b523283b178ab53451583ca4.zip | |
Eliminate dead slots in snapshots using bytecode data-flow analysis.
| -rw-r--r-- | src/lj_bc.h | 2 | ||||
| -rw-r--r-- | src/lj_record.c | 8 | ||||
| -rw-r--r-- | src/lj_snap.c | 143 | ||||
| -rw-r--r-- | src/lj_snap.h | 1 |
4 files changed, 133 insertions, 21 deletions
diff --git a/src/lj_bc.h b/src/lj_bc.h index 32c8f73c..9dffe0c0 100644 --- a/src/lj_bc.h +++ b/src/lj_bc.h | |||
| @@ -156,8 +156,8 @@ | |||
| 156 | _(CALLT, base, ___, lit, call) \ | 156 | _(CALLT, base, ___, lit, call) \ |
| 157 | _(ITERC, base, lit, lit, call) \ | 157 | _(ITERC, base, lit, lit, call) \ |
| 158 | _(ITERN, base, lit, lit, call) \ | 158 | _(ITERN, base, lit, lit, call) \ |
| 159 | _(ISNEXT, base, ___, jump, ___) \ | ||
| 160 | _(VARG, base, lit, lit, ___) \ | 159 | _(VARG, base, lit, lit, ___) \ |
| 160 | _(ISNEXT, base, ___, jump, ___) \ | ||
| 161 | \ | 161 | \ |
| 162 | /* Returns. */ \ | 162 | /* Returns. */ \ |
| 163 | _(RETM, base, ___, lit, ___) \ | 163 | _(RETM, base, ___, lit, ___) \ |
diff --git a/src/lj_record.c b/src/lj_record.c index 6517a1b7..cfdd3e1a 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
| @@ -1364,11 +1364,8 @@ static void rec_comp_fixup(jit_State *J, const BCIns *pc, int cond) | |||
| 1364 | /* Set PC to opposite target to avoid re-recording the comp. in side trace. */ | 1364 | /* Set PC to opposite target to avoid re-recording the comp. in side trace. */ |
| 1365 | J->cur.snapmap[snap->mapofs + snap->nent] = SNAP_MKPC(npc); | 1365 | J->cur.snapmap[snap->mapofs + snap->nent] = SNAP_MKPC(npc); |
| 1366 | J->needsnap = 1; | 1366 | J->needsnap = 1; |
| 1367 | /* Shrink last snapshot if possible. */ | 1367 | if (bc_a(jmpins) < J->maxslot) J->maxslot = bc_a(jmpins); |
| 1368 | if (bc_a(jmpins) < J->maxslot) { | 1368 | lj_snap_shrink(J); /* Shrink last snapshot if possible. */ |
| 1369 | J->maxslot = bc_a(jmpins); | ||
| 1370 | lj_snap_shrink(J); | ||
| 1371 | } | ||
| 1372 | } | 1369 | } |
| 1373 | 1370 | ||
| 1374 | /* Record the next bytecode instruction (_before_ it's executed). */ | 1371 | /* Record the next bytecode instruction (_before_ it's executed). */ |
| @@ -1411,6 +1408,7 @@ void lj_record_ins(jit_State *J) | |||
| 1411 | /* Need snapshot before recording next bytecode (e.g. after a store). */ | 1408 | /* Need snapshot before recording next bytecode (e.g. after a store). */ |
| 1412 | if (J->needsnap) { | 1409 | if (J->needsnap) { |
| 1413 | J->needsnap = 0; | 1410 | J->needsnap = 0; |
| 1411 | lj_snap_purge(J); | ||
| 1414 | lj_snap_add(J); | 1412 | lj_snap_add(J); |
| 1415 | J->mergesnap = 1; | 1413 | J->mergesnap = 1; |
| 1416 | } | 1414 | } |
diff --git a/src/lj_snap.c b/src/lj_snap.c index e04da81f..59435b20 100644 --- a/src/lj_snap.c +++ b/src/lj_snap.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include "lj_gc.h" | 13 | #include "lj_gc.h" |
| 14 | #include "lj_state.h" | 14 | #include "lj_state.h" |
| 15 | #include "lj_frame.h" | 15 | #include "lj_frame.h" |
| 16 | #include "lj_bc.h" | ||
| 16 | #include "lj_ir.h" | 17 | #include "lj_ir.h" |
| 17 | #include "lj_jit.h" | 18 | #include "lj_jit.h" |
| 18 | #include "lj_iropt.h" | 19 | #include "lj_iropt.h" |
| @@ -138,27 +139,139 @@ void lj_snap_add(jit_State *J) | |||
| 138 | snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap); | 139 | snapshot_stack(J, &J->cur.snap[nsnap], nsnapmap); |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 142 | /* -- Snapshot modification ----------------------------------------------- */ | ||
| 143 | |||
| 144 | #define SNAP_USEDEF_SLOTS (LJ_MAX_JSLOTS+LJ_STACK_EXTRA) | ||
| 145 | |||
| 146 | /* Find unused slots with reaching-definitions bytecode data-flow analysis. */ | ||
| 147 | static BCReg snap_usedef(jit_State *J, uint8_t *udf, | ||
| 148 | const BCIns *pc, BCReg maxslot) | ||
| 149 | { | ||
| 150 | BCReg s; | ||
| 151 | GCobj *o; | ||
| 152 | |||
| 153 | if (maxslot == 0) return 0; | ||
| 154 | #ifdef LUAJIT_USE_VALGRIND | ||
| 155 | /* Avoid errors for harmless reads beyond maxslot. */ | ||
| 156 | memset(udf, 1, SNAP_USEDEF_SLOTS); | ||
| 157 | #else | ||
| 158 | memset(udf, 1, maxslot); | ||
| 159 | #endif | ||
| 160 | |||
| 161 | /* Treat open upvalues as used. */ | ||
| 162 | o = gcref(J->L->openupval); | ||
| 163 | while (o) { | ||
| 164 | if (uvval(gco2uv(o)) < J->L->base) break; | ||
| 165 | udf[uvval(gco2uv(o)) - J->L->base] = 0; | ||
| 166 | o = gcref(o->gch.nextgc); | ||
| 167 | } | ||
| 168 | |||
| 169 | #define USE_SLOT(s) udf[(s)] &= ~1 | ||
| 170 | #define DEF_SLOT(s) udf[(s)] *= 3 | ||
| 171 | |||
| 172 | /* Scan through following bytecode and check for uses/defs. */ | ||
| 173 | lua_assert(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc); | ||
| 174 | for (;;) { | ||
| 175 | BCIns ins = *pc++; | ||
| 176 | BCOp op = bc_op(ins); | ||
| 177 | switch (bcmode_b(op)) { | ||
| 178 | case BCMvar: USE_SLOT(bc_b(ins)); break; | ||
| 179 | default: break; | ||
| 180 | } | ||
| 181 | switch (bcmode_c(op)) { | ||
| 182 | case BCMvar: USE_SLOT(bc_c(ins)); break; | ||
| 183 | case BCMrbase: | ||
| 184 | lua_assert(op == BC_CAT); | ||
| 185 | for (s = bc_b(ins); s <= bc_c(ins); s++) USE_SLOT(s); | ||
| 186 | for (; s < maxslot; s++) DEF_SLOT(s); | ||
| 187 | break; | ||
| 188 | case BCMjump: | ||
| 189 | handle_jump: { | ||
| 190 | BCReg minslot = bc_a(ins); | ||
| 191 | if (op >= BC_FORI && op <= BC_JFORL) minslot += FORL_EXT; | ||
| 192 | else if (op >= BC_ITERL && op <= BC_JITERL) minslot += bc_b(pc[-1])-1; | ||
| 193 | for (s = minslot; s < maxslot; s++) DEF_SLOT(s); | ||
| 194 | return minslot < maxslot ? minslot : maxslot; | ||
| 195 | } | ||
| 196 | case BCMlit: | ||
| 197 | if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) { | ||
| 198 | goto handle_jump; | ||
| 199 | } else if (bc_isret(op)) { | ||
| 200 | BCReg top = op == BC_RETM ? maxslot : (bc_a(ins) + bc_d(ins)-1); | ||
| 201 | for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s); | ||
| 202 | for (; s < top; s++) USE_SLOT(s); | ||
| 203 | for (; s < maxslot; s++) DEF_SLOT(s); | ||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | break; | ||
| 207 | case BCMfunc: return maxslot; /* NYI: will abort, anyway. */ | ||
| 208 | default: break; | ||
| 209 | } | ||
| 210 | switch (bcmode_a(op)) { | ||
| 211 | case BCMvar: USE_SLOT(bc_a(ins)); break; | ||
| 212 | case BCMdst: | ||
| 213 | if (!(op == BC_ISTC || op == BC_ISFC)) DEF_SLOT(bc_a(ins)); | ||
| 214 | break; | ||
| 215 | case BCMbase: | ||
| 216 | if (op >= BC_CALLM && op <= BC_VARG) { | ||
| 217 | BCReg top = (op == BC_CALLM || op == BC_CALLMT || bc_c(ins) == 0) ? | ||
| 218 | maxslot : (bc_a(ins) + bc_c(ins)); | ||
| 219 | for (s = bc_a(ins); s < top; s++) USE_SLOT(s); | ||
| 220 | for (; s < maxslot; s++) DEF_SLOT(s); | ||
| 221 | if (op == BC_CALLT || op == BC_CALLMT) { | ||
| 222 | for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s); | ||
| 223 | return 0; | ||
| 224 | } | ||
| 225 | } else if (op == BC_KNIL) { | ||
| 226 | for (s = bc_a(ins); s <= bc_d(ins); s++) DEF_SLOT(s); | ||
| 227 | } else if (op == BC_TSETM) { | ||
| 228 | for (s = bc_a(ins)-1; s < maxslot; s++) USE_SLOT(s); | ||
| 229 | } | ||
| 230 | break; | ||
| 231 | default: break; | ||
| 232 | } | ||
| 233 | lua_assert(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc); | ||
| 234 | } | ||
| 235 | |||
| 236 | #undef USE_SLOT | ||
| 237 | #undef DEF_SLOT | ||
| 238 | |||
| 239 | return 0; /* unreachable */ | ||
| 240 | } | ||
| 241 | |||
| 242 | /* Purge dead slots before the next snapshot. */ | ||
| 243 | void lj_snap_purge(jit_State *J) | ||
| 244 | { | ||
| 245 | uint8_t udf[SNAP_USEDEF_SLOTS]; | ||
| 246 | BCReg maxslot = J->maxslot; | ||
| 247 | BCReg s = snap_usedef(J, udf, J->pc, maxslot); | ||
| 248 | for (; s < maxslot; s++) | ||
| 249 | if (udf[s] != 0) | ||
| 250 | J->base[s] = 0; /* Purge dead slots. */ | ||
| 251 | } | ||
| 252 | |||
| 141 | /* Shrink last snapshot. */ | 253 | /* Shrink last snapshot. */ |
| 142 | void lj_snap_shrink(jit_State *J) | 254 | void lj_snap_shrink(jit_State *J) |
| 143 | { | 255 | { |
| 144 | BCReg nslots = J->baseslot + J->maxslot; | ||
| 145 | SnapShot *snap = &J->cur.snap[J->cur.nsnap-1]; | 256 | SnapShot *snap = &J->cur.snap[J->cur.nsnap-1]; |
| 146 | SnapEntry *map = &J->cur.snapmap[snap->mapofs]; | 257 | SnapEntry *map = &J->cur.snapmap[snap->mapofs]; |
| 147 | MSize nent = snap->nent; | 258 | MSize n, m, nlim, nent = snap->nent; |
| 148 | lua_assert(nslots < snap->nslots); | 259 | uint8_t udf[SNAP_USEDEF_SLOTS]; |
| 149 | snap->nslots = (uint8_t)nslots; | 260 | BCReg maxslot = J->maxslot; |
| 150 | if (nent > 0 && snap_slot(map[nent-1]) >= nslots) { | 261 | BCReg minslot = snap_usedef(J, udf, snap_pc(map[nent]), maxslot); |
| 151 | MSize s, delta, depth = snap->depth; | 262 | BCReg baseslot = J->baseslot; |
| 152 | lua_assert(depth == (MSize)J->framedepth); | 263 | maxslot += baseslot; |
| 153 | for (nent--; nent > 0 && snap_slot(map[nent-1]) >= nslots; nent--) | 264 | minslot += baseslot; |
| 154 | ; | 265 | snap->nslots = (uint8_t)maxslot; |
| 155 | delta = snap->nent - nent; | 266 | for (n = m = 0; n < nent; n++) { /* Remove unused slots from snapshot. */ |
| 156 | snap->nent = (uint8_t)nent; | 267 | BCReg s = snap_slot(map[n]); |
| 157 | J->cur.nsnapmap = (uint16_t)(snap->mapofs + nent + 1 + depth); | 268 | if (s < minslot || (s < maxslot && udf[s-baseslot] == 0)) |
| 158 | map += nent; | 269 | map[m++] = map[n]; /* Only copy used slots. */ |
| 159 | for (s = 0; s <= depth; s++) /* Move PC + frame links down. */ | ||
| 160 | map[s] = map[s+delta]; | ||
| 161 | } | 270 | } |
| 271 | snap->nent = (uint8_t)m; | ||
| 272 | nlim = nent + snap->depth; | ||
| 273 | while (n <= nlim) map[m++] = map[n++]; /* Move PC + frame links down. */ | ||
| 274 | J->cur.nsnapmap = (uint16_t)(snap->mapofs + m); /* Free up space in map. */ | ||
| 162 | } | 275 | } |
| 163 | 276 | ||
| 164 | /* -- Snapshot access ----------------------------------------------------- */ | 277 | /* -- Snapshot access ----------------------------------------------------- */ |
diff --git a/src/lj_snap.h b/src/lj_snap.h index e4c11a8c..031b0ac3 100644 --- a/src/lj_snap.h +++ b/src/lj_snap.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #if LJ_HASJIT | 12 | #if LJ_HASJIT |
| 13 | LJ_FUNC void lj_snap_add(jit_State *J); | 13 | LJ_FUNC void lj_snap_add(jit_State *J); |
| 14 | LJ_FUNC void lj_snap_purge(jit_State *J); | ||
| 14 | LJ_FUNC void lj_snap_shrink(jit_State *J); | 15 | LJ_FUNC void lj_snap_shrink(jit_State *J); |
| 15 | LJ_FUNC void lj_snap_regspmap(uint16_t *rsmap, GCtrace *T, SnapNo snapno); | 16 | LJ_FUNC void lj_snap_regspmap(uint16_t *rsmap, GCtrace *T, SnapNo snapno); |
| 16 | LJ_FUNC const BCIns *lj_snap_restore(jit_State *J, void *exptr); | 17 | LJ_FUNC const BCIns *lj_snap_restore(jit_State *J, void *exptr); |
