Commit 2af6430c2b for perl

commit 2af6430c2b73cbd5ab2f627b65659a54d5371f97
Author: Paul Evans <leonerd@leonerd.org.uk>
Date:   Wed Nov 11 14:39:33 2026 +0000

    pp_rv2{av,hv}: Make use of PL_sv_zero

    This makes these two ops use the same optimisation that `pp_padav` uses
    to avoid creating a zero temporary when asked for a package array or
    hash in scalar context. By reusing `PL_sv_zero` we save memory churn in
    creating a temporary just to set its value to zero.

    As a side-effect of the way it is implemented, we also get this
    behaviour for free from `pp_padhv`.

diff --git a/pp_hot.c b/pp_hot.c
index bf0ab509de..5e27b6f62d 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2312,13 +2312,14 @@ S_padhv_rv2hv_common(pTHX_ HV *hv, U8 gimme, bool is_keys, bool has_targ)
         }
         else {
           push_i:
-            if (has_targ) {
+            if (!i)
+                rpp_push_IMM(&PL_sv_zero);
+            else if (has_targ) {
                 dTARGET;
                 TARGi(i,1);
                 rpp_push_1(targ);
             }
-            else
-            if (is_keys) {
+            else if (is_keys) {
                 /* parent op should be an unused OP_KEYS whose targ we can
                  * use */
                 dTARG;
@@ -2509,8 +2510,10 @@ PP(pp_rv2av)

         if (gimme == G_SCALAR) {
             const SSize_t maxarg = AvFILL(av) + 1;
-            if (PL_op->op_private & OPpTRUEBOOL)
-                rpp_replace_1_IMM_NN(maxarg ? &PL_sv_yes : &PL_sv_zero);
+            if (!maxarg)
+                rpp_replace_1_IMM_NN(&PL_sv_zero);
+            else if (PL_op->op_private & OPpTRUEBOOL)
+                rpp_replace_1_IMM_NN(&PL_sv_yes);
             else {
                 dTARGET;
                 TARGi(maxarg, 1);
diff --git a/t/op/svflags.t b/t/op/svflags.t
index 703ea6d26b..91cfbd2047 100644
--- a/t/op/svflags.t
+++ b/t/op/svflags.t
@@ -10,7 +10,7 @@ BEGIN {
 # Tests the new documented mechanism for determining the original type
 # of an SV.

-plan tests => 24;
+plan tests => 27;
 use strict;
 use B qw(svref_2object SVf_IOK SVf_NOK SVf_POK);

@@ -123,8 +123,34 @@ CODE
 unlike($got, qr/Conditional jump or move depends on uninitialised value/,
         'All fields initialized in SVt_PV[IV|NV|MG] copies');

-my @arr;
-# pp_padav pushes $PL_sv_zero to the stack here
-my $sc = scalar @arr;
-$xobj = svref_2object(\$sc);
-is($xobj->FLAGS & (SVf_IOK | SVf_POK), SVf_IOK, "PL_sv_zero behaves as number (not string) first");
+# pp_padav returns PL_sv_zero if count=0
+{
+    my @arr;
+    my $sc = scalar @arr;
+    $xobj = svref_2object(\$sc);
+    is($xobj->FLAGS & (SVf_IOK | SVf_POK), SVf_IOK, "PL_sv_zero from pp_padav behaves as number (not string) first");
+}
+
+# pp_padhv returns PL_sv_zero if count=0
+{
+    my %hash;
+    my $sc = scalar %hash;
+    $xobj = svref_2object(\$sc);
+    is($xobj->FLAGS & (SVf_IOK | SVf_POK), SVf_IOK, "PL_sv_zero from pp_padhv behaves as number (not string) first");
+}
+
+# pp_rv2av returns PL_sv_zero if count=0
+{
+    our @pkgarr;
+    my $sc = scalar @pkgarr;
+    $xobj = svref_2object(\$sc);
+    is($xobj->FLAGS & (SVf_IOK | SVf_POK), SVf_IOK, "PL_sv_zero from pp_rv2av behaves as number (not string) first");
+}
+
+# pp_rv2hv returns PL_sv_zero if count=0
+{
+    our %pkghash;
+    my $sc = scalar %pkghash;
+    $xobj = svref_2object(\$sc);
+    is($xobj->FLAGS & (SVf_IOK | SVf_POK), SVf_IOK, "PL_sv_zero from pp_rv2hv behaves as number (not string) first");
+}