Skip to content

Commit

Permalink
Perl_leave_adjust_stacks: additional efficiencies when making mortal …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
richardleach committed Apr 21, 2024
1 parent bc24c73 commit ec161f3
Showing 1 changed file with 29 additions and 4 deletions.
33 changes: 29 additions & 4 deletions pp_hot.c
Original file line number Diff line number Diff line change
Expand Up @@ -5992,15 +5992,25 @@ Perl_leave_adjust_stacks(pTHX_ SV **from_sp, SV **to_sp, U8 gimme, int pass)
* ++PL_tmps_ix, moving the previous occupant there
* instead.
*/
SV *newsv = newSV_type(SVt_NULL);

/* A newsv of type SVt_NULL will always be upgraded to
* SvTYPE(sv), where that is a SVt_PVNV or below. It is
* more efficient to create such types directly than
* upgrade to them via sv_upgrade() within sv_setsv_flags. */
SV *newsv = (SvTYPE(sv) <= SVt_PVNV)
? newSV_type(SvTYPE(sv))
: newSV_type(SVt_NULL);

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

#if NVSIZE <= IVSIZE
if (SvTYPE(sv) <= SVt_NV) {
#else
if (SvTYPE(sv) <= SVt_IV) {
/* arg must be one of undef, IV/UV, or RV: skip
* sv_setsv_flags() and do the copy directly */
#endif
/* arg must be one of undef/IV/UV/RV - maybe NV depending on
* config, skip sv_setsv_flags() and do the copy directly */
U32 dstflags;
U32 srcflags = SvFLAGS(sv);

Expand Down Expand Up @@ -6028,6 +6038,21 @@ Perl_leave_adjust_stacks(pTHX_ SV **from_sp, SV **to_sp, U8 gimme, int pass)
|(srcflags & SVf_IVisUV));
}
}
#if NVSIZE <= IVSIZE
else if (srcflags & SVf_NOK) {
SET_SVANY_FOR_BODYLESS_NV(newsv);
dstflags = (SVt_NV|SVf_NOK|SVp_NOK|SVs_TEMP);

/* both src and dst are <= SVt_MV, so sv_any points to the
* head; so access the head directly
*/
assert( &(sv->sv_u.svu_nv)
== &(((XPVNV*) SvANY(sv))->xnv_u.xnv_nv));
assert( &(newsv->sv_u.svu_nv)
== &(((XPVNV*) SvANY(newsv))->xnv_u.xnv_nv));
newsv->sv_u.svu_nv = sv->sv_u.svu_nv;
}
#endif
else {
assert(!(srcflags & SVf_OK));
dstflags = (SVt_NULL|SVs_TEMP); /* SV type plus flags */
Expand Down

0 comments on commit ec161f3

Please sign in to comment.