Created
January 22, 2016 14:10
-
-
Save dstogov/285024375d15cacf2a9b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c | |
index fffcb9c..382a757 100644 | |
--- a/Zend/zend_execute.c | |
+++ b/Zend/zend_execute.c | |
@@ -2426,59 +2426,12 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da | |
ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data *call, zend_op_array *op_array, zval *return_value) /* {{{ */ | |
{ | |
- /* | |
- * Normally the execute_data is allocated on the VM stack (because it does | |
- * not actually do any allocation and thus is faster). For generators | |
- * though this behavior would be suboptimal, because the (rather large) | |
- * structure would have to be copied back and forth every time execution is | |
- * suspended or resumed. That's why for generators the execution context | |
- * is allocated using a separate VM stack, thus allowing to save and | |
- * restore it simply by replacing a pointer. | |
- */ | |
- zend_execute_data *execute_data; | |
- uint32_t num_args = ZEND_CALL_NUM_ARGS(call); | |
- size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval); | |
- uint32_t call_info; | |
- | |
- EG(vm_stack) = zend_vm_stack_new_page( | |
- EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE(1)) ? | |
- ZEND_VM_STACK_PAGE_SIZE(1) : | |
- ZEND_VM_STACK_PAGE_ALIGNED_SIZE(1, stack_size), | |
- NULL); | |
- EG(vm_stack_top) = EG(vm_stack)->top; | |
- EG(vm_stack_end) = EG(vm_stack)->end; | |
- | |
- call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS)); | |
- if (Z_OBJ(call->This)) { | |
- call_info |= ZEND_CALL_RELEASE_THIS; | |
- } | |
- execute_data = zend_vm_stack_push_call_frame( | |
- call_info, | |
- (zend_function*)op_array, | |
- num_args, | |
- call->called_scope, | |
- Z_OBJ(call->This)); | |
- EX(prev_execute_data) = NULL; | |
- EX_NUM_ARGS() = num_args; | |
- | |
- /* copy arguments */ | |
- if (num_args > 0) { | |
- zval *arg_src = ZEND_CALL_ARG(call, 1); | |
- zval *arg_dst = ZEND_CALL_ARG(execute_data, 1); | |
- zval *end = arg_src + num_args; | |
- | |
- do { | |
- ZVAL_COPY_VALUE(arg_dst, arg_src); | |
- arg_src++; | |
- arg_dst++; | |
- } while (arg_src != end); | |
- } | |
- | |
- EX(symbol_table) = NULL; | |
+ call->prev_execute_data = NULL; | |
+ call->symbol_table = NULL; | |
- i_init_func_execute_data(execute_data, op_array, return_value, 1); | |
+ i_init_func_execute_data(call, op_array, return_value, 1); | |
- return execute_data; | |
+ return call; | |
} | |
/* }}} */ | |
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h | |
index 00c651f..b869cc3 100644 | |
--- a/Zend/zend_execute.h | |
+++ b/Zend/zend_execute.h | |
@@ -173,7 +173,10 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(ui | |
ZEND_ASSERT_VM_STACK_GLOBAL; | |
- if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) { | |
+ if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_GENERATOR)) { | |
+ call = (zend_execute_data*)emalloc(used_stack); | |
+ ZEND_SET_CALL_INFO(call, call_info | ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED); | |
+ } else if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) { | |
call = (zend_execute_data*)zend_vm_stack_extend(used_stack); | |
ZEND_SET_CALL_INFO(call, call_info | ZEND_CALL_ALLOCATED); | |
} else { | |
@@ -259,6 +262,13 @@ static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_in | |
ZEND_ASSERT_VM_STACK_GLOBAL; | |
if (UNEXPECTED(call_info & ZEND_CALL_ALLOCATED)) { | |
+ if (!call->func) { | |
+ /* Generator with unused return value */ | |
+ efree(call); | |
+ return; | |
+ } else if (call->func->common.fn_flags & ZEND_ACC_GENERATOR) { | |
+ return; | |
+ } | |
zend_vm_stack p = EG(vm_stack); | |
zend_vm_stack prev = p->prev; | |
@@ -267,7 +277,6 @@ static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_in | |
EG(vm_stack_end) = prev->end; | |
EG(vm_stack) = prev; | |
efree(p); | |
- | |
} else { | |
EG(vm_stack_top) = (zval*)call; | |
} | |
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c | |
index 4861e45..7d45059 100644 | |
--- a/Zend/zend_generators.c | |
+++ b/Zend/zend_generators.c | |
@@ -44,21 +44,7 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato | |
/* -1 required because we want the last run opcode, not the next to-be-run one. */ | |
uint32_t op_num = execute_data->opline - execute_data->func->op_array.opcodes - 1; | |
- /* There may be calls to zend_vm_stack_free_call_frame(), which modifies the VM stack | |
- * globals, so need to load/restore those. */ | |
- zend_vm_stack original_stack = EG(vm_stack); | |
- original_stack->top = EG(vm_stack_top); | |
- EG(vm_stack_top) = generator->stack->top; | |
- EG(vm_stack_end) = generator->stack->end; | |
- EG(vm_stack) = generator->stack; | |
- | |
zend_cleanup_unfinished_execution(execute_data, op_num, 0); | |
- | |
- generator->stack = EG(vm_stack); | |
- generator->stack->top = EG(vm_stack_top); | |
- EG(vm_stack_top) = original_stack->top; | |
- EG(vm_stack_end) = original_stack->end; | |
- EG(vm_stack) = original_stack; | |
} | |
} | |
/* }}} */ | |
@@ -103,7 +89,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished | |
OBJ_RELEASE((zend_object *) EX(func)->common.prototype); | |
} | |
- efree(generator->stack); | |
+ efree(generator->execute_data); | |
generator->execute_data = NULL; | |
} | |
} | |
@@ -223,14 +209,10 @@ ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array | |
{ | |
zend_generator *generator; | |
zend_execute_data *current_execute_data; | |
- zend_execute_data *execute_data; | |
- zend_vm_stack current_stack = EG(vm_stack); | |
- | |
- current_stack->top = EG(vm_stack_top); | |
/* Create new execution context. We have to back up and restore EG(current_execute_data) here. */ | |
current_execute_data = EG(current_execute_data); | |
- execute_data = zend_create_generator_execute_data(call, op_array, return_value); | |
+ zend_create_generator_execute_data(call, op_array, return_value); | |
EG(current_execute_data) = current_execute_data; | |
object_init_ex(return_value, zend_ce_generator); | |
@@ -241,15 +223,10 @@ ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array | |
/* Save execution context in generator object. */ | |
generator = (zend_generator *) Z_OBJ_P(return_value); | |
- generator->execute_data = execute_data; | |
- generator->stack = EG(vm_stack); | |
- generator->stack->top = EG(vm_stack_top); | |
- EG(vm_stack_top) = current_stack->top; | |
- EG(vm_stack_end) = current_stack->end; | |
- EG(vm_stack) = current_stack; | |
+ generator->execute_data = call; | |
/* EX(return_value) keeps pointer to zend_object (not a real zval) */ | |
- execute_data->return_value = (zval*)generator; | |
+ call->return_value = (zval*)generator; | |
memset(&generator->execute_fake, 0, sizeof(zend_execute_data)); | |
Z_OBJ(generator->execute_fake.This) = (zend_object *) generator; | |
@@ -657,15 +634,10 @@ try_again: | |
/* Backup executor globals */ | |
zend_execute_data *original_execute_data = EG(current_execute_data); | |
zend_class_entry *original_scope = EG(scope); | |
- zend_vm_stack original_stack = EG(vm_stack); | |
- original_stack->top = EG(vm_stack_top); | |
/* Set executor globals */ | |
EG(current_execute_data) = generator->execute_data; | |
EG(scope) = generator->execute_data->func->common.scope; | |
- EG(vm_stack_top) = generator->stack->top; | |
- EG(vm_stack_end) = generator->stack->end; | |
- EG(vm_stack) = generator->stack; | |
/* We want the backtrace to look as if the generator function was | |
* called from whatever method we are current running (e.g. next()). | |
@@ -684,18 +656,9 @@ try_again: | |
zend_execute_ex(generator->execute_data); | |
generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING; | |
- /* Unlink generator call_frame from the caller and backup vm_stack_top */ | |
- if (EXPECTED(generator->execute_data)) { | |
- generator->stack = EG(vm_stack); | |
- generator->stack->top = EG(vm_stack_top); | |
- } | |
- | |
/* Restore executor globals */ | |
EG(current_execute_data) = original_execute_data; | |
EG(scope) = original_scope; | |
- EG(vm_stack_top) = original_stack->top; | |
- EG(vm_stack_end) = original_stack->end; | |
- EG(vm_stack) = original_stack; | |
/* If an exception was thrown in the generator we have to internally | |
* rethrow it in the parent scope. | |
diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h | |
index 26ee646..2fc71f5 100644 | |
--- a/Zend/zend_generators.h | |
+++ b/Zend/zend_generators.h | |
@@ -62,9 +62,6 @@ struct _zend_generator { | |
/* The suspended execution context. */ | |
zend_execute_data *execute_data; | |
- /* The separate stack used by generator */ | |
- zend_vm_stack stack; | |
- | |
/* Current value */ | |
zval value; | |
/* Current key */ | |
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h | |
index 86ced99..c90c2bb 100644 | |
--- a/Zend/zend_vm_def.h | |
+++ b/Zend/zend_vm_def.h | |
@@ -3681,6 +3681,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) | |
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { | |
OBJ_RELEASE((zend_object*)fbc->op_array.prototype); | |
} | |
+ call->func = NULL; | |
zend_vm_stack_free_args(call); | |
} | |
} else { | |
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h | |
index 080c799..6ba1c49 100644 | |
--- a/Zend/zend_vm_execute.h | |
+++ b/Zend/zend_vm_execute.h | |
@@ -779,6 +779,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC | |
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { | |
OBJ_RELEASE((zend_object*)fbc->op_array.prototype); | |
} | |
+ call->func = NULL; | |
zend_vm_stack_free_args(call); | |
} | |
} else { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment