b2938d
From d7504df2a5d8985f2a8b04f17acff5e324572c39 Mon Sep 17 00:00:00 2001
b2938d
From: Richard Leach <richardleach@users.noreply.github.com>
b2938d
Date: Sun, 11 Oct 2020 12:26:27 +0100
b2938d
Subject: [PATCH] pp_split: no SWITCHSTACK in @ary = split(...) optimisation
b2938d
MIME-Version: 1.0
b2938d
Content-Type: text/plain; charset=UTF-8
b2938d
Content-Transfer-Encoding: 8bit
b2938d
b2938d
Petr Písař: 607eaf26a99ff76ab48877e68f1d7b005dc51575 ported to 5.32.0.
b2938d
b2938d
Signed-off-by: Petr Písař <ppisar@redhat.com>
b2938d
---
b2938d
 pp.c         | 89 +++++++++++++++++++++++++++++-----------------------
b2938d
 t/op/split.t | 23 +++++++++++++-
b2938d
 2 files changed, 72 insertions(+), 40 deletions(-)
b2938d
b2938d
diff --git a/pp.c b/pp.c
b2938d
index df80830..e4863d3 100644
b2938d
--- a/pp.c
b2938d
+++ b/pp.c
b2938d
@@ -5985,6 +5985,7 @@ PP(pp_split)
b2938d
 
b2938d
     /* handle @ary = split(...) optimisation */
b2938d
     if (PL_op->op_private & OPpSPLIT_ASSIGN) {
b2938d
+	realarray = 1;
b2938d
         if (!(PL_op->op_flags & OPf_STACKED)) {
b2938d
             if (PL_op->op_private & OPpSPLIT_LEX) {
b2938d
                 if (PL_op->op_private & OPpLVAL_INTRO)
b2938d
@@ -6007,26 +6008,10 @@ PP(pp_split)
b2938d
             oldsave = PL_savestack_ix;
b2938d
         }
b2938d
 
b2938d
-	realarray = 1;
b2938d
-	PUTBACK;
b2938d
-	av_extend(ary,0);
b2938d
-	(void)sv_2mortal(SvREFCNT_inc_simple_NN(sv));
b2938d
-	av_clear(ary);
b2938d
-	SPAGAIN;
b2938d
 	if ((mg = SvTIED_mg((const SV *)ary, PERL_MAGIC_tied))) {
b2938d
 	    PUSHMARK(SP);
b2938d
 	    XPUSHs(SvTIED_obj(MUTABLE_SV(ary), mg));
b2938d
-	}
b2938d
-	else {
b2938d
-	    if (!AvREAL(ary)) {
b2938d
-		I32 i;
b2938d
-		AvREAL_on(ary);
b2938d
-		AvREIFY_off(ary);
b2938d
-		for (i = AvFILLp(ary); i >= 0; i--)
b2938d
-		    AvARRAY(ary)[i] = &PL_sv_undef; /* don't free mere refs */
b2938d
-	    }
b2938d
-	    /* temporarily switch stacks */
b2938d
-	    SAVESWITCHSTACK(PL_curstack, ary);
b2938d
+	} else {
b2938d
 	    make_mortal = 0;
b2938d
 	}
b2938d
     }
b2938d
@@ -6358,29 +6343,56 @@ PP(pp_split)
b2938d
     LEAVE_SCOPE(oldsave); /* may undo an earlier SWITCHSTACK */
b2938d
     SPAGAIN;
b2938d
     if (realarray) {
b2938d
-	if (!mg) {
b2938d
-	    if (SvSMAGICAL(ary)) {
b2938d
-		PUTBACK;
b2938d
+        if (!mg) {
b2938d
+            PUTBACK;
b2938d
+            if(AvREAL(ary)) {
b2938d
+                if (av_count(ary) > 0)
b2938d
+                    av_clear(ary);
b2938d
+            } else {
b2938d
+                AvREAL_on(ary);
b2938d
+                AvREIFY_off(ary);
b2938d
+
b2938d
+                if (AvMAX(ary) > -1) {
b2938d
+                    /* don't free mere refs */
b2938d
+                    Zero(AvARRAY(ary), AvMAX(ary), SV*);
b2938d
+                }
b2938d
+            }
b2938d
+            if(AvMAX(ary) < iters)
b2938d
+                av_extend(ary,iters);
b2938d
+            SPAGAIN;
b2938d
+
b2938d
+            /* Need to copy the SV*s from the stack into ary */
b2938d
+            Copy(SP + 1 - iters, AvARRAY(ary), iters, SV*);
b2938d
+            AvFILLp(ary) = iters - 1;
b2938d
+
b2938d
+            if (SvSMAGICAL(ary)) {
b2938d
+                PUTBACK;
b2938d
 		mg_set(MUTABLE_SV(ary));
b2938d
 		SPAGAIN;
b2938d
-	    }
b2938d
-	    if (gimme == G_ARRAY) {
b2938d
-		EXTEND(SP, iters);
b2938d
-		Copy(AvARRAY(ary), SP + 1, iters, SV*);
b2938d
-		SP += iters;
b2938d
-		RETURN;
b2938d
-	    }
b2938d
+            }
b2938d
+
b2938d
+            if (gimme != G_ARRAY) {
b2938d
+                /* SP points to the final SV* pushed to the stack. But the SV*  */
b2938d
+                /* are not going to be used from the stack. Point SP to below   */
b2938d
+                /* the first of these SV*.                                      */
b2938d
+                SP -= iters;
b2938d
+                PUTBACK;
b2938d
+            }
b2938d
 	}
b2938d
 	else {
b2938d
-	    PUTBACK;
b2938d
-	    ENTER_with_name("call_PUSH");
b2938d
-	    call_sv(SV_CONST(PUSH),G_SCALAR|G_DISCARD|G_METHOD_NAMED);
b2938d
-	    LEAVE_with_name("call_PUSH");
b2938d
-	    SPAGAIN;
b2938d
+            PUTBACK;
b2938d
+            av_extend(ary,iters);
b2938d
+            av_clear(ary);
b2938d
+
b2938d
+            ENTER_with_name("call_PUSH");
b2938d
+            call_sv(SV_CONST(PUSH),G_SCALAR|G_DISCARD|G_METHOD_NAMED);
b2938d
+            LEAVE_with_name("call_PUSH");
b2938d
+            SPAGAIN;
b2938d
+
b2938d
 	    if (gimme == G_ARRAY) {
b2938d
 		SSize_t i;
b2938d
 		/* EXTEND should not be needed - we just popped them */
b2938d
-		EXTEND(SP, iters);
b2938d
+		EXTEND_SKIP(SP, iters);
b2938d
 		for (i=0; i < iters; i++) {
b2938d
 		    SV **svp = av_fetch(ary, i, FALSE);
b2938d
 		    PUSHs((svp) ? *svp : &PL_sv_undef);
b2938d
@@ -6389,13 +6401,12 @@ PP(pp_split)
b2938d
 	    }
b2938d
 	}
b2938d
     }
b2938d
-    else {
b2938d
-	if (gimme == G_ARRAY)
b2938d
-	    RETURN;
b2938d
-    }
b2938d
 
b2938d
-    GETTARGET;
b2938d
-    XPUSHi(iters);
b2938d
+    if (gimme != G_ARRAY) {
b2938d
+        GETTARGET;
b2938d
+        XPUSHi(iters);
b2938d
+     }
b2938d
+
b2938d
     RETURN;
b2938d
 }
b2938d
 
b2938d
diff --git a/t/op/split.t b/t/op/split.t
b2938d
index 14f9158..7f37512 100644
b2938d
--- a/t/op/split.t
b2938d
+++ b/t/op/split.t
b2938d
@@ -7,7 +7,7 @@ BEGIN {
b2938d
     set_up_inc('../lib');
b2938d
 }
b2938d
 
b2938d
-plan tests => 176;
b2938d
+plan tests => 182;
b2938d
 
b2938d
 $FS = ':';
b2938d
 
b2938d
@@ -648,6 +648,19 @@ is "@a", '1 2 3', 'assignment to split-to-array (stacked)';
b2938d
     is (+@a, 0, "empty utf8 string");
b2938d
 }
b2938d
 
b2938d
+# correct stack adjustments (gh#18232)
b2938d
+{
b2938d
+    sub foo { return @_ }
b2938d
+    my @a = foo(1, scalar split " ", "a b");
b2938d
+    is(join('', @a), "12", "Scalar split to a sub parameter");
b2938d
+}
b2938d
+
b2938d
+{
b2938d
+    sub foo { return @_ }
b2938d
+    my @a = foo(1, scalar(@x = split " ", "a b"));
b2938d
+    is(join('', @a), "12", "Split to @x then use scalar result as a sub parameter");
b2938d
+}
b2938d
+
b2938d
 fresh_perl_is(<<'CODE', '', {}, "scalar split stack overflow");
b2938d
 map{int"";split//.0>60for"0000000000000000"}split// for"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
b2938d
 CODE
b2938d
@@ -667,3 +680,11 @@ CODE
b2938d
         ok(eq_array(\@result,['a','b']), "Resulting in ('a','b')");
b2938d
     }
b2938d
 }
b2938d
+
b2938d
+# check that the (@ary = split) optimisation survives @ary being modified
b2938d
+
b2938d
+fresh_perl_is('my @ary; @ary = split(/\w(?{ @ary[1000] = 1 })/, "abc");',
b2938d
+        '',{},'(@ary = split ...) survives @ary being Renew()ed');
b2938d
+fresh_perl_is('my @ary; @ary = split(/\w(?{ undef @ary })/, "abc");',
b2938d
+        '',{},'(@ary = split ...) survives an (undef @ary)');
b2938d
+
b2938d
-- 
b2938d
2.25.4
b2938d