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.
This commit is contained in:
David Mitchell 2015-10-22 16:43:49 +01:00
parent d48c660dfc
commit edba15b0cc

84
pp.h
View File

@ -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