Skip to content

Commit b4f00be

Browse files
committed
Cleanup generator closing code a bit
All code dealing with unfinished execution cleanup is now in a separate function (previously most of it was run even when execution was properly finished. Furthermore some code dealing with unclean shutdowns has been removed, which is no longer necessary, because we no longer try to clean up in this case.
1 parent 9589cae commit b4f00be

File tree

1 file changed

+73
-68
lines changed

1 file changed

+73
-68
lines changed

Zend/zend_generators.c

Lines changed: 73 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,73 @@ static zend_object_handlers zend_generator_handlers;
2929

3030
static zend_object_value zend_generator_create(zend_class_entry *class_type TSRMLS_DC);
3131

32+
static void zend_generator_cleanup_unfinished_execution(zend_generator *generator TSRMLS_DC) /* {{{ */
33+
{
34+
zend_execute_data *execute_data = generator->execute_data;
35+
zend_op_array *op_array = execute_data->op_array;
36+
37+
if (generator->send_target) {
38+
Z_DELREF_PP(generator->send_target);
39+
generator->send_target = NULL;
40+
}
41+
42+
/* Manually free loop variables, as execution couldn't reach their
43+
* SWITCH_FREE / FREE opcodes. */
44+
{
45+
/* -1 required because we want the last run opcode, not the
46+
* next to-be-run one. */
47+
zend_uint op_num = execute_data->opline - op_array->opcodes - 1;
48+
49+
int i;
50+
for (i = 0; i < op_array->last_brk_cont; ++i) {
51+
zend_brk_cont_element *brk_cont = op_array->brk_cont_array + i;
52+
53+
if (brk_cont->start < 0) {
54+
continue;
55+
} else if (brk_cont->start > op_num) {
56+
break;
57+
} else if (brk_cont->brk > op_num) {
58+
zend_op *brk_opline = op_array->opcodes + brk_cont->brk;
59+
60+
switch (brk_opline->opcode) {
61+
case ZEND_SWITCH_FREE:
62+
{
63+
temp_variable *var = EX_TMP_VAR(execute_data, brk_opline->op1.var);
64+
zval_ptr_dtor(&var->var.ptr);
65+
}
66+
break;
67+
case ZEND_FREE:
68+
{
69+
temp_variable *var = EX_TMP_VAR(execute_data, brk_opline->op1.var);
70+
zval_dtor(&var->tmp_var);
71+
}
72+
break;
73+
}
74+
}
75+
}
76+
}
77+
78+
/* Clear any backed up stack arguments */
79+
{
80+
void **ptr = generator->stack->top - 1;
81+
void **end = zend_vm_stack_frame_base(execute_data);
82+
83+
for (; ptr >= end; --ptr) {
84+
zval_ptr_dtor((zval **) ptr);
85+
}
86+
}
87+
88+
/* If yield was used as a function argument there may be active
89+
* method calls those objects need to be freed */
90+
while (execute_data->call >= execute_data->call_slots) {
91+
if (execute_data->call->object) {
92+
zval_ptr_dtor(&execute_data->call->object);
93+
}
94+
execute_data->call--;
95+
}
96+
}
97+
/* }}} */
98+
3299
ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution TSRMLS_DC) /* {{{ */
33100
{
34101
if (generator->value) {
@@ -55,76 +122,12 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
55122
zval_ptr_dtor(&execute_data->current_this);
56123
}
57124

58-
if (!finished_execution && generator->send_target) {
59-
Z_DELREF_PP(generator->send_target);
60-
generator->send_target = NULL;
61-
}
62-
63125
/* A fatal error / die occurred during the generator execution. Trying to clean
64126
* up the stack may not be safe in this case. */
65127
if (CG(unclean_shutdown)) {
66128
return;
67129
}
68130

69-
/* If the generator is closed before it can finish execution (reach
70-
* a return statement) we have to free loop variables manually, as
71-
* we don't know whether the SWITCH_FREE / FREE opcodes have run */
72-
if (!finished_execution) {
73-
/* -1 required because we want the last run opcode, not the
74-
* next to-be-run one. */
75-
zend_uint op_num = execute_data->opline - op_array->opcodes - 1;
76-
77-
int i;
78-
for (i = 0; i < op_array->last_brk_cont; ++i) {
79-
zend_brk_cont_element *brk_cont = op_array->brk_cont_array + i;
80-
81-
if (brk_cont->start < 0) {
82-
continue;
83-
} else if (brk_cont->start > op_num) {
84-
break;
85-
} else if (brk_cont->brk > op_num) {
86-
zend_op *brk_opline = op_array->opcodes + brk_cont->brk;
87-
88-
switch (brk_opline->opcode) {
89-
case ZEND_SWITCH_FREE:
90-
{
91-
temp_variable *var = EX_TMP_VAR(execute_data, brk_opline->op1.var);
92-
zval_ptr_dtor(&var->var.ptr);
93-
}
94-
break;
95-
case ZEND_FREE:
96-
{
97-
temp_variable *var = EX_TMP_VAR(execute_data, brk_opline->op1.var);
98-
zval_dtor(&var->tmp_var);
99-
}
100-
break;
101-
}
102-
}
103-
}
104-
}
105-
106-
/* Clear any backed up stack arguments */
107-
if (generator->stack != EG(argument_stack)) {
108-
void **ptr = generator->stack->top - 1;
109-
void **end = zend_vm_stack_frame_base(execute_data);
110-
111-
/* If the top stack element is the argument count, skip it */
112-
if (execute_data->function_state.arguments) {
113-
ptr--;
114-
}
115-
116-
for (; ptr >= end; --ptr) {
117-
zval_ptr_dtor((zval**) ptr);
118-
}
119-
}
120-
121-
while (execute_data->call >= execute_data->call_slots) {
122-
if (execute_data->call->object) {
123-
zval_ptr_dtor(&execute_data->call->object);
124-
}
125-
execute_data->call--;
126-
}
127-
128131
/* We have added an additional stack frame in prev_execute_data, so we
129132
* have to free it. It also contains the arguments passed to the
130133
* generator (for func_get_args) so those have to be freed too. */
@@ -143,17 +146,19 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
143146
}
144147
}
145148

149+
/* Some cleanups are only necessary if the generator was closued
150+
* before it could finish execution (reach a return statement). */
151+
if (!finished_execution) {
152+
zend_generator_cleanup_unfinished_execution(generator TSRMLS_CC);
153+
}
154+
146155
/* Free a clone of closure */
147156
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
148157
destroy_op_array(op_array TSRMLS_CC);
149158
efree(op_array);
150159
}
151160

152161
efree(generator->stack);
153-
if (generator->stack == EG(argument_stack)) {
154-
/* abnormal exit for running generator */
155-
EG(argument_stack) = NULL;
156-
}
157162
generator->execute_data = NULL;
158163
}
159164
}

0 commit comments

Comments
 (0)