diff options
Diffstat (limited to 'src/lj_trace.c')
-rw-r--r-- | src/lj_trace.c | 257 |
1 files changed, 205 insertions, 52 deletions
diff --git a/src/lj_trace.c b/src/lj_trace.c index 89c3c5ed..c2329394 100644 --- a/src/lj_trace.c +++ b/src/lj_trace.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "lj_vm.h" | 30 | #include "lj_vm.h" |
31 | #include "lj_vmevent.h" | 31 | #include "lj_vmevent.h" |
32 | #include "lj_target.h" | 32 | #include "lj_target.h" |
33 | #include "lj_prng.h" | ||
33 | 34 | ||
34 | /* -- Error handling ------------------------------------------------------ */ | 35 | /* -- Error handling ------------------------------------------------------ */ |
35 | 36 | ||
@@ -104,7 +105,8 @@ static void perftools_addtrace(GCtrace *T) | |||
104 | name++; | 105 | name++; |
105 | else | 106 | else |
106 | name = "(string)"; | 107 | name = "(string)"; |
107 | lua_assert(startpc >= proto_bc(pt) && startpc < proto_bc(pt) + pt->sizebc); | 108 | lj_assertX(startpc >= proto_bc(pt) && startpc < proto_bc(pt) + pt->sizebc, |
109 | "trace PC out of range"); | ||
108 | lineno = lj_debug_line(pt, proto_bcpos(pt, startpc)); | 110 | lineno = lj_debug_line(pt, proto_bcpos(pt, startpc)); |
109 | if (!fp) { | 111 | if (!fp) { |
110 | char fname[40]; | 112 | char fname[40]; |
@@ -117,15 +119,26 @@ static void perftools_addtrace(GCtrace *T) | |||
117 | } | 119 | } |
118 | #endif | 120 | #endif |
119 | 121 | ||
120 | /* Allocate space for copy of trace. */ | 122 | /* Allocate space for copy of T. */ |
121 | static GCtrace *trace_save_alloc(jit_State *J) | 123 | GCtrace * LJ_FASTCALL lj_trace_alloc(lua_State *L, GCtrace *T) |
122 | { | 124 | { |
123 | size_t sztr = ((sizeof(GCtrace)+7)&~7); | 125 | size_t sztr = ((sizeof(GCtrace)+7)&~7); |
124 | size_t szins = (J->cur.nins-J->cur.nk)*sizeof(IRIns); | 126 | size_t szins = (T->nins-T->nk)*sizeof(IRIns); |
125 | size_t sz = sztr + szins + | 127 | size_t sz = sztr + szins + |
126 | J->cur.nsnap*sizeof(SnapShot) + | 128 | T->nsnap*sizeof(SnapShot) + |
127 | J->cur.nsnapmap*sizeof(SnapEntry); | 129 | T->nsnapmap*sizeof(SnapEntry); |
128 | return lj_mem_newt(J->L, (MSize)sz, GCtrace); | 130 | GCtrace *T2 = lj_mem_newt(L, (MSize)sz, GCtrace); |
131 | char *p = (char *)T2 + sztr; | ||
132 | T2->gct = ~LJ_TTRACE; | ||
133 | T2->marked = 0; | ||
134 | T2->traceno = 0; | ||
135 | T2->ir = (IRIns *)p - T->nk; | ||
136 | T2->nins = T->nins; | ||
137 | T2->nk = T->nk; | ||
138 | T2->nsnap = T->nsnap; | ||
139 | T2->nsnapmap = T->nsnapmap; | ||
140 | memcpy(p, T->ir + T->nk, szins); | ||
141 | return T2; | ||
129 | } | 142 | } |
130 | 143 | ||
131 | /* Save current trace by copying and compacting it. */ | 144 | /* Save current trace by copying and compacting it. */ |
@@ -139,12 +152,12 @@ static void trace_save(jit_State *J, GCtrace *T) | |||
139 | setgcrefp(J2G(J)->gc.root, T); | 152 | setgcrefp(J2G(J)->gc.root, T); |
140 | newwhite(J2G(J), T); | 153 | newwhite(J2G(J), T); |
141 | T->gct = ~LJ_TTRACE; | 154 | T->gct = ~LJ_TTRACE; |
142 | T->ir = (IRIns *)p - J->cur.nk; | 155 | T->ir = (IRIns *)p - J->cur.nk; /* The IR has already been copied above. */ |
143 | memcpy(p, J->cur.ir+J->cur.nk, szins); | ||
144 | p += szins; | 156 | p += szins; |
145 | TRACE_APPENDVEC(snap, nsnap, SnapShot) | 157 | TRACE_APPENDVEC(snap, nsnap, SnapShot) |
146 | TRACE_APPENDVEC(snapmap, nsnapmap, SnapEntry) | 158 | TRACE_APPENDVEC(snapmap, nsnapmap, SnapEntry) |
147 | J->cur.traceno = 0; | 159 | J->cur.traceno = 0; |
160 | J->curfinal = NULL; | ||
148 | setgcrefp(J->trace[T->traceno], T); | 161 | setgcrefp(J->trace[T->traceno], T); |
149 | lj_gc_barriertrace(J2G(J), T->traceno); | 162 | lj_gc_barriertrace(J2G(J), T->traceno); |
150 | lj_gdbjit_addtrace(J, T); | 163 | lj_gdbjit_addtrace(J, T); |
@@ -172,7 +185,7 @@ void lj_trace_reenableproto(GCproto *pt) | |||
172 | { | 185 | { |
173 | if ((pt->flags & PROTO_ILOOP)) { | 186 | if ((pt->flags & PROTO_ILOOP)) { |
174 | BCIns *bc = proto_bc(pt); | 187 | BCIns *bc = proto_bc(pt); |
175 | BCPos i, sizebc = pt->sizebc;; | 188 | BCPos i, sizebc = pt->sizebc; |
176 | pt->flags &= ~PROTO_ILOOP; | 189 | pt->flags &= ~PROTO_ILOOP; |
177 | if (bc_op(bc[0]) == BC_IFUNCF) | 190 | if (bc_op(bc[0]) == BC_IFUNCF) |
178 | setbc_op(&bc[0], BC_FUNCF); | 191 | setbc_op(&bc[0], BC_FUNCF); |
@@ -194,27 +207,28 @@ static void trace_unpatch(jit_State *J, GCtrace *T) | |||
194 | return; /* No need to unpatch branches in parent traces (yet). */ | 207 | return; /* No need to unpatch branches in parent traces (yet). */ |
195 | switch (bc_op(*pc)) { | 208 | switch (bc_op(*pc)) { |
196 | case BC_JFORL: | 209 | case BC_JFORL: |
197 | lua_assert(traceref(J, bc_d(*pc)) == T); | 210 | lj_assertJ(traceref(J, bc_d(*pc)) == T, "JFORL references other trace"); |
198 | *pc = T->startins; | 211 | *pc = T->startins; |
199 | pc += bc_j(T->startins); | 212 | pc += bc_j(T->startins); |
200 | lua_assert(bc_op(*pc) == BC_JFORI); | 213 | lj_assertJ(bc_op(*pc) == BC_JFORI, "FORL does not point to JFORI"); |
201 | setbc_op(pc, BC_FORI); | 214 | setbc_op(pc, BC_FORI); |
202 | break; | 215 | break; |
203 | case BC_JITERL: | 216 | case BC_JITERL: |
204 | case BC_JLOOP: | 217 | case BC_JLOOP: |
205 | lua_assert(op == BC_ITERL || op == BC_LOOP || bc_isret(op)); | 218 | lj_assertJ(op == BC_ITERL || op == BC_ITERN || op == BC_LOOP || |
219 | bc_isret(op), "bad original bytecode %d", op); | ||
206 | *pc = T->startins; | 220 | *pc = T->startins; |
207 | break; | 221 | break; |
208 | case BC_JMP: | 222 | case BC_JMP: |
209 | lua_assert(op == BC_ITERL); | 223 | lj_assertJ(op == BC_ITERL, "bad original bytecode %d", op); |
210 | pc += bc_j(*pc)+2; | 224 | pc += bc_j(*pc)+2; |
211 | if (bc_op(*pc) == BC_JITERL) { | 225 | if (bc_op(*pc) == BC_JITERL) { |
212 | lua_assert(traceref(J, bc_d(*pc)) == T); | 226 | lj_assertJ(traceref(J, bc_d(*pc)) == T, "JITERL references other trace"); |
213 | *pc = T->startins; | 227 | *pc = T->startins; |
214 | } | 228 | } |
215 | break; | 229 | break; |
216 | case BC_JFUNCF: | 230 | case BC_JFUNCF: |
217 | lua_assert(op == BC_FUNCF); | 231 | lj_assertJ(op == BC_FUNCF, "bad original bytecode %d", op); |
218 | *pc = T->startins; | 232 | *pc = T->startins; |
219 | break; | 233 | break; |
220 | default: /* Already unpatched. */ | 234 | default: /* Already unpatched. */ |
@@ -226,7 +240,8 @@ static void trace_unpatch(jit_State *J, GCtrace *T) | |||
226 | static void trace_flushroot(jit_State *J, GCtrace *T) | 240 | static void trace_flushroot(jit_State *J, GCtrace *T) |
227 | { | 241 | { |
228 | GCproto *pt = &gcref(T->startpt)->pt; | 242 | GCproto *pt = &gcref(T->startpt)->pt; |
229 | lua_assert(T->root == 0 && pt != NULL); | 243 | lj_assertJ(T->root == 0, "not a root trace"); |
244 | lj_assertJ(pt != NULL, "trace has no prototype"); | ||
230 | /* First unpatch any modified bytecode. */ | 245 | /* First unpatch any modified bytecode. */ |
231 | trace_unpatch(J, T); | 246 | trace_unpatch(J, T); |
232 | /* Unlink root trace from chain anchored in prototype. */ | 247 | /* Unlink root trace from chain anchored in prototype. */ |
@@ -274,7 +289,7 @@ int lj_trace_flushall(lua_State *L) | |||
274 | if (T->root == 0) | 289 | if (T->root == 0) |
275 | trace_flushroot(J, T); | 290 | trace_flushroot(J, T); |
276 | lj_gdbjit_deltrace(J, T); | 291 | lj_gdbjit_deltrace(J, T); |
277 | T->traceno = 0; | 292 | T->traceno = T->link = 0; /* Blacklist the link for cont_stitch. */ |
278 | setgcrefnull(J->trace[i]); | 293 | setgcrefnull(J->trace[i]); |
279 | } | 294 | } |
280 | } | 295 | } |
@@ -296,13 +311,42 @@ void lj_trace_initstate(global_State *g) | |||
296 | { | 311 | { |
297 | jit_State *J = G2J(g); | 312 | jit_State *J = G2J(g); |
298 | TValue *tv; | 313 | TValue *tv; |
299 | /* Initialize SIMD constants. */ | 314 | |
315 | /* Initialize aligned SIMD constants. */ | ||
300 | tv = LJ_KSIMD(J, LJ_KSIMD_ABS); | 316 | tv = LJ_KSIMD(J, LJ_KSIMD_ABS); |
301 | tv[0].u64 = U64x(7fffffff,ffffffff); | 317 | tv[0].u64 = U64x(7fffffff,ffffffff); |
302 | tv[1].u64 = U64x(7fffffff,ffffffff); | 318 | tv[1].u64 = U64x(7fffffff,ffffffff); |
303 | tv = LJ_KSIMD(J, LJ_KSIMD_NEG); | 319 | tv = LJ_KSIMD(J, LJ_KSIMD_NEG); |
304 | tv[0].u64 = U64x(80000000,00000000); | 320 | tv[0].u64 = U64x(80000000,00000000); |
305 | tv[1].u64 = U64x(80000000,00000000); | 321 | tv[1].u64 = U64x(80000000,00000000); |
322 | |||
323 | /* Initialize 32/64 bit constants. */ | ||
324 | #if LJ_TARGET_X86ORX64 | ||
325 | J->k64[LJ_K64_TOBIT].u64 = U64x(43380000,00000000); | ||
326 | #if LJ_32 | ||
327 | J->k64[LJ_K64_M2P64_31].u64 = U64x(c1e00000,00000000); | ||
328 | #endif | ||
329 | J->k64[LJ_K64_2P64].u64 = U64x(43f00000,00000000); | ||
330 | J->k32[LJ_K32_M2P64_31] = LJ_64 ? 0xdf800000 : 0xcf000000; | ||
331 | #endif | ||
332 | #if LJ_TARGET_X86ORX64 || LJ_TARGET_MIPS64 | ||
333 | J->k64[LJ_K64_M2P64].u64 = U64x(c3f00000,00000000); | ||
334 | #endif | ||
335 | #if LJ_TARGET_PPC | ||
336 | J->k32[LJ_K32_2P52_2P31] = 0x59800004; | ||
337 | J->k32[LJ_K32_2P52] = 0x59800000; | ||
338 | #endif | ||
339 | #if LJ_TARGET_PPC || LJ_TARGET_MIPS | ||
340 | J->k32[LJ_K32_2P31] = 0x4f000000; | ||
341 | #endif | ||
342 | #if LJ_TARGET_MIPS | ||
343 | J->k64[LJ_K64_2P31].u64 = U64x(41e00000,00000000); | ||
344 | #if LJ_64 | ||
345 | J->k64[LJ_K64_2P63].u64 = U64x(43e00000,00000000); | ||
346 | J->k32[LJ_K32_2P63] = 0x5f000000; | ||
347 | J->k32[LJ_K32_M2P64] = 0xdf800000; | ||
348 | #endif | ||
349 | #endif | ||
306 | } | 350 | } |
307 | 351 | ||
308 | /* Free everything associated with the JIT compiler state. */ | 352 | /* Free everything associated with the JIT compiler state. */ |
@@ -313,11 +357,11 @@ void lj_trace_freestate(global_State *g) | |||
313 | { /* This assumes all traces have already been freed. */ | 357 | { /* This assumes all traces have already been freed. */ |
314 | ptrdiff_t i; | 358 | ptrdiff_t i; |
315 | for (i = 1; i < (ptrdiff_t)J->sizetrace; i++) | 359 | for (i = 1; i < (ptrdiff_t)J->sizetrace; i++) |
316 | lua_assert(i == (ptrdiff_t)J->cur.traceno || traceref(J, i) == NULL); | 360 | lj_assertG(i == (ptrdiff_t)J->cur.traceno || traceref(J, i) == NULL, |
361 | "trace still allocated"); | ||
317 | } | 362 | } |
318 | #endif | 363 | #endif |
319 | lj_mcode_free(J); | 364 | lj_mcode_free(J); |
320 | lj_ir_k64_freeall(J); | ||
321 | lj_mem_freevec(g, J->snapmapbuf, J->sizesnapmap, SnapEntry); | 365 | lj_mem_freevec(g, J->snapmapbuf, J->sizesnapmap, SnapEntry); |
322 | lj_mem_freevec(g, J->snapbuf, J->sizesnap, SnapShot); | 366 | lj_mem_freevec(g, J->snapbuf, J->sizesnap, SnapShot); |
323 | lj_mem_freevec(g, J->irbuf + J->irbotlim, J->irtoplim - J->irbotlim, IRIns); | 367 | lj_mem_freevec(g, J->irbuf + J->irbotlim, J->irtoplim - J->irbotlim, IRIns); |
@@ -329,8 +373,13 @@ void lj_trace_freestate(global_State *g) | |||
329 | /* Blacklist a bytecode instruction. */ | 373 | /* Blacklist a bytecode instruction. */ |
330 | static void blacklist_pc(GCproto *pt, BCIns *pc) | 374 | static void blacklist_pc(GCproto *pt, BCIns *pc) |
331 | { | 375 | { |
332 | setbc_op(pc, (int)bc_op(*pc)+(int)BC_ILOOP-(int)BC_LOOP); | 376 | if (bc_op(*pc) == BC_ITERN) { |
333 | pt->flags |= PROTO_ILOOP; | 377 | setbc_op(pc, BC_ITERC); |
378 | setbc_op(pc+1+bc_j(pc[1]), BC_JMP); | ||
379 | } else { | ||
380 | setbc_op(pc, (int)bc_op(*pc)+(int)BC_ILOOP-(int)BC_LOOP); | ||
381 | pt->flags |= PROTO_ILOOP; | ||
382 | } | ||
334 | } | 383 | } |
335 | 384 | ||
336 | /* Penalize a bytecode instruction. */ | 385 | /* Penalize a bytecode instruction. */ |
@@ -341,7 +390,7 @@ static void penalty_pc(jit_State *J, GCproto *pt, BCIns *pc, TraceError e) | |||
341 | if (mref(J->penalty[i].pc, const BCIns) == pc) { /* Cache slot found? */ | 390 | if (mref(J->penalty[i].pc, const BCIns) == pc) { /* Cache slot found? */ |
342 | /* First try to bump its hotcount several times. */ | 391 | /* First try to bump its hotcount several times. */ |
343 | val = ((uint32_t)J->penalty[i].val << 1) + | 392 | val = ((uint32_t)J->penalty[i].val << 1) + |
344 | LJ_PRNG_BITS(J, PENALTY_RNDBITS); | 393 | (lj_prng_u64(&J2G(J)->prng) & ((1u<<PENALTY_RNDBITS)-1)); |
345 | if (val > PENALTY_MAX) { | 394 | if (val > PENALTY_MAX) { |
346 | blacklist_pc(pt, pc); /* Blacklist it, if that didn't help. */ | 395 | blacklist_pc(pt, pc); /* Blacklist it, if that didn't help. */ |
347 | return; | 396 | return; |
@@ -367,10 +416,11 @@ static void trace_start(jit_State *J) | |||
367 | TraceNo traceno; | 416 | TraceNo traceno; |
368 | 417 | ||
369 | if ((J->pt->flags & PROTO_NOJIT)) { /* JIT disabled for this proto? */ | 418 | if ((J->pt->flags & PROTO_NOJIT)) { /* JIT disabled for this proto? */ |
370 | if (J->parent == 0) { | 419 | if (J->parent == 0 && J->exitno == 0 && bc_op(*J->pc) != BC_ITERN) { |
371 | /* Lazy bytecode patching to disable hotcount events. */ | 420 | /* Lazy bytecode patching to disable hotcount events. */ |
372 | lua_assert(bc_op(*J->pc) == BC_FORL || bc_op(*J->pc) == BC_ITERL || | 421 | lj_assertJ(bc_op(*J->pc) == BC_FORL || bc_op(*J->pc) == BC_ITERL || |
373 | bc_op(*J->pc) == BC_LOOP || bc_op(*J->pc) == BC_FUNCF); | 422 | bc_op(*J->pc) == BC_LOOP || bc_op(*J->pc) == BC_FUNCF, |
423 | "bad hot bytecode %d", bc_op(*J->pc)); | ||
374 | setbc_op(J->pc, (int)bc_op(*J->pc)+(int)BC_ILOOP-(int)BC_LOOP); | 424 | setbc_op(J->pc, (int)bc_op(*J->pc)+(int)BC_ILOOP-(int)BC_LOOP); |
375 | J->pt->flags |= PROTO_ILOOP; | 425 | J->pt->flags |= PROTO_ILOOP; |
376 | } | 426 | } |
@@ -381,7 +431,8 @@ static void trace_start(jit_State *J) | |||
381 | /* Get a new trace number. */ | 431 | /* Get a new trace number. */ |
382 | traceno = trace_findfree(J); | 432 | traceno = trace_findfree(J); |
383 | if (LJ_UNLIKELY(traceno == 0)) { /* No free trace? */ | 433 | if (LJ_UNLIKELY(traceno == 0)) { /* No free trace? */ |
384 | lua_assert((J2G(J)->hookmask & HOOK_GC) == 0); | 434 | lj_assertJ((J2G(J)->hookmask & HOOK_GC) == 0, |
435 | "recorder called from GC hook"); | ||
385 | lj_trace_flushall(J->L); | 436 | lj_trace_flushall(J->L); |
386 | J->state = LJ_TRACE_IDLE; /* Silently ignored. */ | 437 | J->state = LJ_TRACE_IDLE; /* Silently ignored. */ |
387 | return; | 438 | return; |
@@ -401,6 +452,8 @@ static void trace_start(jit_State *J) | |||
401 | J->guardemit.irt = 0; | 452 | J->guardemit.irt = 0; |
402 | J->postproc = LJ_POST_NONE; | 453 | J->postproc = LJ_POST_NONE; |
403 | lj_resetsplit(J); | 454 | lj_resetsplit(J); |
455 | J->retryrec = 0; | ||
456 | J->ktrace = 0; | ||
404 | setgcref(J->cur.startpt, obj2gco(J->pt)); | 457 | setgcref(J->cur.startpt, obj2gco(J->pt)); |
405 | 458 | ||
406 | L = J->L; | 459 | L = J->L; |
@@ -412,6 +465,12 @@ static void trace_start(jit_State *J) | |||
412 | if (J->parent) { | 465 | if (J->parent) { |
413 | setintV(L->top++, J->parent); | 466 | setintV(L->top++, J->parent); |
414 | setintV(L->top++, J->exitno); | 467 | setintV(L->top++, J->exitno); |
468 | } else { | ||
469 | BCOp op = bc_op(*J->pc); | ||
470 | if (op == BC_CALLM || op == BC_CALL || op == BC_ITERC) { | ||
471 | setintV(L->top++, J->exitno); /* Parent of stitched trace. */ | ||
472 | setintV(L->top++, -1); | ||
473 | } | ||
415 | } | 474 | } |
416 | ); | 475 | ); |
417 | lj_record_setup(J); | 476 | lj_record_setup(J); |
@@ -424,7 +483,7 @@ static void trace_stop(jit_State *J) | |||
424 | BCOp op = bc_op(J->cur.startins); | 483 | BCOp op = bc_op(J->cur.startins); |
425 | GCproto *pt = &gcref(J->cur.startpt)->pt; | 484 | GCproto *pt = &gcref(J->cur.startpt)->pt; |
426 | TraceNo traceno = J->cur.traceno; | 485 | TraceNo traceno = J->cur.traceno; |
427 | GCtrace *T = trace_save_alloc(J); /* Do this first. May throw OOM. */ | 486 | GCtrace *T = J->curfinal; |
428 | lua_State *L; | 487 | lua_State *L; |
429 | 488 | ||
430 | switch (op) { | 489 | switch (op) { |
@@ -442,6 +501,7 @@ static void trace_stop(jit_State *J) | |||
442 | J->cur.nextroot = pt->trace; | 501 | J->cur.nextroot = pt->trace; |
443 | pt->trace = (TraceNo1)traceno; | 502 | pt->trace = (TraceNo1)traceno; |
444 | break; | 503 | break; |
504 | case BC_ITERN: | ||
445 | case BC_RET: | 505 | case BC_RET: |
446 | case BC_RET0: | 506 | case BC_RET0: |
447 | case BC_RET1: | 507 | case BC_RET1: |
@@ -449,7 +509,7 @@ static void trace_stop(jit_State *J) | |||
449 | goto addroot; | 509 | goto addroot; |
450 | case BC_JMP: | 510 | case BC_JMP: |
451 | /* Patch exit branch in parent to side trace entry. */ | 511 | /* Patch exit branch in parent to side trace entry. */ |
452 | lua_assert(J->parent != 0 && J->cur.root != 0); | 512 | lj_assertJ(J->parent != 0 && J->cur.root != 0, "not a side trace"); |
453 | lj_asm_patchexit(J, traceref(J, J->parent), J->exitno, J->cur.mcode); | 513 | lj_asm_patchexit(J, traceref(J, J->parent), J->exitno, J->cur.mcode); |
454 | /* Avoid compiling a side trace twice (stack resizing uses parent exit). */ | 514 | /* Avoid compiling a side trace twice (stack resizing uses parent exit). */ |
455 | { | 515 | { |
@@ -465,8 +525,14 @@ static void trace_stop(jit_State *J) | |||
465 | root->nextside = (TraceNo1)traceno; | 525 | root->nextside = (TraceNo1)traceno; |
466 | } | 526 | } |
467 | break; | 527 | break; |
528 | case BC_CALLM: | ||
529 | case BC_CALL: | ||
530 | case BC_ITERC: | ||
531 | /* Trace stitching: patch link of previous trace. */ | ||
532 | traceref(J, J->exitno)->link = traceno; | ||
533 | break; | ||
468 | default: | 534 | default: |
469 | lua_assert(0); | 535 | lj_assertJ(0, "bad stop bytecode %d", op); |
470 | break; | 536 | break; |
471 | } | 537 | } |
472 | 538 | ||
@@ -479,6 +545,7 @@ static void trace_stop(jit_State *J) | |||
479 | lj_vmevent_send(L, TRACE, | 545 | lj_vmevent_send(L, TRACE, |
480 | setstrV(L, L->top++, lj_str_newlit(L, "stop")); | 546 | setstrV(L, L->top++, lj_str_newlit(L, "stop")); |
481 | setintV(L->top++, traceno); | 547 | setintV(L->top++, traceno); |
548 | setfuncV(L, L->top++, J->fn); | ||
482 | ); | 549 | ); |
483 | } | 550 | } |
484 | 551 | ||
@@ -486,8 +553,8 @@ static void trace_stop(jit_State *J) | |||
486 | static int trace_downrec(jit_State *J) | 553 | static int trace_downrec(jit_State *J) |
487 | { | 554 | { |
488 | /* Restart recording at the return instruction. */ | 555 | /* Restart recording at the return instruction. */ |
489 | lua_assert(J->pt != NULL); | 556 | lj_assertJ(J->pt != NULL, "no active prototype"); |
490 | lua_assert(bc_isret(bc_op(*J->pc))); | 557 | lj_assertJ(bc_isret(bc_op(*J->pc)), "not at a return bytecode"); |
491 | if (bc_op(*J->pc) == BC_RETM) | 558 | if (bc_op(*J->pc) == BC_RETM) |
492 | return 0; /* NYI: down-recursion with RETM. */ | 559 | return 0; /* NYI: down-recursion with RETM. */ |
493 | J->parent = 0; | 560 | J->parent = 0; |
@@ -506,6 +573,10 @@ static int trace_abort(jit_State *J) | |||
506 | 573 | ||
507 | J->postproc = LJ_POST_NONE; | 574 | J->postproc = LJ_POST_NONE; |
508 | lj_mcode_abort(J); | 575 | lj_mcode_abort(J); |
576 | if (J->curfinal) { | ||
577 | lj_trace_free(J2G(J), J->curfinal); | ||
578 | J->curfinal = NULL; | ||
579 | } | ||
509 | if (tvisnumber(L->top-1)) | 580 | if (tvisnumber(L->top-1)) |
510 | e = (TraceError)numberVint(L->top-1); | 581 | e = (TraceError)numberVint(L->top-1); |
511 | if (e == LJ_TRERR_MCODELM) { | 582 | if (e == LJ_TRERR_MCODELM) { |
@@ -514,8 +585,17 @@ static int trace_abort(jit_State *J) | |||
514 | return 1; /* Retry ASM with new MCode area. */ | 585 | return 1; /* Retry ASM with new MCode area. */ |
515 | } | 586 | } |
516 | /* Penalize or blacklist starting bytecode instruction. */ | 587 | /* Penalize or blacklist starting bytecode instruction. */ |
517 | if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) | 588 | if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) { |
518 | penalty_pc(J, &gcref(J->cur.startpt)->pt, mref(J->cur.startpc, BCIns), e); | 589 | if (J->exitno == 0) { |
590 | BCIns *startpc = mref(J->cur.startpc, BCIns); | ||
591 | if (e == LJ_TRERR_RETRY) | ||
592 | hotcount_set(J2GG(J), startpc+1, 1); /* Immediate retry. */ | ||
593 | else | ||
594 | penalty_pc(J, &gcref(J->cur.startpt)->pt, startpc, e); | ||
595 | } else { | ||
596 | traceref(J, J->exitno)->link = J->exitno; /* Self-link is blacklisted. */ | ||
597 | } | ||
598 | } | ||
519 | 599 | ||
520 | /* Is there anything to abort? */ | 600 | /* Is there anything to abort? */ |
521 | traceno = J->cur.traceno; | 601 | traceno = J->cur.traceno; |
@@ -581,8 +661,13 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud) | |||
581 | J->state = LJ_TRACE_RECORD; /* trace_start() may change state. */ | 661 | J->state = LJ_TRACE_RECORD; /* trace_start() may change state. */ |
582 | trace_start(J); | 662 | trace_start(J); |
583 | lj_dispatch_update(J2G(J)); | 663 | lj_dispatch_update(J2G(J)); |
584 | break; | 664 | if (J->state != LJ_TRACE_RECORD_1ST) |
665 | break; | ||
666 | /* fallthrough */ | ||
585 | 667 | ||
668 | case LJ_TRACE_RECORD_1ST: | ||
669 | J->state = LJ_TRACE_RECORD; | ||
670 | /* fallthrough */ | ||
586 | case LJ_TRACE_RECORD: | 671 | case LJ_TRACE_RECORD: |
587 | trace_pendpatch(J, 0); | 672 | trace_pendpatch(J, 0); |
588 | setvmstate(J2G(J), RECORD); | 673 | setvmstate(J2G(J), RECORD); |
@@ -688,15 +773,30 @@ static void trace_hotside(jit_State *J, const BCIns *pc) | |||
688 | { | 773 | { |
689 | SnapShot *snap = &traceref(J, J->parent)->snap[J->exitno]; | 774 | SnapShot *snap = &traceref(J, J->parent)->snap[J->exitno]; |
690 | if (!(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT)) && | 775 | if (!(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT)) && |
776 | isluafunc(curr_func(J->L)) && | ||
691 | snap->count != SNAPCOUNT_DONE && | 777 | snap->count != SNAPCOUNT_DONE && |
692 | ++snap->count >= J->param[JIT_P_hotexit]) { | 778 | ++snap->count >= J->param[JIT_P_hotexit]) { |
693 | lua_assert(J->state == LJ_TRACE_IDLE); | 779 | lj_assertJ(J->state == LJ_TRACE_IDLE, "hot side exit while recording"); |
694 | /* J->parent is non-zero for a side trace. */ | 780 | /* J->parent is non-zero for a side trace. */ |
695 | J->state = LJ_TRACE_START; | 781 | J->state = LJ_TRACE_START; |
696 | lj_trace_ins(J, pc); | 782 | lj_trace_ins(J, pc); |
697 | } | 783 | } |
698 | } | 784 | } |
699 | 785 | ||
786 | /* Stitch a new trace to the previous trace. */ | ||
787 | void LJ_FASTCALL lj_trace_stitch(jit_State *J, const BCIns *pc) | ||
788 | { | ||
789 | /* Only start a new trace if not recording or inside __gc call or vmevent. */ | ||
790 | if (J->state == LJ_TRACE_IDLE && | ||
791 | !(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT))) { | ||
792 | J->parent = 0; /* Have to treat it like a root trace. */ | ||
793 | /* J->exitno is set to the invoking trace. */ | ||
794 | J->state = LJ_TRACE_START; | ||
795 | lj_trace_ins(J, pc); | ||
796 | } | ||
797 | } | ||
798 | |||
799 | |||
700 | /* Tiny struct to pass data to protected call. */ | 800 | /* Tiny struct to pass data to protected call. */ |
701 | typedef struct ExitDataCP { | 801 | typedef struct ExitDataCP { |
702 | jit_State *J; | 802 | jit_State *J; |
@@ -740,7 +840,7 @@ static void trace_exit_regs(lua_State *L, ExitState *ex) | |||
740 | } | 840 | } |
741 | #endif | 841 | #endif |
742 | 842 | ||
743 | #ifdef EXITSTATE_PCREG | 843 | #if defined(EXITSTATE_PCREG) || (LJ_UNWIND_JIT && !EXITTRACE_VMSTATE) |
744 | /* Determine trace number from pc of exit instruction. */ | 844 | /* Determine trace number from pc of exit instruction. */ |
745 | static TraceNo trace_exit_find(jit_State *J, MCode *pc) | 845 | static TraceNo trace_exit_find(jit_State *J, MCode *pc) |
746 | { | 846 | { |
@@ -750,7 +850,7 @@ static TraceNo trace_exit_find(jit_State *J, MCode *pc) | |||
750 | if (T && pc >= T->mcode && pc < (MCode *)((char *)T->mcode + T->szmcode)) | 850 | if (T && pc >= T->mcode && pc < (MCode *)((char *)T->mcode + T->szmcode)) |
751 | return traceno; | 851 | return traceno; |
752 | } | 852 | } |
753 | lua_assert(0); | 853 | lj_assertJ(0, "bad exit pc"); |
754 | return 0; | 854 | return 0; |
755 | } | 855 | } |
756 | #endif | 856 | #endif |
@@ -762,40 +862,55 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr) | |||
762 | lua_State *L = J->L; | 862 | lua_State *L = J->L; |
763 | ExitState *ex = (ExitState *)exptr; | 863 | ExitState *ex = (ExitState *)exptr; |
764 | ExitDataCP exd; | 864 | ExitDataCP exd; |
765 | int errcode; | 865 | int errcode, exitcode = J->exitcode; |
866 | TValue exiterr; | ||
766 | const BCIns *pc; | 867 | const BCIns *pc; |
767 | void *cf; | 868 | void *cf; |
768 | GCtrace *T; | 869 | GCtrace *T; |
870 | |||
871 | setnilV(&exiterr); | ||
872 | if (exitcode) { /* Trace unwound with error code. */ | ||
873 | J->exitcode = 0; | ||
874 | copyTV(L, &exiterr, L->top-1); | ||
875 | } | ||
876 | |||
769 | #ifdef EXITSTATE_PCREG | 877 | #ifdef EXITSTATE_PCREG |
770 | J->parent = trace_exit_find(J, (MCode *)(intptr_t)ex->gpr[EXITSTATE_PCREG]); | 878 | J->parent = trace_exit_find(J, (MCode *)(intptr_t)ex->gpr[EXITSTATE_PCREG]); |
771 | #endif | 879 | #endif |
772 | T = traceref(J, J->parent); UNUSED(T); | 880 | T = traceref(J, J->parent); UNUSED(T); |
773 | #ifdef EXITSTATE_CHECKEXIT | 881 | #ifdef EXITSTATE_CHECKEXIT |
774 | if (J->exitno == T->nsnap) { /* Treat stack check like a parent exit. */ | 882 | if (J->exitno == T->nsnap) { /* Treat stack check like a parent exit. */ |
775 | lua_assert(T->root != 0); | 883 | lj_assertJ(T->root != 0, "stack check in root trace"); |
776 | J->exitno = T->ir[REF_BASE].op2; | 884 | J->exitno = T->ir[REF_BASE].op2; |
777 | J->parent = T->ir[REF_BASE].op1; | 885 | J->parent = T->ir[REF_BASE].op1; |
778 | T = traceref(J, J->parent); | 886 | T = traceref(J, J->parent); |
779 | } | 887 | } |
780 | #endif | 888 | #endif |
781 | lua_assert(T != NULL && J->exitno < T->nsnap); | 889 | lj_assertJ(T != NULL && J->exitno < T->nsnap, "bad trace or exit number"); |
782 | exd.J = J; | 890 | exd.J = J; |
783 | exd.exptr = exptr; | 891 | exd.exptr = exptr; |
784 | errcode = lj_vm_cpcall(L, NULL, &exd, trace_exit_cp); | 892 | errcode = lj_vm_cpcall(L, NULL, &exd, trace_exit_cp); |
785 | if (errcode) | 893 | if (errcode) |
786 | return -errcode; /* Return negated error code. */ | 894 | return -errcode; /* Return negated error code. */ |
787 | 895 | ||
788 | lj_vmevent_send(L, TEXIT, | 896 | if (exitcode) copyTV(L, L->top++, &exiterr); /* Anchor the error object. */ |
789 | lj_state_checkstack(L, 4+RID_NUM_GPR+RID_NUM_FPR+LUA_MINSTACK); | 897 | |
790 | setintV(L->top++, J->parent); | 898 | if (!(LJ_HASPROFILE && (G(L)->hookmask & HOOK_PROFILE))) |
791 | setintV(L->top++, J->exitno); | 899 | lj_vmevent_send(L, TEXIT, |
792 | trace_exit_regs(L, ex); | 900 | lj_state_checkstack(L, 4+RID_NUM_GPR+RID_NUM_FPR+LUA_MINSTACK); |
793 | ); | 901 | setintV(L->top++, J->parent); |
902 | setintV(L->top++, J->exitno); | ||
903 | trace_exit_regs(L, ex); | ||
904 | ); | ||
794 | 905 | ||
795 | pc = exd.pc; | 906 | pc = exd.pc; |
796 | cf = cframe_raw(L->cframe); | 907 | cf = cframe_raw(L->cframe); |
797 | setcframe_pc(cf, pc); | 908 | setcframe_pc(cf, pc); |
798 | if (G(L)->gc.state == GCSatomic || G(L)->gc.state == GCSfinalize) { | 909 | if (exitcode) { |
910 | return -exitcode; | ||
911 | } else if (LJ_HASPROFILE && (G(L)->hookmask & HOOK_PROFILE)) { | ||
912 | /* Just exit to interpreter. */ | ||
913 | } else if (G(L)->gc.state == GCSatomic || G(L)->gc.state == GCSfinalize) { | ||
799 | if (!(G(L)->hookmask & HOOK_GC)) | 914 | if (!(G(L)->hookmask & HOOK_GC)) |
800 | lj_gc_step(L); /* Exited because of GC: drive GC forward. */ | 915 | lj_gc_step(L); /* Exited because of GC: drive GC forward. */ |
801 | } else { | 916 | } else { |
@@ -803,13 +918,14 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr) | |||
803 | } | 918 | } |
804 | if (bc_op(*pc) == BC_JLOOP) { | 919 | if (bc_op(*pc) == BC_JLOOP) { |
805 | BCIns *retpc = &traceref(J, bc_d(*pc))->startins; | 920 | BCIns *retpc = &traceref(J, bc_d(*pc))->startins; |
806 | if (bc_isret(bc_op(*retpc))) { | 921 | int isret = bc_isret(bc_op(*retpc)); |
922 | if (isret || bc_op(*retpc) == BC_ITERN) { | ||
807 | if (J->state == LJ_TRACE_RECORD) { | 923 | if (J->state == LJ_TRACE_RECORD) { |
808 | J->patchins = *pc; | 924 | J->patchins = *pc; |
809 | J->patchpc = (BCIns *)pc; | 925 | J->patchpc = (BCIns *)pc; |
810 | *J->patchpc = *retpc; | 926 | *J->patchpc = *retpc; |
811 | J->bcskip = 1; | 927 | J->bcskip = 1; |
812 | } else { | 928 | } else if (isret) { |
813 | pc = retpc; | 929 | pc = retpc; |
814 | setcframe_pc(cf, pc); | 930 | setcframe_pc(cf, pc); |
815 | } | 931 | } |
@@ -819,7 +935,7 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr) | |||
819 | ERRNO_RESTORE | 935 | ERRNO_RESTORE |
820 | switch (bc_op(*pc)) { | 936 | switch (bc_op(*pc)) { |
821 | case BC_CALLM: case BC_CALLMT: | 937 | case BC_CALLM: case BC_CALLMT: |
822 | return (int)((BCReg)(L->top - L->base) - bc_a(*pc) - bc_c(*pc)); | 938 | return (int)((BCReg)(L->top - L->base) - bc_a(*pc) - bc_c(*pc) - LJ_FR2); |
823 | case BC_RETM: | 939 | case BC_RETM: |
824 | return (int)((BCReg)(L->top - L->base) + 1 - bc_a(*pc) - bc_d(*pc)); | 940 | return (int)((BCReg)(L->top - L->base) + 1 - bc_a(*pc) - bc_d(*pc)); |
825 | case BC_TSETM: | 941 | case BC_TSETM: |
@@ -831,4 +947,41 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr) | |||
831 | } | 947 | } |
832 | } | 948 | } |
833 | 949 | ||
950 | #if LJ_UNWIND_JIT | ||
951 | /* Given an mcode address determine trace exit address for unwinding. */ | ||
952 | uintptr_t LJ_FASTCALL lj_trace_unwind(jit_State *J, uintptr_t addr, ExitNo *ep) | ||
953 | { | ||
954 | #if EXITTRACE_VMSTATE | ||
955 | TraceNo traceno = J2G(J)->vmstate; | ||
956 | #else | ||
957 | TraceNo traceno = trace_exit_find(J, (MCode *)addr); | ||
958 | #endif | ||
959 | GCtrace *T = traceref(J, traceno); | ||
960 | if (T | ||
961 | #if EXITTRACE_VMSTATE | ||
962 | && addr >= (uintptr_t)T->mcode && addr < (uintptr_t)T->mcode + T->szmcode | ||
963 | #endif | ||
964 | ) { | ||
965 | SnapShot *snap = T->snap; | ||
966 | SnapNo lo = 0, exitno = T->nsnap; | ||
967 | uintptr_t ofs = (uintptr_t)((MCode *)addr - T->mcode); /* MCode units! */ | ||
968 | /* Rightmost binary search for mcode offset to determine exit number. */ | ||
969 | do { | ||
970 | SnapNo mid = (lo+exitno) >> 1; | ||
971 | if (ofs < snap[mid].mcofs) exitno = mid; else lo = mid + 1; | ||
972 | } while (lo < exitno); | ||
973 | exitno--; | ||
974 | *ep = exitno; | ||
975 | #ifdef EXITSTUBS_PER_GROUP | ||
976 | return (uintptr_t)exitstub_addr(J, exitno); | ||
977 | #else | ||
978 | return (uintptr_t)exitstub_trace_addr(T, exitno); | ||
979 | #endif | ||
980 | } | ||
981 | /* Cannot correlate addr with trace/exit. This will be fatal. */ | ||
982 | lj_assertJ(0, "bad exit pc"); | ||
983 | return 0; | ||
984 | } | ||
985 | #endif | ||
986 | |||
834 | #endif | 987 | #endif |