diff options
Diffstat (limited to '')
-rw-r--r-- | src/lj_record.c | 130 |
1 files changed, 125 insertions, 5 deletions
diff --git a/src/lj_record.c b/src/lj_record.c index a1471aae..e51c98ba 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
@@ -156,6 +156,9 @@ static void rec_check_slots(jit_State *J) | |||
156 | lj_assertJ((J->slot[s+1+LJ_FR2] & TREF_FRAME), | 156 | lj_assertJ((J->slot[s+1+LJ_FR2] & TREF_FRAME), |
157 | "cont slot %d not followed by frame", s); | 157 | "cont slot %d not followed by frame", s); |
158 | depth++; | 158 | depth++; |
159 | } else if ((tr & TREF_KEYINDEX)) { | ||
160 | lj_assertJ(tref_isint(tr), "keyindex slot %d bad type %d", | ||
161 | s, tref_type(tr)); | ||
159 | } else { | 162 | } else { |
160 | /* Number repr. may differ, but other types must be the same. */ | 163 | /* Number repr. may differ, but other types must be the same. */ |
161 | lj_assertJ(tvisnumber(tv) ? tref_isnumber(tr) : | 164 | lj_assertJ(tvisnumber(tv) ? tref_isnumber(tr) : |
@@ -283,9 +286,9 @@ static void canonicalize_slots(jit_State *J) | |||
283 | if (LJ_DUALNUM) return; | 286 | if (LJ_DUALNUM) return; |
284 | for (s = J->baseslot+J->maxslot-1; s >= 1; s--) { | 287 | for (s = J->baseslot+J->maxslot-1; s >= 1; s--) { |
285 | TRef tr = J->slot[s]; | 288 | TRef tr = J->slot[s]; |
286 | if (tref_isinteger(tr)) { | 289 | if (tref_isinteger(tr) && !(tr & TREF_KEYINDEX)) { |
287 | IRIns *ir = IR(tref_ref(tr)); | 290 | IRIns *ir = IR(tref_ref(tr)); |
288 | if (!(ir->o == IR_SLOAD && (ir->op2 & IRSLOAD_READONLY))) | 291 | if (!(ir->o == IR_SLOAD && (ir->op2 & (IRSLOAD_READONLY)))) |
289 | J->slot[s] = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT); | 292 | J->slot[s] = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT); |
290 | } | 293 | } |
291 | } | 294 | } |
@@ -606,6 +609,7 @@ static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev) | |||
606 | { | 609 | { |
607 | if (J->parent == 0 && J->exitno == 0) { | 610 | if (J->parent == 0 && J->exitno == 0) { |
608 | if (pc == J->startpc && J->framedepth + J->retdepth == 0) { | 611 | if (pc == J->startpc && J->framedepth + J->retdepth == 0) { |
612 | if (bc_op(J->cur.startins) == BC_ITERN) return; /* See rec_itern(). */ | ||
609 | /* Same loop? */ | 613 | /* Same loop? */ |
610 | if (ev == LOOPEV_LEAVE) /* Must loop back to form a root trace. */ | 614 | if (ev == LOOPEV_LEAVE) /* Must loop back to form a root trace. */ |
611 | lj_trace_err(J, LJ_TRERR_LLEAVE); | 615 | lj_trace_err(J, LJ_TRERR_LLEAVE); |
@@ -646,6 +650,68 @@ static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev) | |||
646 | } /* Side trace continues across a loop that's left or not entered. */ | 650 | } /* Side trace continues across a loop that's left or not entered. */ |
647 | } | 651 | } |
648 | 652 | ||
653 | /* Record ITERN. */ | ||
654 | static LoopEvent rec_itern(jit_State *J, BCReg ra, BCReg rb) | ||
655 | { | ||
656 | #if LJ_BE | ||
657 | /* YAGNI: Disabled on big-endian due to issues with lj_vm_next, | ||
658 | ** IR_HIOP, RID_RETLO/RID_RETHI and ra_destpair. | ||
659 | */ | ||
660 | UNUSED(ra); UNUSED(rb); | ||
661 | setintV(&J->errinfo, (int32_t)BC_ITERN); | ||
662 | lj_trace_err_info(J, LJ_TRERR_NYIBC); | ||
663 | #else | ||
664 | RecordIndex ix; | ||
665 | /* Since ITERN is recorded at the start, we need our own loop detection. */ | ||
666 | if (J->pc == J->startpc && J->cur.nins > REF_FIRST && | ||
667 | J->framedepth + J->retdepth == 0 && J->parent == 0 && J->exitno == 0) { | ||
668 | lj_record_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Looping trace. */ | ||
669 | return LOOPEV_ENTER; | ||
670 | } | ||
671 | J->maxslot = ra; | ||
672 | lj_snap_add(J); /* Required to make JLOOP the first ins in a side-trace. */ | ||
673 | ix.tab = getslot(J, ra-2); | ||
674 | ix.key = J->base[ra-1] ? J->base[ra-1] : | ||
675 | sloadt(J, (int32_t)(ra-1), IRT_INT, IRSLOAD_KEYINDEX); | ||
676 | copyTV(J->L, &ix.tabv, &J->L->base[ra-2]); | ||
677 | copyTV(J->L, &ix.keyv, &J->L->base[ra-1]); | ||
678 | ix.idxchain = (rb < 3); /* Omit value type check, if unused. */ | ||
679 | ix.mobj = 1; /* We need the next index, too. */ | ||
680 | J->maxslot = ra + lj_record_next(J, &ix); | ||
681 | J->needsnap = 1; | ||
682 | if (!tref_isnil(ix.key)) { /* Looping back? */ | ||
683 | J->base[ra-1] = ix.mobj | TREF_KEYINDEX; /* Control var has next index. */ | ||
684 | J->base[ra] = ix.key; | ||
685 | J->base[ra+1] = ix.val; | ||
686 | J->pc += bc_j(J->pc[1])+2; | ||
687 | return LOOPEV_ENTER; | ||
688 | } else { | ||
689 | J->maxslot = ra-3; | ||
690 | J->pc += 2; | ||
691 | return LOOPEV_LEAVE; | ||
692 | } | ||
693 | #endif | ||
694 | } | ||
695 | |||
696 | /* Record ISNEXT. */ | ||
697 | static void rec_isnext(jit_State *J, BCReg ra) | ||
698 | { | ||
699 | cTValue *b = &J->L->base[ra-3]; | ||
700 | if (tvisfunc(b) && funcV(b)->c.ffid == FF_next && | ||
701 | tvistab(b+1) && tvisnil(b+2)) { | ||
702 | /* These checks are folded away for a compiled pairs(). */ | ||
703 | TRef func = getslot(J, ra-3); | ||
704 | TRef trid = emitir(IRT(IR_FLOAD, IRT_U8), func, IRFL_FUNC_FFID); | ||
705 | emitir(IRTGI(IR_EQ), trid, lj_ir_kint(J, FF_next)); | ||
706 | (void)getslot(J, ra-2); /* Type check for table. */ | ||
707 | (void)getslot(J, ra-1); /* Type check for nil key. */ | ||
708 | J->base[ra-1] = lj_ir_kint(J, 0) | TREF_KEYINDEX; | ||
709 | J->maxslot = ra; | ||
710 | } else { /* Abort trace. Interpreter will despecialize bytecode. */ | ||
711 | lj_trace_err(J, LJ_TRERR_RECERR); | ||
712 | } | ||
713 | } | ||
714 | |||
649 | /* -- Record profiler hook checks ----------------------------------------- */ | 715 | /* -- Record profiler hook checks ----------------------------------------- */ |
650 | 716 | ||
651 | #if LJ_HASPROFILE | 717 | #if LJ_HASPROFILE |
@@ -716,7 +782,7 @@ static TRef rec_call_specialize(jit_State *J, GCfunc *fn, TRef tr) | |||
716 | /* NYI: io_file_iter doesn't have an ffid, yet. */ | 782 | /* NYI: io_file_iter doesn't have an ffid, yet. */ |
717 | { /* Specialize to the ffid. */ | 783 | { /* Specialize to the ffid. */ |
718 | TRef trid = emitir(IRT(IR_FLOAD, IRT_U8), tr, IRFL_FUNC_FFID); | 784 | TRef trid = emitir(IRT(IR_FLOAD, IRT_U8), tr, IRFL_FUNC_FFID); |
719 | emitir(IRTG(IR_EQ, IRT_INT), trid, lj_ir_kint(J, fn->c.ffid)); | 785 | emitir(IRTGI(IR_EQ), trid, lj_ir_kint(J, fn->c.ffid)); |
720 | } | 786 | } |
721 | return tr; | 787 | return tr; |
722 | default: | 788 | default: |
@@ -1565,6 +1631,47 @@ TRef lj_record_idx(jit_State *J, RecordIndex *ix) | |||
1565 | } | 1631 | } |
1566 | } | 1632 | } |
1567 | 1633 | ||
1634 | /* Determine result type of table traversal. */ | ||
1635 | static IRType rec_next_types(GCtab *t, uint32_t idx) | ||
1636 | { | ||
1637 | for (; idx < t->asize; idx++) { | ||
1638 | cTValue *a = arrayslot(t, idx); | ||
1639 | if (LJ_LIKELY(!tvisnil(a))) | ||
1640 | return (LJ_DUALNUM ? IRT_INT : IRT_NUM) + (itype2irt(a) << 8); | ||
1641 | } | ||
1642 | idx -= t->asize; | ||
1643 | for (; idx <= t->hmask; idx++) { | ||
1644 | Node *n = &noderef(t->node)[idx]; | ||
1645 | if (!tvisnil(&n->val)) | ||
1646 | return itype2irt(&n->key) + (itype2irt(&n->val) << 8); | ||
1647 | } | ||
1648 | return IRT_NIL + (IRT_NIL << 8); | ||
1649 | } | ||
1650 | |||
1651 | /* Record a table traversal step aka next(). */ | ||
1652 | int lj_record_next(jit_State *J, RecordIndex *ix) | ||
1653 | { | ||
1654 | IRType t, tkey, tval; | ||
1655 | TRef trvk; | ||
1656 | t = rec_next_types(tabV(&ix->tabv), ix->keyv.u32.lo); | ||
1657 | tkey = (t & 0xff); tval = (t >> 8); | ||
1658 | trvk = lj_ir_call(J, IRCALL_lj_vm_next, ix->tab, ix->key); | ||
1659 | if (ix->mobj || tkey == IRT_NIL) { | ||
1660 | TRef idx = emitir(IRTI(IR_HIOP), trvk, trvk); | ||
1661 | /* Always check for invalid key from next() for nil result. */ | ||
1662 | if (!ix->mobj) emitir(IRTGI(IR_NE), idx, lj_ir_kint(J, -1)); | ||
1663 | ix->mobj = idx; | ||
1664 | } | ||
1665 | ix->key = lj_record_vload(J, trvk, 1, tkey); | ||
1666 | if (tkey == IRT_NIL || ix->idxchain) { /* Omit value type check. */ | ||
1667 | ix->val = TREF_NIL; | ||
1668 | return 1; | ||
1669 | } else { /* Need value. */ | ||
1670 | ix->val = lj_record_vload(J, trvk, 0, tval); | ||
1671 | return 2; | ||
1672 | } | ||
1673 | } | ||
1674 | |||
1568 | static void rec_tsetm(jit_State *J, BCReg ra, BCReg rn, int32_t i) | 1675 | static void rec_tsetm(jit_State *J, BCReg ra, BCReg rn, int32_t i) |
1569 | { | 1676 | { |
1570 | RecordIndex ix; | 1677 | RecordIndex ix; |
@@ -2440,6 +2547,9 @@ void lj_record_ins(jit_State *J) | |||
2440 | case BC_ITERL: | 2547 | case BC_ITERL: |
2441 | rec_loop_interp(J, pc, rec_iterl(J, *pc)); | 2548 | rec_loop_interp(J, pc, rec_iterl(J, *pc)); |
2442 | break; | 2549 | break; |
2550 | case BC_ITERN: | ||
2551 | rec_loop_interp(J, pc, rec_itern(J, ra, rb)); | ||
2552 | break; | ||
2443 | case BC_LOOP: | 2553 | case BC_LOOP: |
2444 | rec_loop_interp(J, pc, rec_loop(J, ra, 1)); | 2554 | rec_loop_interp(J, pc, rec_loop(J, ra, 1)); |
2445 | break; | 2555 | break; |
@@ -2468,6 +2578,10 @@ void lj_record_ins(jit_State *J) | |||
2468 | J->maxslot = ra; /* Shrink used slots. */ | 2578 | J->maxslot = ra; /* Shrink used slots. */ |
2469 | break; | 2579 | break; |
2470 | 2580 | ||
2581 | case BC_ISNEXT: | ||
2582 | rec_isnext(J, ra); | ||
2583 | break; | ||
2584 | |||
2471 | /* -- Function headers -------------------------------------------------- */ | 2585 | /* -- Function headers -------------------------------------------------- */ |
2472 | 2586 | ||
2473 | case BC_FUNCF: | 2587 | case BC_FUNCF: |
@@ -2497,8 +2611,6 @@ void lj_record_ins(jit_State *J) | |||
2497 | break; | 2611 | break; |
2498 | } | 2612 | } |
2499 | /* fallthrough */ | 2613 | /* fallthrough */ |
2500 | case BC_ITERN: | ||
2501 | case BC_ISNEXT: | ||
2502 | case BC_UCLO: | 2614 | case BC_UCLO: |
2503 | case BC_FNEW: | 2615 | case BC_FNEW: |
2504 | setintV(&J->errinfo, (int32_t)op); | 2616 | setintV(&J->errinfo, (int32_t)op); |
@@ -2550,6 +2662,13 @@ static const BCIns *rec_setup_root(jit_State *J) | |||
2550 | lj_assertJ(bc_op(pc[-1]) == BC_JMP, "ITERL does not point to JMP+1"); | 2662 | lj_assertJ(bc_op(pc[-1]) == BC_JMP, "ITERL does not point to JMP+1"); |
2551 | J->bc_min = pc; | 2663 | J->bc_min = pc; |
2552 | break; | 2664 | break; |
2665 | case BC_ITERN: | ||
2666 | lj_assertJ(bc_op(pc[1]) == BC_ITERL, "no ITERL after ITERN"); | ||
2667 | J->maxslot = ra; | ||
2668 | J->bc_extent = (MSize)(-bc_j(pc[1]))*sizeof(BCIns); | ||
2669 | J->bc_min = pc+2 + bc_j(pc[1]); | ||
2670 | J->state = LJ_TRACE_RECORD_1ST; /* Record the first ITERN, too. */ | ||
2671 | break; | ||
2553 | case BC_LOOP: | 2672 | case BC_LOOP: |
2554 | /* Only check BC range for real loops, but not for "repeat until true". */ | 2673 | /* Only check BC range for real loops, but not for "repeat until true". */ |
2555 | pcj = pc + bc_j(ins); | 2674 | pcj = pc + bc_j(ins); |
@@ -2657,6 +2776,7 @@ void lj_record_setup(jit_State *J) | |||
2657 | J->pc = rec_setup_root(J); | 2776 | J->pc = rec_setup_root(J); |
2658 | /* Note: the loop instruction itself is recorded at the end and not | 2777 | /* Note: the loop instruction itself is recorded at the end and not |
2659 | ** at the start! So snapshot #0 needs to point to the *next* instruction. | 2778 | ** at the start! So snapshot #0 needs to point to the *next* instruction. |
2779 | ** The one exception is BC_ITERN, which sets LJ_TRACE_RECORD_1ST. | ||
2660 | */ | 2780 | */ |
2661 | lj_snap_add(J); | 2781 | lj_snap_add(J); |
2662 | if (bc_op(J->cur.startins) == BC_FORL) | 2782 | if (bc_op(J->cur.startins) == BC_FORL) |