Commit:    9c96fe52d95a6674f90dc8efd4e2c054818c96ad
Author:    Dmitry Stogov <dmi...@zend.com>         Wed, 12 Dec 2012 17:47:55 
+0400
Parents:   4d8d5d83fce83c32a04cd8d8cf50d909ab101f38
Branches:  PHP-5.5 master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=9c96fe52d95a6674f90dc8efd4e2c054818c96ad

Log:
Restored proper generators behaviour in conjunction with "finally". (Nikita)

Changed paths:
  A  Zend/tests/generators/finally/finally_ran_on_close.phpt
  A  Zend/tests/generators/finally/return_return.phpt
  A  Zend/tests/generators/finally/return_yield.phpt
  A  Zend/tests/generators/finally/throw_yield.phpt
  A  Zend/tests/generators/finally/yield_return.phpt
  A  Zend/tests/generators/finally/yield_throw.phpt
  A  Zend/tests/generators/finally/yield_yield.phpt
  D  Zend/tests/generators/finally_ran_on_close.phpt
  D  Zend/tests/generators/finally_uninterrupted.phpt
  D  Zend/tests/generators/finally_with_return.phpt
  M  Zend/zend_generators.c
  M  Zend/zend_opcode.c
  M  Zend/zend_vm_def.h
  M  Zend/zend_vm_execute.h
  M  Zend/zend_vm_opcodes.h

diff --git a/Zend/tests/generators/finally/finally_ran_on_close.phpt 
b/Zend/tests/generators/finally/finally_ran_on_close.phpt
new file mode 100644
index 0000000..04a0561
--- /dev/null
+++ b/Zend/tests/generators/finally/finally_ran_on_close.phpt
@@ -0,0 +1,30 @@
+--TEST--
+finally is run even if a generator is closed mid-execution
+--FILE--
+<?php
+
+function gen() {
+    try {
+        try {
+            echo "before yield\n";
+            yield;
+            echo "after yield\n";
+        } finally {
+            echo "finally run\n";
+        }
+        echo "code after finally\n";
+    } finally {
+        echo "second finally run\n";
+    }
+    echo "code after second finally\n";
+}
+
+$gen = gen();
+$gen->rewind();
+unset($gen);
+
+?>
+--EXPECT--
+before yield
+finally run
+second finally run
diff --git a/Zend/tests/generators/finally/return_return.phpt 
b/Zend/tests/generators/finally/return_return.phpt
new file mode 100644
index 0000000..02e2739
--- /dev/null
+++ b/Zend/tests/generators/finally/return_return.phpt
@@ -0,0 +1,33 @@
+--TEST--
+try { return } finally { return } in generator
+--FILE--
+<?php
+
+function gen() {
+    try {
+        try {
+            echo "before return\n";
+            return;
+            echo "after return\n";
+        } finally {
+            echo "before return in inner finally\n";
+            return;
+            echo "after return in inner finally\n";
+        }
+    } finally {
+        echo "outer finally run\n";
+    }
+
+    echo "code after finally\n";
+
+    yield; // force generator
+}
+
+$gen = gen();
+$gen->rewind(); // force run
+
+?>
+--EXPECTF--
+before return
+before return in inner finally
+outer finally run
diff --git a/Zend/tests/generators/finally/return_yield.phpt 
b/Zend/tests/generators/finally/return_yield.phpt
new file mode 100644
index 0000000..c4f3485
--- /dev/null
+++ b/Zend/tests/generators/finally/return_yield.phpt
@@ -0,0 +1,18 @@
+--TEST--
+try { return } finally { yield }
+--FILE--
+<?php
+function foo($f, $t) {
+    for ($i = $f; $i <= $t; $i++) {
+        try {
+            return;
+        } finally {
+            yield $i;
+        }
+    }
+}
+foreach (foo(1, 5) as $x) {
+    echo $x, "\n";
+}
+--EXPECT--
+1
diff --git a/Zend/tests/generators/finally/throw_yield.phpt 
b/Zend/tests/generators/finally/throw_yield.phpt
new file mode 100644
index 0000000..2013c3e
--- /dev/null
+++ b/Zend/tests/generators/finally/throw_yield.phpt
@@ -0,0 +1,24 @@
+--TEST--
+try { throw } finally { yield }
+--FILE--
+<?php
+function foo($f, $t) {
+    for ($i = $f; $i <= $t; $i++) {
+        try {
+            throw new Exception;
+        } finally {
+            yield $i;
+        }
+    }
+}
+foreach (foo(1, 5) as $x) {
+    echo $x, "\n";
+}
+--EXPECTF--
+1
+
+Fatal error: Uncaught exception 'Exception' in %s:%d
+Stack trace:
+#0 %s(%d): foo(1, 5)
+#1 {main}
+  thrown in %s on line %d
diff --git a/Zend/tests/generators/finally/yield_return.phpt 
b/Zend/tests/generators/finally/yield_return.phpt
new file mode 100644
index 0000000..e3e1bec
--- /dev/null
+++ b/Zend/tests/generators/finally/yield_return.phpt
@@ -0,0 +1,18 @@
+--TEST--
+try { yield } finally { return }
+--FILE--
+<?php
+function foo($f, $t) {
+    for ($i = $f; $i <= $t; $i++) {
+        try {
+            yield $i;
+        } finally {
+            return;
+        }
+    }
+}
+foreach (foo(1, 5) as $x) {
+    echo $x, "\n";
+}
+--EXPECT--
+1
diff --git a/Zend/tests/generators/finally/yield_throw.phpt 
b/Zend/tests/generators/finally/yield_throw.phpt
new file mode 100644
index 0000000..0ead450
--- /dev/null
+++ b/Zend/tests/generators/finally/yield_throw.phpt
@@ -0,0 +1,24 @@
+--TEST--
+try { yield } finally { throw }
+--FILE--
+<?php
+function foo($f, $t) {
+    for ($i = $f; $i <= $t; $i++) {
+        try {
+            yield $i;
+        } finally {
+            throw new Exception;
+        }
+    }
+}
+foreach (foo(1, 5) as $x) {
+    echo $x, "\n";
+}
+--EXPECTF--
+1
+
+Fatal error: Uncaught exception 'Exception' in %s:%d
+Stack trace:
+#0 %s(%d): foo(1, 5)
+#1 {main}
+  thrown in %s on line %d
diff --git a/Zend/tests/generators/finally/yield_yield.phpt 
b/Zend/tests/generators/finally/yield_yield.phpt
new file mode 100644
index 0000000..76610ef
--- /dev/null
+++ b/Zend/tests/generators/finally/yield_yield.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Try { yield } finally { yield }
+--FILE--
+<?php
+
+function foo() {
+    try {
+        echo "1";
+        yield "2";
+        echo "3";
+    } finally {
+        echo "4";
+        yield "5";
+        echo "6";
+    }
+    echo "7";
+}
+foreach (foo() as $x) {
+    echo $x;
+}
+--EXPECT--
+1234567
diff --git a/Zend/tests/generators/finally_ran_on_close.phpt 
b/Zend/tests/generators/finally_ran_on_close.phpt
deleted file mode 100644
index 04a0561..0000000
--- a/Zend/tests/generators/finally_ran_on_close.phpt
+++ /dev/null
@@ -1,30 +0,0 @@
---TEST--
-finally is run even if a generator is closed mid-execution
---FILE--
-<?php
-
-function gen() {
-    try {
-        try {
-            echo "before yield\n";
-            yield;
-            echo "after yield\n";
-        } finally {
-            echo "finally run\n";
-        }
-        echo "code after finally\n";
-    } finally {
-        echo "second finally run\n";
-    }
-    echo "code after second finally\n";
-}
-
-$gen = gen();
-$gen->rewind();
-unset($gen);
-
-?>
---EXPECT--
-before yield
-finally run
-second finally run
diff --git a/Zend/tests/generators/finally_uninterrupted.phpt 
b/Zend/tests/generators/finally_uninterrupted.phpt
deleted file mode 100644
index 64c9438..0000000
--- a/Zend/tests/generators/finally_uninterrupted.phpt
+++ /dev/null
@@ -1,28 +0,0 @@
---TEST--
-Use of finally in generator without interrupt
---FILE--
-<?php
-
-function gen() {
-    try {
-        throw new Exception;
-    } finally {
-        echo "finally run\n";
-    }
-
-    yield; // force generator
-}
-
-$gen = gen();
-$gen->rewind(); // force run
-
-?>
---EXPECTF--
-finally run
-
-Fatal error: Uncaught exception 'Exception' in %s:%d
-Stack trace:
-#0 [internal function]: gen()
-#1 %s(%d): Generator->rewind()
-#2 {main}
-  thrown in %s on line %d
diff --git a/Zend/tests/generators/finally_with_return.phpt 
b/Zend/tests/generators/finally_with_return.phpt
deleted file mode 100644
index b26a49f..0000000
--- a/Zend/tests/generators/finally_with_return.phpt
+++ /dev/null
@@ -1,33 +0,0 @@
---TEST--
-Use of finally in generator with return
---FILE--
-<?php
-
-function gen() {
-    try {
-        try {
-            echo "before return\n";
-            return;
-            echo "after return\n";
-        } finally {
-            echo "before return in inner finally\n";
-            return;
-            echo "after return in inner finally\n";
-        }
-    } finally {
-        echo "outer finally run\n";
-    }
-
-    echo "code after finally\n";
-
-    yield; // force generator
-}
-
-$gen = gen();
-$gen->rewind(); // force run
-
-?>
---EXPECTF--
-before return
-before return in inner finally
-outer finally run
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 1844be8..2ee2fb9 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -32,7 +32,41 @@ ZEND_API void zend_generator_close(zend_generator 
*generator, zend_bool finished
        if (generator->execute_data) {
                zend_execute_data *execute_data = generator->execute_data;
                zend_op_array *op_array = execute_data->op_array;
-               void **stack_frame;
+
+               if (!finished_execution) {
+                       if (op_array->has_finally_block) {
+                               /* -1 required because we want the last run 
opcode, not the
+                                * next to-be-run one. */
+                               zend_uint op_num = execute_data->opline - 
op_array->opcodes - 1;
+                               zend_uint finally_op_num = 0;
+
+                               /* Find next finally block */
+                               int i;
+                               for (i = 0; i < op_array->last_try_catch; i++) {
+                                       zend_try_catch_element *try_catch = 
&op_array->try_catch_array[i];
+
+                                       if (op_num < try_catch->try_op) {
+                                               break;
+                                       }
+
+                                       if (op_num < try_catch->finally_op) {
+                                               finally_op_num = 
try_catch->finally_op;
+                                       }
+                               }
+
+                               /* If a finally block was found we jump 
directly to it and
+                                * resume the generator. Furthermore we abort 
this close call
+                                * because the generator will already be closed 
somewhere in
+                                * the resume. */
+                               if (finally_op_num) {
+                                       execute_data->opline = 
&op_array->opcodes[finally_op_num];
+                                       execute_data->fast_ret = NULL;
+                                       generator->flags |= 
ZEND_GENERATOR_FORCED_CLOSE;
+                                       zend_generator_resume(generator 
TSRMLS_CC);
+                                       return;
+                               }
+                       }
+               }
 
                if (!execute_data->symbol_table) {
                        zend_free_compiled_variables(execute_data);
@@ -83,7 +117,7 @@ ZEND_API void zend_generator_close(zend_generator 
*generator, zend_bool finished
 
                /* Clear any backed up stack arguments */
                if (generator->stack != EG(argument_stack)) {
-                       stack_frame = zend_vm_stack_frame_base(execute_data);
+                       void **stack_frame = 
zend_vm_stack_frame_base(execute_data);
                        while (generator->stack->top != stack_frame) {
                                zval_ptr_dtor((zval**)stack_frame);
                                stack_frame++;
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index 2fd8f52..3fb9453 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -542,17 +542,9 @@ static void zend_resolve_finally_call(zend_op_array 
*op_array, zend_uint op_num,
                     dst_num > op_array->try_catch_array[i].finally_end)) {
                        /* we have a jump out of try block that needs executing 
finally */
 
-                       /* generate a FAST_CALL to finaly block */
+                       /* generate a FAST_CALL to finally block */
                    start_op = get_next_op_number(op_array);
 
-                       if (op_array->opcodes[op_num].opcode == ZEND_YIELD) {
-                               /* Disable yield in finally block */
-                               opline = get_next_op(op_array TSRMLS_CC);
-                               opline->opcode = ZEND_GENERATOR_FLAG;
-                               opline->extended_value = 1;
-                               SET_UNUSED(opline->op1);
-                               SET_UNUSED(opline->op2);
-                       }
                        opline = get_next_op(op_array TSRMLS_CC);
                        opline->opcode = ZEND_FAST_CALL;
                        SET_UNUSED(opline->op1);
@@ -563,7 +555,7 @@ static void zend_resolve_finally_call(zend_op_array 
*op_array, zend_uint op_num,
                                opline->op2.opline_num = 
op_array->try_catch_array[i].catch_op;
                        }
 
-                       /* generate a sequence of FAST_CALL to upward finaly 
block */
+                       /* generate a sequence of FAST_CALL to upward finally 
block */
                        while (i > 0) {
                                i--;
                                if (op_array->try_catch_array[i].finally_op &&
@@ -579,14 +571,6 @@ static void zend_resolve_finally_call(zend_op_array 
*op_array, zend_uint op_num,
                                        opline->op1.opline_num = 
op_array->try_catch_array[i].finally_op;
                                }
                        }
-                       if (op_array->opcodes[op_num].opcode == ZEND_YIELD) {
-                               /* Re-enable yield */
-                               opline = get_next_op(op_array TSRMLS_CC);
-                               opline->opcode = ZEND_GENERATOR_FLAG;
-                               opline->extended_value = 0;
-                               SET_UNUSED(opline->op1);
-                               SET_UNUSED(opline->op2);
-                       }
 
                        /* Finish the sequence with original opcode */
                        opline = get_next_op(op_array TSRMLS_CC);
@@ -642,7 +626,7 @@ static void zend_resolve_finally_calls(zend_op_array 
*op_array TSRMLS_DC)
                switch (opline->opcode) {
                        case ZEND_RETURN:
                        case ZEND_RETURN_BY_REF:
-                       case ZEND_YIELD:
+                       case ZEND_GENERATOR_RETURN:
                                zend_resolve_finally_call(op_array, i, 
(zend_uint)-1 TSRMLS_CC);
                                break;
                        case ZEND_BRK:
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index c5d1748..939dc1d 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5252,19 +5252,6 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED)
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HANDLER(159, ZEND_GENERATOR_FLAG, ANY, ANY)
-{
-       USE_OPLINE
-       zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
-
-       if (opline->extended_value) {
-               generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
-       } else {
-               generator->flags &= ~ZEND_GENERATOR_FORCED_CLOSE;
-       }
-       ZEND_VM_NEXT_OPCODE();
-}
-
 ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, 
CONST|TMP|VAR|CV|UNUSED)
 {
        USE_OPLINE
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 7c11016..dd77aa5 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1134,19 +1134,6 @@ static int ZEND_FASTCALL  
ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        }
 }
 
-static int ZEND_FASTCALL  
ZEND_GENERATOR_FLAG_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
-       USE_OPLINE
-       zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
-
-       if (opline->extended_value) {
-               generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
-       } else {
-               generator->flags &= ~ZEND_GENERATOR_FORCED_CLOSE;
-       }
-       ZEND_VM_NEXT_OPCODE();
-}
-
 static int ZEND_FASTCALL  ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -44840,31 +44827,31 @@ void zend_init_opcodes_handlers(void)
        ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
        ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
        ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
-       ZEND_GENERATOR_FLAG_SPEC_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
        ZEND_YIELD_SPEC_CONST_CONST_HANDLER,
        ZEND_YIELD_SPEC_CONST_TMP_HANDLER,
        ZEND_YIELD_SPEC_CONST_VAR_HANDLER,
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index fcf7960..52f6cde 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -159,7 +159,6 @@
 #define ZEND_SEPARATE                        156
 #define ZEND_QM_ASSIGN_VAR                   157
 #define ZEND_JMP_SET_VAR                     158
-#define ZEND_GENERATOR_FLAG                  159
 #define ZEND_YIELD                           160
 #define ZEND_GENERATOR_RETURN                161
 #define ZEND_FAST_CALL                       162
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to