diff options
author | Mike Pall <mike> | 2010-02-23 18:27:39 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2010-02-23 19:41:32 +0100 |
commit | 8ae2f9feaaed874e01a87df6646242b80acceabb (patch) | |
tree | 0c0e030b007a4ef5b663476f4142f1f860ee3675 /src | |
parent | d5c8fe4b90c54cbd03924d3eaf04d83dcf2f3cb8 (diff) | |
download | luajit-8ae2f9feaaed874e01a87df6646242b80acceabb.tar.gz luajit-8ae2f9feaaed874e01a87df6646242b80acceabb.tar.bz2 luajit-8ae2f9feaaed874e01a87df6646242b80acceabb.zip |
Randomize penalties for aborts and add blacklisting.
Diffstat (limited to 'src')
-rw-r--r-- | src/lj_dispatch.h | 2 | ||||
-rw-r--r-- | src/lj_jit.h | 13 | ||||
-rw-r--r-- | src/lj_record.c | 6 | ||||
-rw-r--r-- | src/lj_trace.c | 42 | ||||
-rw-r--r-- | src/lj_traceerr.h | 2 |
5 files changed, 45 insertions, 20 deletions
diff --git a/src/lj_dispatch.h b/src/lj_dispatch.h index 1aa7dae0..5ef9dcd4 100644 --- a/src/lj_dispatch.h +++ b/src/lj_dispatch.h | |||
@@ -19,8 +19,6 @@ typedef uint16_t HotCount; | |||
19 | /* Number of hot counter hash table entries (must be a power of two). */ | 19 | /* Number of hot counter hash table entries (must be a power of two). */ |
20 | #define HOTCOUNT_SIZE 64 | 20 | #define HOTCOUNT_SIZE 64 |
21 | #define HOTCOUNT_PCMASK ((HOTCOUNT_SIZE-1)*sizeof(HotCount)) | 21 | #define HOTCOUNT_PCMASK ((HOTCOUNT_SIZE-1)*sizeof(HotCount)) |
22 | #define HOTCOUNT_MIN_PENALTY 103 | ||
23 | #define HOTCOUNT_MAX_PENALTY 60000 | ||
24 | 22 | ||
25 | /* This solves a circular dependency problem -- bump as needed. Sigh. */ | 23 | /* This solves a circular dependency problem -- bump as needed. Sigh. */ |
26 | #define GG_NUM_ASMFF 62 | 24 | #define GG_NUM_ASMFF 62 |
diff --git a/src/lj_jit.h b/src/lj_jit.h index 18069ac9..23adf30d 100644 --- a/src/lj_jit.h +++ b/src/lj_jit.h | |||
@@ -69,14 +69,14 @@ | |||
69 | _(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \ | 69 | _(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \ |
70 | _(\007, maxsnap, 100) /* Max. # of snapshots for a trace. */ \ | 70 | _(\007, maxsnap, 100) /* Max. # of snapshots for a trace. */ \ |
71 | \ | 71 | \ |
72 | _(\007, hotloop, 57) /* # of iterations to detect a hot loop. */ \ | 72 | _(\007, hotloop, 56) /* # of iter. to detect a hot loop/call. */ \ |
73 | _(\007, hotexit, 10) /* # of taken exits to start a side trace. */ \ | 73 | _(\007, hotexit, 10) /* # of taken exits to start a side trace. */ \ |
74 | _(\007, tryside, 4) /* # of attempts to compile a side trace. */ \ | 74 | _(\007, tryside, 4) /* # of attempts to compile a side trace. */ \ |
75 | \ | 75 | \ |
76 | _(\012, instunroll, 4) /* Max. unroll for instable loops. */ \ | 76 | _(\012, instunroll, 4) /* Max. unroll for instable loops. */ \ |
77 | _(\012, loopunroll, 7) /* Max. unroll for loop ops in side traces. */ \ | 77 | _(\012, loopunroll, 7) /* Max. unroll for loop ops in side traces. */ \ |
78 | _(\012, callunroll, 3) /* Max. unroll for recursive calls. */ \ | 78 | _(\012, callunroll, 3) /* Max. unroll for recursive calls. */ \ |
79 | _(\011, recunroll, 2) /* Max. unroll for true recursion. */ \ | 79 | _(\011, recunroll, 2) /* Min. unroll for true recursion. */ \ |
80 | \ | 80 | \ |
81 | /* Size of each machine code area (in KBytes). */ \ | 81 | /* Size of each machine code area (in KBytes). */ \ |
82 | _(\011, sizemcode, JIT_P_sizemcode_DEFAULT) \ | 82 | _(\011, sizemcode, JIT_P_sizemcode_DEFAULT) \ |
@@ -181,13 +181,15 @@ typedef struct Trace { | |||
181 | 181 | ||
182 | /* Round-robin penalty cache for bytecodes leading to aborted traces. */ | 182 | /* Round-robin penalty cache for bytecodes leading to aborted traces. */ |
183 | typedef struct HotPenalty { | 183 | typedef struct HotPenalty { |
184 | const BCIns *pc; /* Starting bytecode PC. */ | 184 | MRef pc; /* Starting bytecode PC. */ |
185 | uint16_t val; /* Penalty value, i.e. hotcount start. */ | 185 | uint16_t val; /* Penalty value, i.e. hotcount start. */ |
186 | uint16_t reason; /* Abort reason (really TraceErr). */ | 186 | uint16_t reason; /* Abort reason (really TraceErr). */ |
187 | } HotPenalty; | 187 | } HotPenalty; |
188 | 188 | ||
189 | /* Number of slots for the penalty cache. Must be a power of 2. */ | 189 | #define PENALTY_SLOTS 64 /* Penalty cache slot. Must be a power of 2. */ |
190 | #define PENALTY_SLOTS 16 | 190 | #define PENALTY_MIN 36 /* Minimum penalty value. */ |
191 | #define PENALTY_MAX 60000 /* Maximum penalty value. */ | ||
192 | #define PENALTY_RNDBITS 4 /* # of random bits to add to penalty value. */ | ||
191 | 193 | ||
192 | /* Round-robin backpropagation cache for narrowing conversions. */ | 194 | /* Round-robin backpropagation cache for narrowing conversions. */ |
193 | typedef struct BPropEntry { | 195 | typedef struct BPropEntry { |
@@ -264,6 +266,7 @@ typedef struct jit_State { | |||
264 | 266 | ||
265 | HotPenalty penalty[PENALTY_SLOTS]; /* Penalty slots. */ | 267 | HotPenalty penalty[PENALTY_SLOTS]; /* Penalty slots. */ |
266 | uint32_t penaltyslot; /* Round-robin index into penalty slots. */ | 268 | uint32_t penaltyslot; /* Round-robin index into penalty slots. */ |
269 | uint32_t prngstate; /* PRNG state for penalty randomization. */ | ||
267 | 270 | ||
268 | BPropEntry bpropcache[BPROP_SLOTS]; /* Backpropagation cache slots. */ | 271 | BPropEntry bpropcache[BPROP_SLOTS]; /* Backpropagation cache slots. */ |
269 | uint32_t bpropslot; /* Round-robin index into bpropcache slots. */ | 272 | uint32_t bpropslot; /* Round-robin index into bpropcache slots. */ |
diff --git a/src/lj_record.c b/src/lj_record.c index 2b63b87d..1ef01386 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
@@ -419,9 +419,9 @@ static int innerloopleft(jit_State *J, const BCIns *pc) | |||
419 | { | 419 | { |
420 | ptrdiff_t i; | 420 | ptrdiff_t i; |
421 | for (i = 0; i < PENALTY_SLOTS; i++) | 421 | for (i = 0; i < PENALTY_SLOTS; i++) |
422 | if (J->penalty[i].pc == pc) { | 422 | if (mref(J->penalty[i].pc, const BCIns) == pc) { |
423 | if (J->penalty[i].reason == LJ_TRERR_LLEAVE && | 423 | if (J->penalty[i].reason == LJ_TRERR_LLEAVE && |
424 | J->penalty[i].val >= 2*HOTCOUNT_MIN_PENALTY) | 424 | J->penalty[i].val >= 2*PENALTY_MIN) |
425 | return 1; | 425 | return 1; |
426 | break; | 426 | break; |
427 | } | 427 | } |
@@ -2149,7 +2149,7 @@ void lj_record_ins(jit_State *J) | |||
2149 | case BC_ILOOP: | 2149 | case BC_ILOOP: |
2150 | case BC_IFUNCF: | 2150 | case BC_IFUNCF: |
2151 | case BC_IFUNCV: | 2151 | case BC_IFUNCV: |
2152 | lj_trace_err(J, LJ_TRERR_LBLACKL); | 2152 | lj_trace_err(J, LJ_TRERR_BLACKL); |
2153 | break; | 2153 | break; |
2154 | 2154 | ||
2155 | case BC_JMP: | 2155 | case BC_JMP: |
diff --git a/src/lj_trace.c b/src/lj_trace.c index 43104be6..6f63c945 100644 --- a/src/lj_trace.c +++ b/src/lj_trace.c | |||
@@ -294,27 +294,50 @@ void lj_trace_freestate(global_State *g) | |||
294 | lj_mem_freevec(g, J->trace, J->sizetrace, Trace *); | 294 | lj_mem_freevec(g, J->trace, J->sizetrace, Trace *); |
295 | } | 295 | } |
296 | 296 | ||
297 | /* -- Trace compiler state machine ---------------------------------------- */ | 297 | /* -- Penalties and blacklisting ------------------------------------------ */ |
298 | |||
299 | /* Trivial PRNG for randomization of penalties. */ | ||
300 | static uint32_t penalty_prng(jit_State *J, int bits) | ||
301 | { | ||
302 | /* Yes, this LCG is very weak, but that doesn't matter for our use case. */ | ||
303 | J->prngstate = J->prngstate * 1103515245 + 12345; | ||
304 | return J->prngstate >> (32-bits); | ||
305 | } | ||
306 | |||
307 | /* Blacklist a bytecode instruction. */ | ||
308 | static void blacklist_pc(GCproto *pt, BCIns *pc) | ||
309 | { | ||
310 | setbc_op(pc, (int)bc_op(*pc)+(int)BC_ILOOP-(int)BC_LOOP); | ||
311 | pt->flags |= PROTO_HAS_ILOOP; | ||
312 | } | ||
298 | 313 | ||
299 | /* Penalize a bytecode instruction by bumping its hot counter. */ | 314 | /* Penalize a bytecode instruction. */ |
300 | static void hotpenalty(jit_State *J, const BCIns *pc, TraceError e) | 315 | static void penalty_pc(jit_State *J, GCproto *pt, BCIns *pc, TraceError e) |
301 | { | 316 | { |
302 | uint32_t i, val = HOTCOUNT_MIN_PENALTY; | 317 | uint32_t i, val = PENALTY_MIN; |
303 | for (i = 0; i < PENALTY_SLOTS; i++) | 318 | for (i = 0; i < PENALTY_SLOTS; i++) |
304 | if (J->penalty[i].pc == pc) { | 319 | if (mref(J->penalty[i].pc, const BCIns) == pc) { /* Cache slot found? */ |
305 | val = ((uint32_t)J->penalty[i].val << 1) + 1; | 320 | /* First try to bump its hotcount several times. */ |
306 | if (val > HOTCOUNT_MAX_PENALTY) val = HOTCOUNT_MAX_PENALTY; | 321 | val = ((uint32_t)J->penalty[i].val << 1) + |
322 | penalty_prng(J, PENALTY_RNDBITS); | ||
323 | if (val > PENALTY_MAX) { | ||
324 | blacklist_pc(pt, pc); /* Blacklist it, if that didn't help. */ | ||
325 | return; | ||
326 | } | ||
307 | goto setpenalty; | 327 | goto setpenalty; |
308 | } | 328 | } |
329 | /* Assign a new penalty cache slot. */ | ||
309 | i = J->penaltyslot; | 330 | i = J->penaltyslot; |
310 | J->penaltyslot = (J->penaltyslot + 1) & (PENALTY_SLOTS-1); | 331 | J->penaltyslot = (J->penaltyslot + 1) & (PENALTY_SLOTS-1); |
311 | J->penalty[i].pc = pc; | 332 | setmref(J->penalty[i].pc, pc); |
312 | setpenalty: | 333 | setpenalty: |
313 | J->penalty[i].val = (uint16_t)val; | 334 | J->penalty[i].val = (uint16_t)val; |
314 | J->penalty[i].reason = e; | 335 | J->penalty[i].reason = e; |
315 | hotcount_set(J2GG(J), pc+1, val); | 336 | hotcount_set(J2GG(J), pc+1, val); |
316 | } | 337 | } |
317 | 338 | ||
339 | /* -- Trace compiler state machine ---------------------------------------- */ | ||
340 | |||
318 | /* Start tracing. */ | 341 | /* Start tracing. */ |
319 | static void trace_start(jit_State *J) | 342 | static void trace_start(jit_State *J) |
320 | { | 343 | { |
@@ -433,8 +456,9 @@ static int trace_abort(jit_State *J) | |||
433 | J->state = LJ_TRACE_ASM; | 456 | J->state = LJ_TRACE_ASM; |
434 | return 1; /* Retry ASM with new MCode area. */ | 457 | return 1; /* Retry ASM with new MCode area. */ |
435 | } | 458 | } |
459 | /* Penalize or blacklist starting bytecode instruction. */ | ||
436 | if (J->parent == 0) | 460 | if (J->parent == 0) |
437 | hotpenalty(J, J->startpc, e); /* Penalize starting instruction. */ | 461 | penalty_pc(J, &gcref(J->cur.startpt)->pt, (BCIns *)J->startpc, e); |
438 | if (J->curtrace) { /* Is there anything to abort? */ | 462 | if (J->curtrace) { /* Is there anything to abort? */ |
439 | ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ | 463 | ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ |
440 | lj_vmevent_send(L, TRACE, | 464 | lj_vmevent_send(L, TRACE, |
diff --git a/src/lj_traceerr.h b/src/lj_traceerr.h index abc53024..db7668fe 100644 --- a/src/lj_traceerr.h +++ b/src/lj_traceerr.h | |||
@@ -10,13 +10,13 @@ TREDEF(RECERR, "error thrown or hook called during recording") | |||
10 | TREDEF(TRACEOV, "trace too long") | 10 | TREDEF(TRACEOV, "trace too long") |
11 | TREDEF(STACKOV, "trace too deep") | 11 | TREDEF(STACKOV, "trace too deep") |
12 | TREDEF(SNAPOV, "too many snapshots") | 12 | TREDEF(SNAPOV, "too many snapshots") |
13 | TREDEF(BLACKL, "blacklisted") | ||
13 | TREDEF(NYIBC, "NYI: bytecode %d") | 14 | TREDEF(NYIBC, "NYI: bytecode %d") |
14 | 15 | ||
15 | /* Recording loop ops. */ | 16 | /* Recording loop ops. */ |
16 | TREDEF(LLEAVE, "leaving loop in root trace") | 17 | TREDEF(LLEAVE, "leaving loop in root trace") |
17 | TREDEF(LINNER, "inner loop in root trace") | 18 | TREDEF(LINNER, "inner loop in root trace") |
18 | TREDEF(LUNROLL, "loop unroll limit reached") | 19 | TREDEF(LUNROLL, "loop unroll limit reached") |
19 | TREDEF(LBLACKL, "blacklisted loop") | ||
20 | 20 | ||
21 | /* Recording calls/returns. */ | 21 | /* Recording calls/returns. */ |
22 | TREDEF(BADTYPE, "bad argument type") | 22 | TREDEF(BADTYPE, "bad argument type") |