diff options
author | David Mitchell <davem@iabyn.com> | 2015-10-22 16:43:49 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2015-11-10 13:52:34 +0000 |
commit | edba15b0ccf22f00ea6d7cc58eb2c173437a09cc (patch) | |
tree | 5059ae1193b24bff9924af56d20536824f3e2a77 | |
parent | d48c660dfce02fc4e698f3b0589c77612ecf27a4 (diff) | |
download | perl-edba15b0ccf22f00ea6d7cc58eb2c173437a09cc.tar.gz |
make SETi/u/n, (X)PUSHi/u/n more efficient
These macros are used by many pp functions to set TARG to an int or float
value and put it on the stack. The macros use a call to sv_setiv()
or similar.
However, there is a good chance that the target is ether a lexical var
or a PADTMP that has been assigned just an IV/NV in the past, in which
case its body is likely to still be of type SVt_IV/SVt_NV. If this is
the case, we can set its value much more efficiently.
Update those setting macros to first check if the target has a simple
body, and if so, set directly.
This makes quite a significant performance difference on code that does
a lot of arithmetic, at the cost of a larger binary (0.36% on my Linux
x86_64 system).
It also allows you (at compile time) to skip testing for taint if you
know that the value can't be tainted (e.g. pp_add() when both args are
non-magical and so can't have taint magic attached). The next commit will
make use of this.
Includes a couple of efficiency tweaks suggested by Daniel Dragan.
-rw-r--r-- | pp.h | 84 |
1 files changed, 75 insertions, 9 deletions
@@ -371,19 +371,85 @@ Does not use C<TARG>. See also C<L</XPUSHu>>, C<L</mPUSHu>> and C<L</PUSHu>>. } } STMT_END #endif +/* set TARG to the IV value i. If do_taint is false, + * assume that PL_tainted can never be true */ +#define TARGi(i, do_taint) \ + STMT_START { \ + IV TARGi_iv = i; \ + if (LIKELY( \ + ((SvFLAGS(TARG) & (SVTYPEMASK|SVf_THINKFIRST)) == SVt_IV) \ + & (do_taint ? !TAINT_get : 1))) \ + { \ + /* Cheap SvIOK_only(). \ + * Assert that flags which SvIOK_only() would test or \ + * clear can't be set, because we're SVt_IV */ \ + assert(!(SvFLAGS(TARG) & \ + (SVf_OOK|SVf_UTF8|(SVf_OK & ~(SVf_IOK|SVp_IOK))))); \ + SvFLAGS(TARG) |= (SVf_IOK|SVp_IOK); \ + /* SvIV_set() where sv_any points to head */ \ + TARG->sv_u.svu_iv = TARGi_iv; \ + } \ + else \ + sv_setiv_mg(targ, TARGi_iv); \ + } STMT_END + +/* set TARG to the UV value u. If do_taint is false, + * assume that PL_tainted can never be true */ +#define TARGu(u, do_taint) \ + STMT_START { \ + UV TARGu_uv = u; \ + if (LIKELY( \ + ((SvFLAGS(TARG) & (SVTYPEMASK|SVf_THINKFIRST)) == SVt_IV) \ + & (do_taint ? !TAINT_get : 1) \ + & (TARGu_uv <= (UV)IV_MAX))) \ + { \ + /* Cheap SvIOK_only(). \ + * Assert that flags which SvIOK_only() would test or \ + * clear can't be set, because we're SVt_IV */ \ + assert(!(SvFLAGS(TARG) & \ + (SVf_OOK|SVf_UTF8|(SVf_OK & ~(SVf_IOK|SVp_IOK))))); \ + SvFLAGS(TARG) |= (SVf_IOK|SVp_IOK); \ + /* SvIV_set() where sv_any points to head */ \ + TARG->sv_u.svu_iv = TARGu_uv; \ + } \ + else \ + sv_setuv_mg(targ, TARGu_uv); \ + } STMT_END + +/* set TARG to the NV value n. If do_taint is false, + * assume that PL_tainted can never be true */ +#define TARGn(n, do_taint) \ + STMT_START { \ + NV TARGn_nv = n; \ + if (LIKELY( \ + ((SvFLAGS(TARG) & (SVTYPEMASK|SVf_THINKFIRST)) == SVt_NV) \ + & (do_taint ? !TAINT_get : 1))) \ + { \ + /* Cheap SvNOK_only(). \ + * Assert that flags which SvNOK_only() would test or \ + * clear can't be set, because we're SVt_NV */ \ + assert(!(SvFLAGS(TARG) & \ + (SVf_OOK|SVf_UTF8|(SVf_OK & ~(SVf_NOK|SVp_NOK))))); \ + SvFLAGS(TARG) |= (SVf_NOK|SVp_NOK); \ + SvNV_set(TARG, TARGn_nv); \ + } \ + else \ + sv_setnv_mg(targ, TARGn_nv); \ + } STMT_END + #define PUSHs(s) (*++sp = (s)) #define PUSHTARG STMT_START { SvSETMAGIC(TARG); PUSHs(TARG); } STMT_END #define PUSHp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); PUSHTARG; } STMT_END -#define PUSHn(n) STMT_START { sv_setnv(TARG, (NV)(n)); PUSHTARG; } STMT_END -#define PUSHi(i) STMT_START { sv_setiv(TARG, (IV)(i)); PUSHTARG; } STMT_END -#define PUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG; } STMT_END +#define PUSHn(n) STMT_START { TARGn(n,1); PUSHs(TARG); } STMT_END +#define PUSHi(i) STMT_START { TARGi(i,1); PUSHs(TARG); } STMT_END +#define PUSHu(u) STMT_START { TARGu(u,1); PUSHs(TARG); } STMT_END #define XPUSHs(s) STMT_START { EXTEND(sp,1); *++sp = (s); } STMT_END #define XPUSHTARG STMT_START { SvSETMAGIC(TARG); XPUSHs(TARG); } STMT_END #define XPUSHp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); XPUSHTARG; } STMT_END -#define XPUSHn(n) STMT_START { sv_setnv(TARG, (NV)(n)); XPUSHTARG; } STMT_END -#define XPUSHi(i) STMT_START { sv_setiv(TARG, (IV)(i)); XPUSHTARG; } STMT_END -#define XPUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END +#define XPUSHn(n) STMT_START { TARGn(n,1); XPUSHs(TARG); } STMT_END +#define XPUSHi(i) STMT_START { TARGi(i,1); XPUSHs(TARG); } STMT_END +#define XPUSHu(u) STMT_START { TARGu(u,1); XPUSHs(TARG); } STMT_END #define XPUSHundef STMT_START { SvOK_off(TARG); XPUSHs(TARG); } STMT_END #define mPUSHs(s) PUSHs(sv_2mortal(s)) @@ -403,9 +469,9 @@ Does not use C<TARG>. See also C<L</XPUSHu>>, C<L</mPUSHu>> and C<L</PUSHu>>. #define SETs(s) (*sp = s) #define SETTARG STMT_START { SvSETMAGIC(TARG); SETs(TARG); } STMT_END #define SETp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); SETTARG; } STMT_END -#define SETn(n) STMT_START { sv_setnv(TARG, (NV)(n)); SETTARG; } STMT_END -#define SETi(i) STMT_START { sv_setiv(TARG, (IV)(i)); SETTARG; } STMT_END -#define SETu(u) STMT_START { sv_setuv(TARG, (UV)(u)); SETTARG; } STMT_END +#define SETn(n) STMT_START { TARGn(n,1); SETs(TARG); } STMT_END +#define SETi(i) STMT_START { TARGi(i,1); SETs(TARG); } STMT_END +#define SETu(u) STMT_START { TARGu(u,1); SETs(TARG); } STMT_END #define dTOPss SV *sv = TOPs #define dPOPss SV *sv = POPs |