Perl_leave_scope - sv_backoff shouldn't do an unnecessay string copy

When a `my` SV goes out of scope, any OOK hack on its string buffer is
undone by `Perl_sv_backoff`. If the SV is `SvOK`, a copy of the buffer
contents will occur, but since the contents are defunct at this point,
the copy is unnecessary.

See https://github.com/Perl/perl5/issues/23967 as an example of where
this unnecessary copy had a noticeable effect on performance.

This commit essentially inlines the necessary parts of `sv_backoff` to
avoid the copy, without excessive messing around with `sv`'s flags at
the call site in `Perl_leave_scope`.
This commit is contained in:
Richard Leach 2025-11-29 00:31:51 +00:00
parent e3b0f74b83
commit 4342210875

16
scope.c
View File

@ -1440,8 +1440,20 @@ Perl_leave_scope(pTHX_ I32 base)
if (SvTYPE(sv) == SVt_PVHV && HvHasAUX(sv)) if (SvTYPE(sv) == SVt_PVHV && HvHasAUX(sv))
Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv)); Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv));
else if(SvOOK(sv)) else if(SvOOK(sv)) {
sv_backoff(sv); /* Inlined sv_backoff() - the buffer contents are
* defunct and there's no need to copy them. All that
* is needed is resetting SvLEN and the SvPVX pointer. */
assert(SvTYPE(sv) != SVt_PVHV); /* the branch above */
assert(SvTYPE(sv) != SVt_PVAV);
STRLEN delta;
SvOOK_offset(sv, delta);
SvLEN_set(sv, SvLEN(sv) + delta);
SvPV_set(sv, SvPVX(sv) - delta);
SvFLAGS(sv) &= ~SVf_OOK;
}
if (SvMAGICAL(sv)) { if (SvMAGICAL(sv)) {
/* note that backrefs (either in HvAUX or magic) /* note that backrefs (either in HvAUX or magic)