In perl.git, the branch blead has been updated

<http://perl5.git.perl.org/perl.git/commitdiff/0d42e778cfa0ef9c7315b82e62a6c9fe0cb1cec5?hp=47d3b731f074752fe0862ffdf333cfd3935f793a>

- Log -----------------------------------------------------------------
commit 0d42e778cfa0ef9c7315b82e62a6c9fe0cb1cec5
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Thu Oct 16 17:44:56 2014 -0700

    [perl #122995] Hang with while(1) in a sub-list
    
    It was hanging at compile time in some cases, e.g.:
    
    sub foo { () = ($a, my $b, ($c, do { while(1) {} })) }
    
    The optimisation added in 5.20 to turn list+pushmark into null ops
    when they are in list context (effectively making ($a,($b,$c)) equiva-
    lent to ($a,$b,$c) with regard to which ops are executed) followed
    op_next pointers to find the last op that was a kid of the sublist.
    
    You can’t just follow op_next pointers like that, because it will loop
    at compile time on infinite loops like while (1){}.
    
    In this case, the last kid was being found in order to elide the erst-
    while list op from the op_next chain, but that is not necessary, since
    later OP_NULL handling takes care of it anyway.

M       op.c
M       t/op/list.t

commit 0298c7603f0a7ee6e46fc9ebc8283c40ee2f6ad4
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Thu Oct 16 16:18:59 2014 -0700

    Improve void varop optimisation
    
    After eliding the varop, the optimisation added in 5afbd733 repro-
    cesses the previous op if it is a nextstate op.  But it was doing this
    by setting the current op to the one before the nextstate, so that the
    o=o->op_next in the loop header would cause it to reprocess the next-
    state in the next iteration.  So, if that nextstate op were at the
    beginning of a subroutine, the optimisation would be skipped, and this
    would still execute two nextstate ops in a row:
    
    sub foo {
        our($a, $b);
        die;
    }
    
    So, instead, just use ‘goto’ to reprocess the op, and we can do it
    even if there is no op before the nextstate.

M       lib/B/Deparse.t
M       op.c
M       t/op/opt.t
-----------------------------------------------------------------------

Summary of changes:
 lib/B/Deparse.t |  2 +-
 op.c            | 17 +++++------------
 t/op/list.t     |  4 ++++
 t/op/opt.t      |  9 ++++++++-
 4 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/lib/B/Deparse.t b/lib/B/Deparse.t
index 52e0084..7a0c4d9 100644
--- a/lib/B/Deparse.t
+++ b/lib/B/Deparse.t
@@ -1470,9 +1470,9 @@ my($m7, undef, $m8) = (1, 2, 3);
 ($m7, undef, $m8) = (1, 2, 3);
 ####
 # 'our/local' works with padrange op
-no strict;
 our($z, @z);
 our $o1;
+no strict;
 local $o11;
 $o1 = 1;
 local $o1 = 1;
diff --git a/op.c b/op.c
index 9fd1d09..0501187 100644
--- a/op.c
+++ b/op.c
@@ -11658,19 +11658,11 @@ S_inplace_aassign(pTHX_ OP *o) {
 STATIC void
 S_null_listop_in_list_context(pTHX_ OP *o)
 {
-    OP *kid;
-
     PERL_ARGS_ASSERT_NULL_LISTOP_IN_LIST_CONTEXT;
 
     /* This is an OP_LIST in list (or void) context. That means we
      * can ditch the OP_LIST and the OP_PUSHMARK within. */
 
-    kid = cLISTOPo->op_first;
-    /* Find the end of the chain of OPs executed within the OP_LIST. */
-    while (kid->op_next != o)
-        kid = kid->op_next;
-
-    kid->op_next = o->op_next; /* patch list out of exec chain */
     op_null(cUNOPo->op_first); /* NULL the pushmark */
     op_null(o); /* NULL the list */
 }
@@ -11709,6 +11701,7 @@ Perl_rpeep(pTHX_ OP *o)
            break;
        }
 
+      redo:
        /* By default, this op has now been optimised. A couple of cases below
           clear this again.  */
        o->op_opt = 1;
@@ -12238,12 +12231,12 @@ Perl_rpeep(pTHX_ OP *o)
                oldop->op_next = o->op_next->op_next;
                /* Reprocess the previous op if it is a nextstate, to
                   allow double-nextstate optimisation.  */
-               if (oldop->op_type == OP_NEXTSTATE && oldoldop
-                && oldoldop->op_next == oldop) {
+               if (oldop->op_type == OP_NEXTSTATE) {
                    oldop->op_opt = 0;
-                   o = oldop = oldoldop;
+                   o = oldop;
+                   oldop = oldoldop;
                    oldoldop = NULL;
-                   continue;
+                   goto redo;
                }
                o = oldop;
            }
diff --git a/t/op/list.t b/t/op/list.t
index d14873f..3f42e6d 100644
--- a/t/op/list.t
+++ b/t/op/list.t
@@ -190,3 +190,7 @@ sub {
  )
 }
  ->(("${\''}")[0,0]);
+
+# [perl #122995] Hang when compiling while(1) in a sub-list
+# No ok() or is() necessary.
+sub foo { () = ($a, my $b, ($c, do { while(1) {} })) }
diff --git a/t/op/opt.t b/t/op/opt.t
index aa73fd7..50eff6d 100644
--- a/t/op/opt.t
+++ b/t/op/opt.t
@@ -9,7 +9,7 @@ BEGIN {
     @INC = '../lib';
 }
 
-plan 20;
+plan 21;
 
 use B qw 'svref_2object OPpASSIGN_COMMON';
 
@@ -62,6 +62,13 @@ is svref_2object(sub { 0;0;0;0;0;0;time 
})->START->next->name, 'time',
   'multiple nextstates become one';
 
 
+# rv2[ahs]v in void context
+
+is svref_2object(sub { our($foo,@fit,%far); our $bar; our($a,$b); time })
+    ->START->next->name, 'time',
+  'rv2[ahs]v in void context';
+
+
 # split to array
 
 for(['@pkgary'      , '@_'       ],

--
Perl5 Master Repository

Reply via email to