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