diff options
Diffstat (limited to 'src/lj_record.c')
-rw-r--r-- | src/lj_record.c | 41 |
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. */ | ||
526 | static 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. */ |
526 | static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) | 549 | static 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; |