From 4342210875c1fea7efb91105b1d600cbea2cc012 Mon Sep 17 00:00:00 2001 From: Richard Leach Date: Sat, 29 Nov 2025 00:31:51 +0000 Subject: [PATCH] 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`. --- scope.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/scope.c b/scope.c index b8063c2776..dddd1018bf 100644 --- a/scope.c +++ b/scope.c @@ -1440,8 +1440,20 @@ Perl_leave_scope(pTHX_ I32 base) if (SvTYPE(sv) == SVt_PVHV && HvHasAUX(sv)) Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv)); - else if(SvOOK(sv)) - sv_backoff(sv); + else if(SvOOK(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)) { /* note that backrefs (either in HvAUX or magic)