diff options
author | Mike Pall <mike> | 2010-02-04 03:08:29 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2010-02-04 03:08:29 +0100 |
commit | 7256690364a2c9a5e9269ffd89bc132ee188480d (patch) | |
tree | 20d8a6a37fb64492e12407ee412b4c2f10137e93 /src/lj_record.c | |
parent | 78f5e2ffd34e01626b910341a7808ea4be8a6d0d (diff) | |
download | luajit-7256690364a2c9a5e9269ffd89bc132ee188480d.tar.gz luajit-7256690364a2c9a5e9269ffd89bc132ee188480d.tar.bz2 luajit-7256690364a2c9a5e9269ffd89bc132ee188480d.zip |
Add shadow frame link stack for trace recorder.
Simplifies snapshots. Prerequisite for pre-call snapshots.
Increases consistency for fast function calls, too.
Diffstat (limited to 'src/lj_record.c')
-rw-r--r-- | src/lj_record.c | 63 |
1 files changed, 55 insertions, 8 deletions
diff --git a/src/lj_record.c b/src/lj_record.c index 824d2fd1..f6d13264 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
@@ -101,20 +101,45 @@ static void rec_check_ir(jit_State *J) | |||
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | /* Compare frame stack of the recorder and the VM. */ | ||
105 | static void rec_check_frames(jit_State *J) | ||
106 | { | ||
107 | cTValue *frame = J->L->base - 1; | ||
108 | cTValue *lim = J->L->base - J->baseslot; | ||
109 | int32_t depth = J->framedepth; | ||
110 | while (frame > lim) { | ||
111 | depth--; | ||
112 | lua_assert(depth >= 0); | ||
113 | lua_assert((SnapEntry)frame_ftsz(frame) == J->frame[depth]); | ||
114 | if (frame_iscont(frame)) { | ||
115 | depth--; | ||
116 | lua_assert(depth >= 0); | ||
117 | lua_assert((SnapEntry)frame_ftsz(frame-1) == J->frame[depth]); | ||
118 | } | ||
119 | frame = frame_prev(frame); | ||
120 | } | ||
121 | lua_assert(depth == 0); | ||
122 | } | ||
123 | |||
104 | /* Sanity check the slots. */ | 124 | /* Sanity check the slots. */ |
105 | static void rec_check_slots(jit_State *J) | 125 | static void rec_check_slots(jit_State *J) |
106 | { | 126 | { |
107 | BCReg s, nslots = J->baseslot + J->maxslot; | 127 | BCReg s, nslots = J->baseslot + J->maxslot; |
128 | int32_t depth; | ||
108 | lua_assert(J->baseslot >= 1 && J->baseslot < LJ_MAX_JSLOTS); | 129 | lua_assert(J->baseslot >= 1 && J->baseslot < LJ_MAX_JSLOTS); |
109 | lua_assert(nslots < LJ_MAX_JSLOTS); | 130 | lua_assert(nslots < LJ_MAX_JSLOTS); |
110 | for (s = 0; s < nslots; s++) { | 131 | for (s = 0; s < nslots; s++) { |
111 | TRef tr = J->slot[s]; | 132 | TRef tr = J->slot[s]; |
133 | if (s != 0 && (tr & (TREF_CONT|TREF_FRAME))) | ||
134 | depth++; | ||
112 | if (tr) { | 135 | if (tr) { |
113 | IRRef ref = tref_ref(tr); | 136 | IRRef ref = tref_ref(tr); |
114 | lua_assert(ref >= J->cur.nk && ref < J->cur.nins); | 137 | lua_assert(ref >= J->cur.nk && ref < J->cur.nins); |
115 | lua_assert(irt_t(IR(ref)->t) == tref_t(tr)); | 138 | lua_assert(irt_t(IR(ref)->t) == tref_t(tr)); |
116 | } | 139 | } |
117 | } | 140 | } |
141 | lua_assert(J->framedepth == depth); | ||
142 | rec_check_frames(J); | ||
118 | } | 143 | } |
119 | #endif | 144 | #endif |
120 | 145 | ||
@@ -854,6 +879,7 @@ typedef struct RecordFFData { | |||
854 | ptrdiff_t nres; /* Number of returned results (defaults to 1). */ | 879 | ptrdiff_t nres; /* Number of returned results (defaults to 1). */ |
855 | ptrdiff_t cres; /* Wanted number of call results. */ | 880 | ptrdiff_t cres; /* Wanted number of call results. */ |
856 | uint32_t data; /* Per-ffid auxiliary data (opcode, literal etc.). */ | 881 | uint32_t data; /* Per-ffid auxiliary data (opcode, literal etc.). */ |
882 | int metacall; /* True if function was resolved via __call. */ | ||
857 | } RecordFFData; | 883 | } RecordFFData; |
858 | 884 | ||
859 | /* Type of handler to record a fast function. */ | 885 | /* Type of handler to record a fast function. */ |
@@ -1020,9 +1046,14 @@ static void recff_tostring(jit_State *J, TRef *res, RecordFFData *rd) | |||
1020 | ix.tab = tr; | 1046 | ix.tab = tr; |
1021 | copyTV(J->L, &ix.tabv, &rd->argv[0]); | 1047 | copyTV(J->L, &ix.tabv, &rd->argv[0]); |
1022 | if (rec_mm_lookup(J, &ix, MM_tostring)) { /* Has __tostring metamethod? */ | 1048 | if (rec_mm_lookup(J, &ix, MM_tostring)) { /* Has __tostring metamethod? */ |
1049 | if (rd->metacall) /* Must not use kludge. */ | ||
1050 | recff_err_nyi(J, rd); | ||
1023 | res[0] = ix.mobj; | 1051 | res[0] = ix.mobj; |
1024 | copyTV(J->L, rd->argv - 1, &ix.mobjv); | 1052 | copyTV(J->L, rd->argv - 1, &ix.mobjv); /* Kludge. */ |
1025 | if (!rec_call(J, (BCReg)(res - J->base), 1, 1)) /* Pending call? */ | 1053 | J->framedepth--; |
1054 | if (rec_call(J, (BCReg)(res - J->base), 1, 1)) | ||
1055 | J->framedepth++; | ||
1056 | else | ||
1026 | rd->cres = CALLRES_PENDING; | 1057 | rd->cres = CALLRES_PENDING; |
1027 | /* Otherwise res[0] already contains the result. */ | 1058 | /* Otherwise res[0] already contains the result. */ |
1028 | } else if (tref_isnumber(tr)) { | 1059 | } else if (tref_isnumber(tr)) { |
@@ -1067,6 +1098,8 @@ static void recff_pcall(jit_State *J, TRef *res, RecordFFData *rd) | |||
1067 | { | 1098 | { |
1068 | if (rd->nargs >= 1) { | 1099 | if (rd->nargs >= 1) { |
1069 | BCReg parg = (BCReg)(arg - J->base); | 1100 | BCReg parg = (BCReg)(arg - J->base); |
1101 | J->pc = (const BCIns *)(sizeof(TValue) - 4 + | ||
1102 | (hook_active(J2G(J)) ? FRAME_PCALLH : FRAME_PCALL)); | ||
1070 | if (rec_call(J, parg, CALLRES_MULTI, rd->nargs - 1)) { /* Resolved call. */ | 1103 | if (rec_call(J, parg, CALLRES_MULTI, rd->nargs - 1)) { /* Resolved call. */ |
1071 | res[0] = TREF_TRUE; /* Prepend true result. No need to move results. */ | 1104 | res[0] = TREF_TRUE; /* Prepend true result. No need to move results. */ |
1072 | rd->nres = (ptrdiff_t)J->maxslot - (ptrdiff_t)parg + 1; | 1105 | rd->nres = (ptrdiff_t)J->maxslot - (ptrdiff_t)parg + 1; |
@@ -1108,6 +1141,8 @@ static void recff_xpcall(jit_State *J, TRef *res, RecordFFData *rd) | |||
1108 | copyTV(J->L, &rd->argv[0], &argv1); | 1141 | copyTV(J->L, &rd->argv[0], &argv1); |
1109 | copyTV(J->L, &rd->argv[1], &argv0); | 1142 | copyTV(J->L, &rd->argv[1], &argv0); |
1110 | oargv = savestack(J->L, rd->argv); | 1143 | oargv = savestack(J->L, rd->argv); |
1144 | J->pc = (const BCIns *)(2*sizeof(TValue) - 4 + | ||
1145 | (hook_active(J2G(J)) ? FRAME_PCALLH : FRAME_PCALL)); | ||
1111 | /* Need to protect rec_call because the recorder may throw. */ | 1146 | /* Need to protect rec_call because the recorder may throw. */ |
1112 | rx.parg = parg; | 1147 | rx.parg = parg; |
1113 | rx.nargs = rd->nargs - 2; | 1148 | rx.nargs = rd->nargs - 2; |
@@ -1549,7 +1584,7 @@ static void rec_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) | |||
1549 | } else if (frame_iscont(frame)) { /* Return to continuation frame. */ | 1584 | } else if (frame_iscont(frame)) { /* Return to continuation frame. */ |
1550 | ASMFunction cont = frame_contf(frame); | 1585 | ASMFunction cont = frame_contf(frame); |
1551 | BCReg cbase = (BCReg)frame_delta(frame); | 1586 | BCReg cbase = (BCReg)frame_delta(frame); |
1552 | if (J->framedepth-- <= 0) | 1587 | if ((J->framedepth -= 2) <= 0) |
1553 | lj_trace_err(J, LJ_TRERR_NYIRETL); | 1588 | lj_trace_err(J, LJ_TRERR_NYIRETL); |
1554 | J->baseslot -= (BCReg)cbase; | 1589 | J->baseslot -= (BCReg)cbase; |
1555 | J->base -= cbase; | 1590 | J->base -= cbase; |
@@ -1602,6 +1637,7 @@ static int rec_call(jit_State *J, BCReg func, ptrdiff_t cres, ptrdiff_t nargs) | |||
1602 | if (tref_isfunc(res[0])) { /* Regular function call. */ | 1637 | if (tref_isfunc(res[0])) { /* Regular function call. */ |
1603 | rd.fn = funcV(tv); | 1638 | rd.fn = funcV(tv); |
1604 | rd.argv = tv+1; | 1639 | rd.argv = tv+1; |
1640 | rd.metacall = 0; | ||
1605 | } else { /* Otherwise resolve __call metamethod for called object. */ | 1641 | } else { /* Otherwise resolve __call metamethod for called object. */ |
1606 | RecordIndex ix; | 1642 | RecordIndex ix; |
1607 | ptrdiff_t i; | 1643 | ptrdiff_t i; |
@@ -1615,13 +1651,21 @@ static int rec_call(jit_State *J, BCReg func, ptrdiff_t cres, ptrdiff_t nargs) | |||
1615 | res[0] = ix.mobj; | 1651 | res[0] = ix.mobj; |
1616 | rd.fn = funcV(&ix.mobjv); | 1652 | rd.fn = funcV(&ix.mobjv); |
1617 | rd.argv = tv; /* The called object is the 1st arg. */ | 1653 | rd.argv = tv; /* The called object is the 1st arg. */ |
1654 | rd.metacall = 1; | ||
1618 | } | 1655 | } |
1619 | 1656 | ||
1620 | /* Specialize to the runtime value of the called function. */ | 1657 | /* Specialize to the runtime value of the called function. */ |
1621 | trfunc = lj_ir_kfunc(J, rd.fn); | 1658 | trfunc = lj_ir_kfunc(J, rd.fn); |
1622 | emitir(IRTG(IR_EQ, IRT_FUNC), res[0], trfunc); | 1659 | emitir(IRTG(IR_EQ, IRT_FUNC), res[0], trfunc); |
1623 | res[0] = trfunc | TREF_FRAME; | 1660 | res[0] = trfunc | TREF_FRAME; |
1624 | J->framedepth++; | 1661 | |
1662 | /* Add frame links. */ | ||
1663 | J->frame[J->framedepth++] = SNAP_MKPC(J->pc+1); | ||
1664 | if (cres == CALLRES_CONT) /* Continuations need an extra frame stack slot. */ | ||
1665 | J->frame[J->framedepth++] = SNAP_MKFTSZ((func+1)*sizeof(TValue)+FRAME_CONT); | ||
1666 | /* NYI: func is wrong if any fast function ever sets up a continuation. */ | ||
1667 | if (J->framedepth > LJ_MAX_JFRAME) | ||
1668 | lj_trace_err(J, LJ_TRERR_STACKOV); | ||
1625 | 1669 | ||
1626 | if (isluafunc(rd.fn)) { /* Record call to Lua function. */ | 1670 | if (isluafunc(rd.fn)) { /* Record call to Lua function. */ |
1627 | GCproto *pt = funcproto(rd.fn); | 1671 | GCproto *pt = funcproto(rd.fn); |
@@ -1659,6 +1703,7 @@ static int rec_call(jit_State *J, BCReg func, ptrdiff_t cres, ptrdiff_t nargs) | |||
1659 | return 0; /* No result yet. */ | 1703 | return 0; /* No result yet. */ |
1660 | } else { /* Record call to C function or fast function. */ | 1704 | } else { /* Record call to C function or fast function. */ |
1661 | uint32_t m = 0; | 1705 | uint32_t m = 0; |
1706 | BCReg oldmaxslot = J->maxslot; | ||
1662 | res[1+nargs] = 0; | 1707 | res[1+nargs] = 0; |
1663 | rd.nargs = nargs; | 1708 | rd.nargs = nargs; |
1664 | if (rd.fn->c.ffid < sizeof(recff_idmap)/sizeof(recff_idmap[0])) | 1709 | if (rd.fn->c.ffid < sizeof(recff_idmap)/sizeof(recff_idmap[0])) |
@@ -1682,10 +1727,12 @@ static int rec_call(jit_State *J, BCReg func, ptrdiff_t cres, ptrdiff_t nargs) | |||
1682 | rec_ret(J, func, rd.nres); | 1727 | rec_ret(J, func, rd.nres); |
1683 | } else if (cres == CALLRES_CONT) { | 1728 | } else if (cres == CALLRES_CONT) { |
1684 | /* Note: immediately resolved continuations must not change J->maxslot. */ | 1729 | /* Note: immediately resolved continuations must not change J->maxslot. */ |
1730 | J->maxslot = oldmaxslot; | ||
1731 | J->framedepth--; | ||
1685 | res[rd.nres] = TREF_NIL; /* Turn 0 results into nil result. */ | 1732 | res[rd.nres] = TREF_NIL; /* Turn 0 results into nil result. */ |
1686 | } else { | 1733 | } else { |
1687 | J->framedepth++; | ||
1688 | lua_assert(cres == CALLRES_PENDING); | 1734 | lua_assert(cres == CALLRES_PENDING); |
1735 | J->framedepth++; | ||
1689 | return 0; /* Pending call, no result yet. */ | 1736 | return 0; /* Pending call, no result yet. */ |
1690 | } | 1737 | } |
1691 | return 1; /* Result resolved immediately. */ | 1738 | return 1; /* Result resolved immediately. */ |
@@ -2213,13 +2260,13 @@ static void rec_setup_side(jit_State *J, Trace *T) | |||
2213 | } | 2260 | } |
2214 | setslot: | 2261 | setslot: |
2215 | J->slot[s] = tr | (sn&(SNAP_CONT|SNAP_FRAME)); /* Same as TREF_* flags. */ | 2262 | J->slot[s] = tr | (sn&(SNAP_CONT|SNAP_FRAME)); /* Same as TREF_* flags. */ |
2216 | if ((sn & SNAP_FRAME) && s != 0) { | 2263 | if ((sn & SNAP_FRAME) && s != 0) |
2217 | J->baseslot = s+1; | 2264 | J->baseslot = s+1; |
2218 | J->framedepth++; | ||
2219 | } | ||
2220 | } | 2265 | } |
2221 | J->base = J->slot + J->baseslot; | 2266 | J->base = J->slot + J->baseslot; |
2222 | J->maxslot = snap->nslots - J->baseslot; | 2267 | J->maxslot = snap->nslots - J->baseslot; |
2268 | J->framedepth = snap->depth; /* Copy frames from snapshot. */ | ||
2269 | memcpy(J->frame, &map[nent+1], sizeof(SnapEntry)*(size_t)snap->depth); | ||
2223 | lj_snap_add(J); | 2270 | lj_snap_add(J); |
2224 | } | 2271 | } |
2225 | 2272 | ||