Skip to content

Commit 8456431

Browse files
committed
Perl_leave_adjust_stacks: additional efficiency for mortal copies
The existing code has a fast path for copying a SVt_NULL or SVt_IV. For all other types, a new SVt_NULL is passed into sv_setsv_flags, where it will be upgraded into the required type by sv_upgrade(). This commit makes two changes: 1) Special case copying a SVt_NV where possible, as sv_setsv_flags does. 2) It's safe and more efficient to directly create a new type of SVt_PVNV or below, rather than upgrade it later, so do that.
1 parent a902d92 commit 8456431

File tree

1 file changed

+26
-4
lines changed

1 file changed

+26
-4
lines changed

pp_hot.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5992,15 +5992,22 @@ Perl_leave_adjust_stacks(pTHX_ SV **from_sp, SV **to_sp, U8 gimme, int pass)
59925992
* ++PL_tmps_ix, moving the previous occupant there
59935993
* instead.
59945994
*/
5995-
SV *newsv = newSV_type(SVt_NULL);
5995+
5996+
/* A newsv of type SVt_NULL will always be upgraded to
5997+
* SvTYPE(sv), where that is a SVt_PVNV or below. It is
5998+
* more efficient to create such types directly than
5999+
* upgrade to them via sv_upgrade() within sv_setsv_flags. */
6000+
SV *newsv = (SvTYPE(sv) <= SVt_PVNV)
6001+
? newSV_type(SvTYPE(sv))
6002+
: newSV_type(SVt_NULL);
59966003

59976004
PL_tmps_stack[++PL_tmps_ix] = *tmps_basep;
59986005
/* put it on the tmps stack early so it gets freed if we die */
59996006
*tmps_basep++ = newsv;
60006007

6001-
if (SvTYPE(sv) <= SVt_IV) {
6002-
/* arg must be one of undef, IV/UV, or RV: skip
6003-
* sv_setsv_flags() and do the copy directly */
6008+
if (SvTYPE(sv) <= (NVSIZE <= IVSIZE ? SVt_NV : SVt_IV)) {
6009+
/* arg must be one of undef/IV/UV/RV - maybe NV depending on
6010+
* config, skip sv_setsv_flags() and do the copy directly */
60046011
U32 dstflags;
60056012
U32 srcflags = SvFLAGS(sv);
60066013

@@ -6028,6 +6035,21 @@ Perl_leave_adjust_stacks(pTHX_ SV **from_sp, SV **to_sp, U8 gimme, int pass)
60286035
|(srcflags & SVf_IVisUV));
60296036
}
60306037
}
6038+
#if NVSIZE <= IVSIZE
6039+
else if (srcflags & SVf_NOK) {
6040+
SET_SVANY_FOR_BODYLESS_NV(newsv);
6041+
dstflags = (SVt_NV|SVf_NOK|SVp_NOK|SVs_TEMP);
6042+
6043+
/* both src and dst are <= SVt_MV, so sv_any points to the
6044+
* head; so access the head directly
6045+
*/
6046+
assert( &(sv->sv_u.svu_nv)
6047+
== &(((XPVNV*) SvANY(sv))->xnv_u.xnv_nv));
6048+
assert( &(newsv->sv_u.svu_nv)
6049+
== &(((XPVNV*) SvANY(newsv))->xnv_u.xnv_nv));
6050+
newsv->sv_u.svu_nv = sv->sv_u.svu_nv;
6051+
}
6052+
#endif
60316053
else {
60326054
assert(!(srcflags & SVf_OK));
60336055
dstflags = (SVt_NULL|SVs_TEMP); /* SV type plus flags */

0 commit comments

Comments
 (0)