]> granicus.if.org Git - php/commitdiff
Restored proper generators behaviour in conjunction with "finally". (Nikita)
authorDmitry Stogov <dmitry@zend.com>
Wed, 12 Dec 2012 13:47:55 +0000 (17:47 +0400)
committerDmitry Stogov <dmitry@zend.com>
Wed, 12 Dec 2012 13:47:55 +0000 (17:47 +0400)
13 files changed:
Zend/tests/generators/finally/finally_ran_on_close.phpt [moved from Zend/tests/generators/finally_ran_on_close.phpt with 100% similarity]
Zend/tests/generators/finally/return_return.phpt [moved from Zend/tests/generators/finally_with_return.phpt with 92% similarity]
Zend/tests/generators/finally/return_yield.phpt [new file with mode: 0644]
Zend/tests/generators/finally/throw_yield.phpt [new file with mode: 0644]
Zend/tests/generators/finally/yield_return.phpt [new file with mode: 0644]
Zend/tests/generators/finally/yield_throw.phpt [new file with mode: 0644]
Zend/tests/generators/finally/yield_yield.phpt [new file with mode: 0644]
Zend/tests/generators/finally_uninterrupted.phpt [deleted file]
Zend/zend_generators.c
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.h

similarity index 92%
rename from Zend/tests/generators/finally_with_return.phpt
rename to Zend/tests/generators/finally/return_return.phpt
index b26a49f32fa3b0bb29be6efff81451ba6b827e4a..02e2739de7ec5b77d51d334a80a6e3ae84412e13 100644 (file)
@@ -1,5 +1,5 @@
 --TEST--
-Use of finally in generator with return
+try { return } finally { return } in generator
 --FILE--
 <?php
 
diff --git a/Zend/tests/generators/finally/return_yield.phpt b/Zend/tests/generators/finally/return_yield.phpt
new file mode 100644 (file)
index 0000000..c4f3485
--- /dev/null
@@ -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 (file)
index 0000000..2013c3e
--- /dev/null
@@ -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 (file)
index 0000000..e3e1bec
--- /dev/null
@@ -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 (file)
index 0000000..0ead450
--- /dev/null
@@ -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 (file)
index 0000000..76610ef
--- /dev/null
@@ -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_uninterrupted.phpt b/Zend/tests/generators/finally_uninterrupted.phpt
deleted file mode 100644 (file)
index 64c9438..0000000
+++ /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
index 1844be86d5a5e622531ea14c461857e68d0f1dcc..2ee2fb96813516606b2f2f7adec788f1b39601e3 100644 (file)
@@ -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++;
index 2fd8f529ef1f8909e20404817720529eb09820ff..3fb9453314a77630961a0789c6c19a163eb4891f 100644 (file)
@@ -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:
index c5d1748cd2407095badfeb8ab3b14cc22488a896..939dc1d066202be374ca84f6cf2a0869341af968 100644 (file)
@@ -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
index 7c11016c064989fc62c5c1b0caaf5d3dc3cb5372..dd77aa5f8ef1f3a0e2f684c126b1b1bdbf0782e1 100644 (file)
@@ -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,
index fcf7960b8e4134105a2b103f13bc72003c606396..52f6cde59e71fc5a1c6a263a4f79c1e0c2213ca7 100644 (file)
 #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