diff options
author | Mike Pall <mike> | 2010-04-18 13:41:30 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2010-04-19 00:43:35 +0200 |
commit | 932cda0fe3cbd34e60aa68479935c946f69b756f (patch) | |
tree | 9e46aa620a75b5ac5bc95413b8b7b57e507d82a1 /src/lj_asm.c | |
parent | ff82df797a5ddf6ed2610ff1808b1fdc53686ea1 (diff) | |
download | luajit-932cda0fe3cbd34e60aa68479935c946f69b756f.tar.gz luajit-932cda0fe3cbd34e60aa68479935c946f69b756f.tar.bz2 luajit-932cda0fe3cbd34e60aa68479935c946f69b756f.zip |
Replace on-trace GC frame syncing with interpreter exit.
Need to sync GC objects to stack only during atomic GC phase.
Need to setup a proper frame structure only for calling finalizers.
Force an exit to the interpreter and let it handle the uncommon cases.
Finally solves the "NYI: gcstep sync with frames" issue.
Diffstat (limited to 'src/lj_asm.c')
-rw-r--r-- | src/lj_asm.c | 66 |
1 files changed, 17 insertions, 49 deletions
diff --git a/src/lj_asm.c b/src/lj_asm.c index 75a0cd53..73416768 100644 --- a/src/lj_asm.c +++ b/src/lj_asm.c | |||
@@ -2752,67 +2752,32 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap) | |||
2752 | 2752 | ||
2753 | /* -- GC handling --------------------------------------------------------- */ | 2753 | /* -- GC handling --------------------------------------------------------- */ |
2754 | 2754 | ||
2755 | /* Sync all live GC values to Lua stack slots. */ | ||
2756 | static void asm_gc_sync(ASMState *as, SnapShot *snap, Reg base) | ||
2757 | { | ||
2758 | /* Some care must be taken when allocating registers here, since this is | ||
2759 | ** not part of the fast path. All scratch registers are evicted in the | ||
2760 | ** fast path, so it's easiest to force allocation from scratch registers | ||
2761 | ** only. This avoids register allocation state unification. | ||
2762 | */ | ||
2763 | RegSet allow = rset_exclude(RSET_SCRATCH & RSET_GPR, base); | ||
2764 | SnapEntry *map = &as->T->snapmap[snap->mapofs]; | ||
2765 | MSize n, nent = snap->nent; | ||
2766 | for (n = 0; n < nent; n++) { | ||
2767 | SnapEntry sn = map[n]; | ||
2768 | IRRef ref = snap_ref(sn); | ||
2769 | /* NYI: sync the frame, bump base, set topslot, clear new slots. */ | ||
2770 | if ((sn & (SNAP_CONT|SNAP_FRAME))) | ||
2771 | lj_trace_err(as->J, LJ_TRERR_NYIGCF); | ||
2772 | if (!irref_isk(ref)) { | ||
2773 | IRIns *ir = IR(ref); | ||
2774 | if (irt_isgcv(ir->t)) { | ||
2775 | int32_t ofs = 8*(int32_t)(snap_slot(sn)-1); | ||
2776 | Reg src = ra_alloc1(as, ref, allow); | ||
2777 | emit_movtomro(as, src, base, ofs); | ||
2778 | emit_movmroi(as, base, ofs+4, irt_toitype(ir->t)); | ||
2779 | checkmclim(as); | ||
2780 | } | ||
2781 | } | ||
2782 | } | ||
2783 | } | ||
2784 | |||
2785 | /* Check GC threshold and do one or more GC steps. */ | 2755 | /* Check GC threshold and do one or more GC steps. */ |
2786 | static void asm_gc_check(ASMState *as, SnapShot *snap) | 2756 | static void asm_gc_check(ASMState *as) |
2787 | { | 2757 | { |
2788 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_step_jit]; | 2758 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_step_jit]; |
2789 | IRRef args[2]; | 2759 | IRRef args[2]; |
2790 | MCLabel l_end; | 2760 | MCLabel l_end; |
2791 | Reg base, lstate, tmp; | 2761 | Reg base, lstate, tmp; |
2792 | RegSet drop = RSET_SCRATCH; | 2762 | ra_evictset(as, RSET_SCRATCH); |
2793 | if (ra_hasreg(IR(REF_BASE)->r)) /* Stack may be reallocated by the GC. */ | ||
2794 | drop |= RID2RSET(IR(REF_BASE)->r); /* Need to evict BASE, too. */ | ||
2795 | ra_evictset(as, drop); | ||
2796 | l_end = emit_label(as); | 2763 | l_end = emit_label(as); |
2764 | /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */ | ||
2765 | asm_guardcc(as, CC_NE); /* Assumes asm_snap_prep() already done. */ | ||
2766 | emit_rr(as, XO_TEST, RID_RET, RID_RET); | ||
2797 | args[0] = ASMREF_L; | 2767 | args[0] = ASMREF_L; |
2798 | args[1] = ASMREF_TMP1; | 2768 | args[1] = ASMREF_TMP1; |
2799 | asm_gencall(as, ci, args); | 2769 | asm_gencall(as, ci, args); |
2800 | tmp = ra_releasetmp(as, ASMREF_TMP1); | 2770 | tmp = ra_releasetmp(as, ASMREF_TMP1); |
2801 | emit_loadi(as, tmp, (int32_t)as->gcsteps); | 2771 | emit_loadi(as, tmp, (int32_t)as->gcsteps); |
2802 | /* We don't know spadj yet, so get the C frame from L->cframe. */ | ||
2803 | emit_movmroi(as, tmp, CFRAME_OFS_PC, | ||
2804 | (int32_t)as->T->snapmap[snap->mapofs+snap->nent]); | ||
2805 | emit_gri(as, XG_ARITHi(XOg_AND), tmp|REX_64, CFRAME_RAWMASK); | ||
2806 | lstate = IR(ASMREF_L)->r; | ||
2807 | emit_rmro(as, XO_MOV, tmp|REX_64, lstate, offsetof(lua_State, cframe)); | ||
2808 | /* It's ok if lstate is already in a non-scratch reg. But all allocations | 2772 | /* It's ok if lstate is already in a non-scratch reg. But all allocations |
2809 | ** in the non-fast path must use a scratch reg. See comment above. | 2773 | ** in the non-fast path must use a scratch reg (avoids unification). |
2810 | */ | 2774 | */ |
2775 | lstate = IR(ASMREF_L)->r; | ||
2811 | base = ra_alloc1(as, REF_BASE, rset_exclude(RSET_SCRATCH & RSET_GPR, lstate)); | 2776 | base = ra_alloc1(as, REF_BASE, rset_exclude(RSET_SCRATCH & RSET_GPR, lstate)); |
2812 | emit_movtomro(as, base|REX_64, lstate, offsetof(lua_State, base)); | 2777 | emit_movtomro(as, base|REX_64, lstate, offsetof(lua_State, base)); |
2813 | asm_gc_sync(as, snap, base); | ||
2814 | /* BASE/L get restored anyway, better do it inside the slow path. */ | 2778 | /* BASE/L get restored anyway, better do it inside the slow path. */ |
2815 | if (as->parent || as->curins == as->loopref) ra_restore(as, REF_BASE); | 2779 | if (rset_test(RSET_SCRATCH, base) && (as->parent || as->snapno != 0)) |
2780 | ra_restore(as, REF_BASE); | ||
2816 | if (rset_test(RSET_SCRATCH, lstate) && ra_hasreg(IR(ASMREF_L)->r)) | 2781 | if (rset_test(RSET_SCRATCH, lstate) && ra_hasreg(IR(ASMREF_L)->r)) |
2817 | ra_restore(as, ASMREF_L); | 2782 | ra_restore(as, ASMREF_L); |
2818 | /* Jump around GC step if GC total < GC threshold. */ | 2783 | /* Jump around GC step if GC total < GC threshold. */ |
@@ -3034,7 +2999,7 @@ static void asm_loop(ASMState *as) | |||
3034 | /* LOOP is a guard, so the snapno is up to date. */ | 2999 | /* LOOP is a guard, so the snapno is up to date. */ |
3035 | as->loopsnapno = as->snapno; | 3000 | as->loopsnapno = as->snapno; |
3036 | if (as->gcsteps) | 3001 | if (as->gcsteps) |
3037 | asm_gc_check(as, &as->T->snap[as->loopsnapno]); | 3002 | asm_gc_check(as); |
3038 | /* LOOP marks the transition from the variant to the invariant part. */ | 3003 | /* LOOP marks the transition from the variant to the invariant part. */ |
3039 | as->testmcp = as->invmcp = NULL; | 3004 | as->testmcp = as->invmcp = NULL; |
3040 | as->sectref = 0; | 3005 | as->sectref = 0; |
@@ -3126,7 +3091,7 @@ static void asm_head_side(ASMState *as) | |||
3126 | allow = asm_head_side_base(as, pbase, allow); | 3091 | allow = asm_head_side_base(as, pbase, allow); |
3127 | 3092 | ||
3128 | /* Scan all parent SLOADs and collect register dependencies. */ | 3093 | /* Scan all parent SLOADs and collect register dependencies. */ |
3129 | for (i = as->curins; i > REF_BASE; i--) { | 3094 | for (i = as->stopins; i > REF_BASE; i--) { |
3130 | IRIns *ir = IR(i); | 3095 | IRIns *ir = IR(i); |
3131 | RegSP rs; | 3096 | RegSP rs; |
3132 | lua_assert(ir->o == IR_SLOAD && (ir->op2 & IRSLOAD_PARENT)); | 3097 | lua_assert(ir->o == IR_SLOAD && (ir->op2 & IRSLOAD_PARENT)); |
@@ -3161,7 +3126,7 @@ static void asm_head_side(ASMState *as) | |||
3161 | 3126 | ||
3162 | /* Reload spilled target registers. */ | 3127 | /* Reload spilled target registers. */ |
3163 | if (pass2) { | 3128 | if (pass2) { |
3164 | for (i = as->curins; i > REF_BASE; i--) { | 3129 | for (i = as->stopins; i > REF_BASE; i--) { |
3165 | IRIns *ir = IR(i); | 3130 | IRIns *ir = IR(i); |
3166 | if (irt_ismarked(ir->t)) { | 3131 | if (irt_ismarked(ir->t)) { |
3167 | RegSet mask; | 3132 | RegSet mask; |
@@ -3686,8 +3651,11 @@ void lj_asm_trace(jit_State *J, Trace *T) | |||
3686 | 3651 | ||
3687 | RA_DBG_REF(); | 3652 | RA_DBG_REF(); |
3688 | checkmclim(as); | 3653 | checkmclim(as); |
3689 | if (as->gcsteps) | 3654 | if (as->gcsteps) { |
3690 | asm_gc_check(as, &as->T->snap[0]); | 3655 | as->curins = as->T->snap[0].ref; |
3656 | asm_snap_prep(as); /* The GC check is a guard. */ | ||
3657 | asm_gc_check(as); | ||
3658 | } | ||
3691 | ra_evictk(as); | 3659 | ra_evictk(as); |
3692 | if (as->parent) | 3660 | if (as->parent) |
3693 | asm_head_side(as); | 3661 | asm_head_side(as); |