summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Dragan <bulk88@hotmail.com>2014-09-23 18:19:32 -0400
committerFather Chrysostomos <sprout@cpan.org>2014-09-23 18:15:20 -0700
commit7776003ecba252f04a5359ee75d84770ad318f9a (patch)
tree9f2a41d3b2de4e7af3c02dc05192f01a6a671d92
parent0c7df90239f4c313f42964755700c2a3c78ec63c (diff)
downloadperl-7776003ecba252f04a5359ee75d84770ad318f9a.tar.gz
optimize pp_length for simple PVs
Previously in pp_length, for non-magic, non-utf8 PVs, a number of conditional branches based on bitfield testing had to execute, and finally the length of a non-utf8 SVPV was fetched with sv_len_utf8_nomg. sv_len_utf8_nomg checks SvUTF8, and if false, use the len from SvPV_nomg_const call in sv_len_utf8_nomg. Note in pp_length, SvPV_nomg_const already exists for the "use bytes" branch. After this patch, a !SvGMAGICAL && (!SvUTF8 || use_bytes) SV will take only 1 conditional branch and no func calls before reaching sv_setiv. svflags is reused for the mg_get test since partially masked svflags will already be in a register vs fetching the whole flags from SV head again. SETS(TARG) was factored out from all the SETI/SETTARG macros. If targ is not set/written to (the PL_sv_undef branch), do not check/call for set magic on it, just return from the opcode. Also a putback was removed since the operand SV is replaced inplace on Perl stack with a SV with IV length in it. For profiling info, profiling stats, and rejected implementations see [perl #122835]
-rw-r--r--pod/perldelta.pod3
-rw-r--r--pp.c39
2 files changed, 32 insertions, 10 deletions
diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 608c1df506..65c495aa0e 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -104,7 +104,8 @@ There may well be none in a stable release.
=item *
-XXX
+C<length> is upto 20% faster for non-magical/non-tied containing a string and
+either non-utf8 or C<use bytes;> scalars.
=back
diff --git a/pp.c b/pp.c
index d33914b449..18c3f03464 100644
--- a/pp.c
+++ b/pp.c
@@ -2956,24 +2956,45 @@ PP(pp_length)
dSP; dTARGET;
SV * const sv = TOPs;
- SvGETMAGIC(sv);
+ U32 in_bytes = IN_BYTES;
+ /* simplest case shortcut */
+ /* turn off SVf_UTF8 in tmp flags if HINT_BYTES on*/
+ U32 svflags = (SvFLAGS(sv) ^ (in_bytes << 26)) & (SVf_POK|SVs_GMG|SVf_UTF8);
+ assert(HINT_BYTES == 0x00000008 && SVf_UTF8 == 0x20000000 && (SVf_UTF8 == HINT_BYTES << 26));
+ SETs(TARG);
+
+ if(LIKELY(svflags == SVf_POK))
+ goto simple_pv;
+ if(svflags & SVs_GMG)
+ mg_get(sv);
if (SvOK(sv)) {
- if (!IN_BYTES)
- SETi(sv_len_utf8_nomg(sv));
+ if (!IN_BYTES) /* reread to avoid using an C auto/register */
+ sv_setiv(TARG, (IV)sv_len_utf8_nomg(sv));
else
{
STRLEN len;
- (void)SvPV_nomg_const(sv,len);
- SETi(len);
+ /* unrolled SvPV_nomg_const(sv,len) */
+ if(SvPOK_nog(sv)){
+ simple_pv:
+ len = SvCUR(sv);
+ } else {
+ (void)sv_2pv_flags(sv, &len, 0|SV_CONST_RETURN);
+ }
+ sv_setiv(TARG, (IV)(len));
}
} else {
if (!SvPADTMP(TARG)) {
sv_setsv_nomg(TARG, &PL_sv_undef);
- SETTARG;
- }
- SETs(&PL_sv_undef);
+ } else { /* TARG is on stack at this point and is overwriten by SETs.
+ This branch is the odd one out, so put TARG by default on
+ stack earlier to let local SP go out of liveness sooner */
+ SETs(&PL_sv_undef);
+ goto no_set_magic;
+ }
}
- RETURN;
+ SvSETMAGIC(TARG);
+ no_set_magic:
+ return NORMAL; /* no putback, SP didn't move in this opcode */
}
/* Returns false if substring is completely outside original string.