diff options
author | Mike Pall <mike> | 2015-05-19 01:59:29 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2015-05-19 01:59:29 +0200 |
commit | b82fc3ddc032dfc3da813cda9715d356975922e7 (patch) | |
tree | 21e5a68db18a8b3bc339c0e1b3a5c8825ab1e75a | |
parent | d8cfc370ef182ff3240ffd1e27e33d4594fde658 (diff) | |
download | luajit-b82fc3ddc032dfc3da813cda9715d356975922e7.tar.gz luajit-b82fc3ddc032dfc3da813cda9715d356975922e7.tar.bz2 luajit-b82fc3ddc032dfc3da813cda9715d356975922e7.zip |
Bump table allocations retroactively if they grow later on.
-rw-r--r-- | src/lj_jit.h | 14 | ||||
-rw-r--r-- | src/lj_record.c | 76 | ||||
-rw-r--r-- | src/lj_tab.c | 6 | ||||
-rw-r--r-- | src/lj_tab.h | 1 | ||||
-rw-r--r-- | src/lj_trace.c | 12 | ||||
-rw-r--r-- | src/lj_traceerr.h | 1 |
6 files changed, 101 insertions, 9 deletions
diff --git a/src/lj_jit.h b/src/lj_jit.h index 4b51baeb..db3d89bb 100644 --- a/src/lj_jit.h +++ b/src/lj_jit.h | |||
@@ -290,6 +290,15 @@ typedef struct ScEvEntry { | |||
290 | uint8_t dir; /* Direction. 1: +, 0: -. */ | 290 | uint8_t dir; /* Direction. 1: +, 0: -. */ |
291 | } ScEvEntry; | 291 | } ScEvEntry; |
292 | 292 | ||
293 | /* Reverse bytecode map (IRRef -> PC). Only for selected instructions. */ | ||
294 | typedef struct RBCHashEntry { | ||
295 | MRef pc; /* Bytecode PC. */ | ||
296 | IRRef ref; /* IR reference. */ | ||
297 | } RBCHashEntry; | ||
298 | |||
299 | /* Number of slots in the reverse bytecode hash table. Must be a power of 2. */ | ||
300 | #define RBCHASH_SLOTS 8 | ||
301 | |||
293 | /* 128 bit SIMD constants. */ | 302 | /* 128 bit SIMD constants. */ |
294 | enum { | 303 | enum { |
295 | LJ_KSIMD_ABS, | 304 | LJ_KSIMD_ABS, |
@@ -364,8 +373,9 @@ typedef struct jit_State { | |||
364 | 373 | ||
365 | PostProc postproc; /* Required post-processing after execution. */ | 374 | PostProc postproc; /* Required post-processing after execution. */ |
366 | #if LJ_SOFTFP || (LJ_32 && LJ_HASFFI) | 375 | #if LJ_SOFTFP || (LJ_32 && LJ_HASFFI) |
367 | int needsplit; /* Need SPLIT pass. */ | 376 | uint8_t needsplit; /* Need SPLIT pass. */ |
368 | #endif | 377 | #endif |
378 | uint8_t retryrec; /* Retry recording. */ | ||
369 | 379 | ||
370 | GCRef *trace; /* Array of traces. */ | 380 | GCRef *trace; /* Array of traces. */ |
371 | TraceNo freetrace; /* Start of scan for next free trace. */ | 381 | TraceNo freetrace; /* Start of scan for next free trace. */ |
@@ -382,6 +392,8 @@ typedef struct jit_State { | |||
382 | uint32_t penaltyslot; /* Round-robin index into penalty slots. */ | 392 | uint32_t penaltyslot; /* Round-robin index into penalty slots. */ |
383 | uint32_t prngstate; /* PRNG state. */ | 393 | uint32_t prngstate; /* PRNG state. */ |
384 | 394 | ||
395 | RBCHashEntry rbchash[RBCHASH_SLOTS]; /* Reverse bytecode map. */ | ||
396 | |||
385 | BPropEntry bpropcache[BPROP_SLOTS]; /* Backpropagation cache slots. */ | 397 | BPropEntry bpropcache[BPROP_SLOTS]; /* Backpropagation cache slots. */ |
386 | uint32_t bpropslot; /* Round-robin index into bpropcache slots. */ | 398 | uint32_t bpropslot; /* Round-robin index into bpropcache slots. */ |
387 | 399 | ||
diff --git a/src/lj_record.c b/src/lj_record.c index 56038156..583f80aa 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
@@ -235,6 +235,8 @@ static void canonicalize_slots(jit_State *J) | |||
235 | /* Stop recording. */ | 235 | /* Stop recording. */ |
236 | void lj_record_stop(jit_State *J, TraceLink linktype, TraceNo lnk) | 236 | void lj_record_stop(jit_State *J, TraceLink linktype, TraceNo lnk) |
237 | { | 237 | { |
238 | if (J->retryrec) | ||
239 | lj_trace_err(J, LJ_TRERR_RETRY); | ||
238 | lj_trace_end(J); | 240 | lj_trace_end(J); |
239 | J->cur.linktype = (uint8_t)linktype; | 241 | J->cur.linktype = (uint8_t)linktype; |
240 | J->cur.link = (uint16_t)lnk; | 242 | J->cur.link = (uint16_t)lnk; |
@@ -1127,6 +1129,60 @@ static void rec_mm_comp_cdata(jit_State *J, RecordIndex *ix, int op, MMS mm) | |||
1127 | 1129 | ||
1128 | /* -- Indexed access ------------------------------------------------------ */ | 1130 | /* -- Indexed access ------------------------------------------------------ */ |
1129 | 1131 | ||
1132 | /* Bump table allocations in bytecode when they grow during recording. */ | ||
1133 | static void rec_idx_bump(jit_State *J, RecordIndex *ix) | ||
1134 | { | ||
1135 | RBCHashEntry *rbc = &J->rbchash[(ix->tab & (RBCHASH_SLOTS-1))]; | ||
1136 | if (tref_ref(ix->tab) == rbc->ref) { | ||
1137 | const BCIns *pc = mref(rbc->pc, const BCIns); | ||
1138 | GCtab *tb = tabV(&ix->tabv); | ||
1139 | uint32_t nhbits; | ||
1140 | IRIns *ir; | ||
1141 | if (!tvisnil(&ix->keyv)) | ||
1142 | (void)lj_tab_set(J->L, tb, &ix->keyv); /* Grow table right now. */ | ||
1143 | nhbits = tb->hmask > 0 ? lj_fls(tb->hmask)+1 : 0; | ||
1144 | ir = IR(tref_ref(ix->tab)); | ||
1145 | if (ir->o == IR_TNEW) { | ||
1146 | uint32_t ah = bc_d(*pc); | ||
1147 | uint32_t asize = ah & 0x7ff, hbits = ah >> 11; | ||
1148 | if (nhbits > hbits) hbits = nhbits; | ||
1149 | if (tb->asize > asize) { | ||
1150 | asize = tb->asize <= 0x7ff ? tb->asize : 0x7ff; | ||
1151 | } | ||
1152 | if ((asize | (hbits<<11)) != ah) { /* Has the size changed? */ | ||
1153 | /* Patch bytecode, but continue recording (for more patching). */ | ||
1154 | setbc_d(pc, (asize | (hbits<<11))); | ||
1155 | /* Patching TNEW operands is only safe if the trace is aborted. */ | ||
1156 | ir->op1 = asize; ir->op2 = hbits; | ||
1157 | J->retryrec = 1; /* Abort the trace at the end of recording. */ | ||
1158 | } | ||
1159 | } else if (ir->o == IR_TDUP) { | ||
1160 | GCtab *tpl = gco2tab(proto_kgc(J->pt, ~(ptrdiff_t)bc_d(*pc))); | ||
1161 | /* Grow template table, but preserve keys with nil values. */ | ||
1162 | if (tb->asize > tpl->asize || (1u << nhbits)-1 > tpl->hmask) { | ||
1163 | Node *node = noderef(tpl->node); | ||
1164 | uint32_t i, hmask = tpl->hmask; | ||
1165 | for (i = 0; i <= hmask; i++) { | ||
1166 | if (!tvisnil(&node[i].key) && tvisnil(&node[i].val)) | ||
1167 | settabV(J->L, &node[i].val, tpl); | ||
1168 | } | ||
1169 | if (!tvisnil(&ix->keyv) && tref_isk(ix->key)) { | ||
1170 | TValue *o = lj_tab_set(J->L, tpl, &ix->keyv); | ||
1171 | if (tvisnil(o)) settabV(J->L, o, tpl); | ||
1172 | } | ||
1173 | lj_tab_resize(J->L, tpl, tb->asize, nhbits); | ||
1174 | hmask = tpl->hmask; | ||
1175 | for (i = 0; i <= hmask; i++) { | ||
1176 | /* This is safe, since template tables only hold immutable values. */ | ||
1177 | if (tvistab(&node[i].val)) | ||
1178 | setnilV(&node[i].val); | ||
1179 | } | ||
1180 | J->retryrec = 1; /* Abort the trace at the end of recording. */ | ||
1181 | } | ||
1182 | } | ||
1183 | } | ||
1184 | } | ||
1185 | |||
1130 | /* Record bounds-check. */ | 1186 | /* Record bounds-check. */ |
1131 | static void rec_idx_abc(jit_State *J, TRef asizeref, TRef ikey, uint32_t asize) | 1187 | static void rec_idx_abc(jit_State *J, TRef asizeref, TRef ikey, uint32_t asize) |
1132 | { | 1188 | { |
@@ -1352,6 +1408,8 @@ TRef lj_record_idx(jit_State *J, RecordIndex *ix) | |||
1352 | key = emitir(IRTN(IR_CONV), key, IRCONV_NUM_INT); | 1408 | key = emitir(IRTN(IR_CONV), key, IRCONV_NUM_INT); |
1353 | xref = emitir(IRT(IR_NEWREF, IRT_P32), ix->tab, key); | 1409 | xref = emitir(IRT(IR_NEWREF, IRT_P32), ix->tab, key); |
1354 | keybarrier = 0; /* NEWREF already takes care of the key barrier. */ | 1410 | keybarrier = 0; /* NEWREF already takes care of the key barrier. */ |
1411 | if ((J->flags & JIT_F_OPT_SINK)) /* Avoid a separate flag. */ | ||
1412 | rec_idx_bump(J, ix); | ||
1355 | } | 1413 | } |
1356 | } else if (!lj_opt_fwd_wasnonnil(J, loadop, tref_ref(xref))) { | 1414 | } else if (!lj_opt_fwd_wasnonnil(J, loadop, tref_ref(xref))) { |
1357 | /* Cannot derive that the previous value was non-nil, must do checks. */ | 1415 | /* Cannot derive that the previous value was non-nil, must do checks. */ |
@@ -1390,9 +1448,16 @@ static void rec_tsetm(jit_State *J, BCReg ra, BCReg rn, int32_t i) | |||
1390 | { | 1448 | { |
1391 | RecordIndex ix; | 1449 | RecordIndex ix; |
1392 | cTValue *basev = J->L->base; | 1450 | cTValue *basev = J->L->base; |
1393 | copyTV(J->L, &ix.tabv, &basev[ra-1]); | 1451 | GCtab *t = tabV(&basev[ra-1]); |
1452 | settabV(J->L, &ix.tabv, t); | ||
1394 | ix.tab = getslot(J, ra-1); | 1453 | ix.tab = getslot(J, ra-1); |
1395 | ix.idxchain = 0; | 1454 | ix.idxchain = 0; |
1455 | if ((J->flags & JIT_F_OPT_SINK)) { | ||
1456 | if (t->asize < i+rn-ra) | ||
1457 | lj_tab_reasize(J->L, t, i+rn-ra); | ||
1458 | setnilV(&ix.keyv); | ||
1459 | rec_idx_bump(J, &ix); | ||
1460 | } | ||
1396 | for (; ra < rn; i++, ra++) { | 1461 | for (; ra < rn; i++, ra++) { |
1397 | setintV(&ix.keyv, i); | 1462 | setintV(&ix.keyv, i); |
1398 | ix.key = lj_ir_kint(J, i); | 1463 | ix.key = lj_ir_kint(J, i); |
@@ -1712,8 +1777,12 @@ static TRef rec_tnew(jit_State *J, uint32_t ah) | |||
1712 | { | 1777 | { |
1713 | uint32_t asize = ah & 0x7ff; | 1778 | uint32_t asize = ah & 0x7ff; |
1714 | uint32_t hbits = ah >> 11; | 1779 | uint32_t hbits = ah >> 11; |
1780 | TRef tr; | ||
1715 | if (asize == 0x7ff) asize = 0x801; | 1781 | if (asize == 0x7ff) asize = 0x801; |
1716 | return emitir(IRTG(IR_TNEW, IRT_TAB), asize, hbits); | 1782 | tr = emitir(IRTG(IR_TNEW, IRT_TAB), asize, hbits); |
1783 | J->rbchash[(tr & (RBCHASH_SLOTS-1))].ref = tref_ref(tr); | ||
1784 | setmref(J->rbchash[(tr & (RBCHASH_SLOTS-1))].pc, J->pc); | ||
1785 | return tr; | ||
1717 | } | 1786 | } |
1718 | 1787 | ||
1719 | /* -- Concatenation ------------------------------------------------------- */ | 1788 | /* -- Concatenation ------------------------------------------------------- */ |
@@ -2139,6 +2208,8 @@ void lj_record_ins(jit_State *J) | |||
2139 | case BC_TDUP: | 2208 | case BC_TDUP: |
2140 | rc = emitir(IRTG(IR_TDUP, IRT_TAB), | 2209 | rc = emitir(IRTG(IR_TDUP, IRT_TAB), |
2141 | lj_ir_ktab(J, gco2tab(proto_kgc(J->pt, ~(ptrdiff_t)rc))), 0); | 2210 | lj_ir_ktab(J, gco2tab(proto_kgc(J->pt, ~(ptrdiff_t)rc))), 0); |
2211 | J->rbchash[(rc & (RBCHASH_SLOTS-1))].ref = tref_ref(rc); | ||
2212 | setmref(J->rbchash[(rc & (RBCHASH_SLOTS-1))].pc, pc); | ||
2142 | break; | 2213 | break; |
2143 | 2214 | ||
2144 | /* -- Calls and vararg handling ----------------------------------------- */ | 2215 | /* -- Calls and vararg handling ----------------------------------------- */ |
@@ -2352,6 +2423,7 @@ void lj_record_setup(jit_State *J) | |||
2352 | /* Initialize state related to current trace. */ | 2423 | /* Initialize state related to current trace. */ |
2353 | memset(J->slot, 0, sizeof(J->slot)); | 2424 | memset(J->slot, 0, sizeof(J->slot)); |
2354 | memset(J->chain, 0, sizeof(J->chain)); | 2425 | memset(J->chain, 0, sizeof(J->chain)); |
2426 | memset(J->rbchash, 0, sizeof(J->rbchash)); | ||
2355 | memset(J->bpropcache, 0, sizeof(J->bpropcache)); | 2427 | memset(J->bpropcache, 0, sizeof(J->bpropcache)); |
2356 | J->scev.idx = REF_NIL; | 2428 | J->scev.idx = REF_NIL; |
2357 | setmref(J->scev.pc, NULL); | 2429 | setmref(J->scev.pc, NULL); |
diff --git a/src/lj_tab.c b/src/lj_tab.c index a9f43835..88bf1089 100644 --- a/src/lj_tab.c +++ b/src/lj_tab.c | |||
@@ -246,7 +246,7 @@ void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t) | |||
246 | /* -- Table resizing ------------------------------------------------------ */ | 246 | /* -- Table resizing ------------------------------------------------------ */ |
247 | 247 | ||
248 | /* Resize a table to fit the new array/hash part sizes. */ | 248 | /* Resize a table to fit the new array/hash part sizes. */ |
249 | static void resizetab(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits) | 249 | void lj_tab_resize(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits) |
250 | { | 250 | { |
251 | Node *oldnode = noderef(t->node); | 251 | Node *oldnode = noderef(t->node); |
252 | uint32_t oldasize = t->asize; | 252 | uint32_t oldasize = t->asize; |
@@ -383,7 +383,7 @@ static void rehashtab(lua_State *L, GCtab *t, cTValue *ek) | |||
383 | asize += countint(ek, bins); | 383 | asize += countint(ek, bins); |
384 | na = bestasize(bins, &asize); | 384 | na = bestasize(bins, &asize); |
385 | total -= na; | 385 | total -= na; |
386 | resizetab(L, t, asize, hsize2hbits(total)); | 386 | lj_tab_resize(L, t, asize, hsize2hbits(total)); |
387 | } | 387 | } |
388 | 388 | ||
389 | #if LJ_HASFFI | 389 | #if LJ_HASFFI |
@@ -395,7 +395,7 @@ void lj_tab_rehash(lua_State *L, GCtab *t) | |||
395 | 395 | ||
396 | void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize) | 396 | void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize) |
397 | { | 397 | { |
398 | resizetab(L, t, nasize+1, t->hmask > 0 ? lj_fls(t->hmask)+1 : 0); | 398 | lj_tab_resize(L, t, nasize+1, t->hmask > 0 ? lj_fls(t->hmask)+1 : 0); |
399 | } | 399 | } |
400 | 400 | ||
401 | /* -- Table getters ------------------------------------------------------- */ | 401 | /* -- Table getters ------------------------------------------------------- */ |
diff --git a/src/lj_tab.h b/src/lj_tab.h index 1da28bd9..7cf031be 100644 --- a/src/lj_tab.h +++ b/src/lj_tab.h | |||
@@ -44,6 +44,7 @@ LJ_FUNC void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t); | |||
44 | #if LJ_HASFFI | 44 | #if LJ_HASFFI |
45 | LJ_FUNC void lj_tab_rehash(lua_State *L, GCtab *t); | 45 | LJ_FUNC void lj_tab_rehash(lua_State *L, GCtab *t); |
46 | #endif | 46 | #endif |
47 | LJ_FUNC void lj_tab_resize(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits); | ||
47 | LJ_FUNCA void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize); | 48 | LJ_FUNCA void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize); |
48 | 49 | ||
49 | /* Caveat: all getters except lj_tab_get() can return NULL! */ | 50 | /* Caveat: all getters except lj_tab_get() can return NULL! */ |
diff --git a/src/lj_trace.c b/src/lj_trace.c index 39ff0461..79c50b0a 100644 --- a/src/lj_trace.c +++ b/src/lj_trace.c | |||
@@ -394,6 +394,7 @@ static void trace_start(jit_State *J) | |||
394 | J->guardemit.irt = 0; | 394 | J->guardemit.irt = 0; |
395 | J->postproc = LJ_POST_NONE; | 395 | J->postproc = LJ_POST_NONE; |
396 | lj_resetsplit(J); | 396 | lj_resetsplit(J); |
397 | J->retryrec = 0; | ||
397 | setgcref(J->cur.startpt, obj2gco(J->pt)); | 398 | setgcref(J->cur.startpt, obj2gco(J->pt)); |
398 | 399 | ||
399 | L = J->L; | 400 | L = J->L; |
@@ -510,10 +511,15 @@ static int trace_abort(jit_State *J) | |||
510 | } | 511 | } |
511 | /* Penalize or blacklist starting bytecode instruction. */ | 512 | /* Penalize or blacklist starting bytecode instruction. */ |
512 | if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) { | 513 | if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) { |
513 | if (J->exitno == 0) | 514 | if (J->exitno == 0) { |
514 | penalty_pc(J, &gcref(J->cur.startpt)->pt, mref(J->cur.startpc, BCIns), e); | 515 | BCIns *startpc = mref(J->cur.startpc, BCIns); |
515 | else | 516 | if (e == LJ_TRERR_RETRY) |
517 | hotcount_set(J2GG(J), startpc+1, 1); /* Immediate retry. */ | ||
518 | else | ||
519 | penalty_pc(J, &gcref(J->cur.startpt)->pt, startpc, e); | ||
520 | } else { | ||
516 | traceref(J, J->exitno)->link = J->exitno; /* Self-link is blacklisted. */ | 521 | traceref(J, J->exitno)->link = J->exitno; /* Self-link is blacklisted. */ |
522 | } | ||
517 | } | 523 | } |
518 | 524 | ||
519 | /* Is there anything to abort? */ | 525 | /* Is there anything to abort? */ |
diff --git a/src/lj_traceerr.h b/src/lj_traceerr.h index 5a2fe8bb..0f38562b 100644 --- a/src/lj_traceerr.h +++ b/src/lj_traceerr.h | |||
@@ -12,6 +12,7 @@ TREDEF(TRACEOV, "trace too long") | |||
12 | TREDEF(STACKOV, "trace too deep") | 12 | TREDEF(STACKOV, "trace too deep") |
13 | TREDEF(SNAPOV, "too many snapshots") | 13 | TREDEF(SNAPOV, "too many snapshots") |
14 | TREDEF(BLACKL, "blacklisted") | 14 | TREDEF(BLACKL, "blacklisted") |
15 | TREDEF(RETRY, "retry recording") | ||
15 | TREDEF(NYIBC, "NYI: bytecode %d") | 16 | TREDEF(NYIBC, "NYI: bytecode %d") |
16 | 17 | ||
17 | /* Recording loop ops. */ | 18 | /* Recording loop ops. */ |