summaryrefslogtreecommitdiff
path: root/src/lj_record.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_record.c')
-rw-r--r--src/lj_record.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/lj_record.c b/src/lj_record.c
index da9c221c..62f5c066 100644
--- a/src/lj_record.c
+++ b/src/lj_record.c
@@ -522,6 +522,29 @@ static void rec_tailcall(jit_State *J, BCReg func, ptrdiff_t nargs)
522 lj_trace_err(J, LJ_TRERR_LUNROLL); 522 lj_trace_err(J, LJ_TRERR_LUNROLL);
523} 523}
524 524
525/* Check unroll limits for down-recursion. */
526static int check_downrec_unroll(jit_State *J, GCproto *pt)
527{
528 IRRef ptref;
529 for (ptref = J->chain[IR_KGC]; ptref; ptref = IR(ptref)->prev)
530 if (ir_kgc(IR(ptref)) == obj2gco(pt)) {
531 int count = 0;
532 IRRef ref;
533 for (ref = J->chain[IR_RETF]; ref; ref = IR(ref)->prev)
534 if (IR(ref)->op1 == ptref)
535 count++;
536 if (count) {
537 if (J->pc == J->startpc) {
538 if (count + J->tailcalled > J->param[JIT_P_recunroll])
539 return 1;
540 } else {
541 lj_trace_err(J, LJ_TRERR_DOWNREC);
542 }
543 }
544 }
545 return 0;
546}
547
525/* Record return. */ 548/* Record return. */
526static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) 549static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
527{ 550{
@@ -545,6 +568,15 @@ static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
545 BCIns callins = *(frame_pc(frame)-1); 568 BCIns callins = *(frame_pc(frame)-1);
546 ptrdiff_t nresults = bc_b(callins) ? (ptrdiff_t)bc_b(callins)-1 :gotresults; 569 ptrdiff_t nresults = bc_b(callins) ? (ptrdiff_t)bc_b(callins)-1 :gotresults;
547 BCReg cbase = bc_a(callins); 570 BCReg cbase = bc_a(callins);
571 GCproto *pt = funcproto(frame_func(frame - (cbase+1)));
572 if (J->pt && frame == J->L->base - 1) {
573 if (J->framedepth == 0 && check_downrec_unroll(J, pt)) {
574 J->maxslot = rbase + nresults;
575 rec_stop(J, J->curtrace); /* Down-recursion. */
576 return;
577 }
578 lj_snap_add(J);
579 }
548 for (i = 0; i < nresults; i++) /* Adjust results. */ 580 for (i = 0; i < nresults; i++) /* Adjust results. */
549 J->base[i-1] = i < gotresults ? J->base[rbase+i] : TREF_NIL; 581 J->base[i-1] = i < gotresults ? J->base[rbase+i] : TREF_NIL;
550 J->maxslot = cbase+(BCReg)nresults; 582 J->maxslot = cbase+(BCReg)nresults;
@@ -553,11 +585,10 @@ static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
553 lua_assert(J->baseslot > cbase+1); 585 lua_assert(J->baseslot > cbase+1);
554 J->baseslot -= cbase+1; 586 J->baseslot -= cbase+1;
555 J->base -= cbase+1; 587 J->base -= cbase+1;
556 } else if (J->parent == 0) { 588 } else if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) {
557 /* Return to lower frame would leave the loop in a root trace. */ 589 /* Return to lower frame would leave the loop in a root trace. */
558 lj_trace_err(J, LJ_TRERR_LLEAVE); 590 lj_trace_err(J, LJ_TRERR_LLEAVE);
559 } else { /* Return to lower frame. Guard for the target we return to. */ 591 } else { /* Return to lower frame. Guard for the target we return to. */
560 GCproto *pt = funcproto(frame_func(frame - (cbase+1)));
561 TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); 592 TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO);
562 TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame)); 593 TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame));
563 emitir(IRTG(IR_RETF, IRT_PTR), trpt, trpc); 594 emitir(IRTG(IR_RETF, IRT_PTR), trpt, trpc);
@@ -2285,6 +2316,12 @@ static const BCIns *rec_setup_root(jit_State *J)
2285 J->maxslot = ra; 2316 J->maxslot = ra;
2286 pc++; 2317 pc++;
2287 break; 2318 break;
2319 case BC_RET:
2320 case BC_RET0:
2321 case BC_RET1:
2322 /* No bytecode range check for down-recursive root traces. */
2323 J->maxslot = ra + bc_d(ins);
2324 break;
2288 case BC_FUNCF: 2325 case BC_FUNCF:
2289 /* No bytecode range check for root traces started by a hot call. */ 2326 /* No bytecode range check for root traces started by a hot call. */
2290 J->maxslot = J->pt->numparams; 2327 J->maxslot = J->pt->numparams;