Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/UPGRADING b/UPGRADING
- index 18ab6bf..953d2db 100755
- --- a/UPGRADING
- +++ b/UPGRADING
- @@ -28,6 +28,27 @@ PHP 5.5 UPGRADE NOTES
- zend_logo_guid() have been removed
- - Removal of Logo GUIDs
- +- extensions can't override zend_execute() any more, they should override
- + zend_execute_ex() instead. The EG(current_execute_data) is already
- + initialized in zend_execute_ex(), so for compatibility extensions
- + may need to use EG(current_execute_data)->prev_execute_data instead.
- +- removed EG(arg_types_stack), EX(fbc), EX(called_scope), EX(current_object)
- +- added op_array->nested_calls. It's calculated at compile time.
- +- added EX(call_slots). It is an array to store informatin about syntaticaly
- + nested calls (e.g. foo(bar())). It's preallocated together with execute_data.
- +- added EX(call) - pointer to a current calling function. Actually an
- + element of EX(call_slots)
- +- opcodes INIT_METHOD_CALL, ZEND_INIT_STATIC_METHOD_CALL,
- + ZEND_INIT_FCALL_BY_NAME, ZEND_INIT_NS_FCALL_BY_NAME use result.num as
- + an index in EX(call_slots)
- +- opcode ZEND_NEW uses extended_vallue as an index in EX(call_slots)
- +- opcoes ZEND_DO_FCALL and ZEND_DO_FCALL_BY_NAME use op2.num as
- + an index in EX(call_slots)
- +- added op_array->used_stack. It's calcualated at compile time and the
- + corresponding stack space is preallocated together with execute_data.
- + ZEND_SEND* and ZEND_DO_FCALL* don't need to check for stack overflow
- + anymore.
- +
- ========================================
- 2. New Features
- ========================================
- diff --git a/Zend/zend.c b/Zend/zend.c
- index 9ab879a..fc6aed0 100644
- --- a/Zend/zend.c
- +++ b/Zend/zend.c
- @@ -683,11 +683,11 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions TS
- #if HAVE_DTRACE
- /* build with dtrace support */
- zend_compile_file = dtrace_compile_file;
- - zend_execute = dtrace_execute;
- + zend_execute_ex = dtrace_execute_ex;
- zend_execute_internal = dtrace_execute_internal;
- #else
- zend_compile_file = compile_file;
- - zend_execute = execute;
- + zend_execute_ex = execute_ex;
- zend_execute_internal = NULL;
- #endif /* HAVE_SYS_SDT_H */
- zend_compile_string = compile_string;
- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
- index de77068..e768996 100644
- --- a/Zend/zend_compile.c
- +++ b/Zend/zend_compile.c
- @@ -179,6 +179,8 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */
- CG(context).literals_size = 0;
- CG(context).current_brk_cont = -1;
- CG(context).backpatch_count = 0;
- + CG(context).nested_calls = 0;
- + CG(context).used_stack = 0;
- CG(context).labels = NULL;
- }
- /* }}} */
- @@ -1950,6 +1952,9 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
- function_name->u.constant.value.str.val = lcname;
- zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
- + if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
- + CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
- + }
- zend_do_extended_fcall_begin(TSRMLS_C);
- return 0;
- }
- @@ -1988,11 +1993,13 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
- GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
- }
- last_op->opcode = ZEND_INIT_METHOD_CALL;
- - SET_UNUSED(last_op->result);
- + last_op->result_type = IS_UNUSED;
- + last_op->result.num = CG(context).nested_calls;
- Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
- } else {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_INIT_FCALL_BY_NAME;
- + opline->result.num = CG(context).nested_calls;
- SET_UNUSED(opline->op1);
- if (left_bracket->op_type == IS_CONST) {
- opline->op2_type = IS_CONST;
- @@ -2004,6 +2011,9 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
- }
- zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
- + if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
- + CG(active_op_array)->nested_calls = CG(context).nested_calls;
- + }
- zend_do_extended_fcall_begin(TSRMLS_C);
- }
- /* }}} */
- @@ -2031,12 +2041,14 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
- /* In run-time PHP will check for function with full name and
- internal function with short name */
- opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
- + opline->result.num = CG(context).nested_calls;
- SET_UNUSED(opline->op1);
- opline->op2_type = IS_CONST;
- opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
- GET_CACHE_SLOT(opline->op2.constant);
- } else {
- opline->opcode = ZEND_INIT_FCALL_BY_NAME;
- + opline->result.num = CG(context).nested_calls;
- SET_UNUSED(opline->op1);
- if (function_name->op_type == IS_CONST) {
- opline->op2_type = IS_CONST;
- @@ -2048,6 +2060,9 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
- }
- zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
- + if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
- + CG(active_op_array)->nested_calls = CG(context).nested_calls;
- + }
- zend_do_extended_fcall_begin(TSRMLS_C);
- }
- /* }}} */
- @@ -2395,6 +2410,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
- opline->extended_value = class_node.EA ;
- }
- opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
- + opline->result.num = CG(context).nested_calls;
- if (class_node.op_type == IS_CONST) {
- opline->op1_type = IS_CONST;
- opline->op1.constant =
- @@ -2416,6 +2432,9 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
- }
- zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
- + if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
- + CG(active_op_array)->nested_calls = CG(context).nested_calls;
- + }
- zend_do_extended_fcall_begin(TSRMLS_C);
- return 1; /* Dynamic */
- }
- @@ -2436,21 +2455,29 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
- if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
- opline->opcode = ZEND_DO_FCALL;
- SET_NODE(opline->op1, function_name);
- + SET_UNUSED(opline->op2);
- + opline->op2.num = CG(context).nested_calls;
- CALCULATE_LITERAL_HASH(opline->op1.constant);
- GET_CACHE_SLOT(opline->op1.constant);
- } else {
- opline->opcode = ZEND_DO_FCALL_BY_NAME;
- SET_UNUSED(opline->op1);
- + SET_UNUSED(opline->op2);
- + opline->op2.num = --CG(context).nested_calls;
- }
- }
- opline->result.var = get_temporary_variable(CG(active_op_array));
- opline->result_type = IS_VAR;
- - GET_NODE(result, opline->result) ;
- - SET_UNUSED(opline->op2);
- + GET_NODE(result, opline->result);
- zend_stack_del_top(&CG(function_call_stack));
- opline->extended_value = Z_LVAL(argument_list->u.constant);
- +
- + if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) {
- + CG(active_op_array)->used_stack = CG(context).used_stack + 1;
- + }
- + CG(context).used_stack -= Z_LVAL(argument_list->u.constant);
- }
- /* }}} */
- @@ -2558,6 +2585,10 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{
- SET_NODE(opline->op1, param);
- opline->op2.opline_num = offset;
- SET_UNUSED(opline->op2);
- +
- + if (++CG(context).used_stack > CG(active_op_array)->used_stack) {
- + CG(active_op_array)->used_stack = CG(context).used_stack;
- + }
- }
- /* }}} */
- @@ -5547,12 +5578,16 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /*
- new_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_NEW;
- + opline->extended_value = CG(context).nested_calls;
- opline->result_type = IS_VAR;
- opline->result.var = get_temporary_variable(CG(active_op_array));
- SET_NODE(opline->op1, class_type);
- SET_UNUSED(opline->op2);
- zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *));
- + if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
- + CG(active_op_array)->nested_calls = CG(context).nested_calls;
- + }
- }
- /* }}} */
- @@ -5765,6 +5800,13 @@ void zend_do_shell_exec(znode *result, const znode *cmd TSRMLS_DC) /* {{{ */
- opline->extended_value = 1;
- SET_UNUSED(opline->op2);
- GET_NODE(result, opline->result);
- +
- + if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
- + CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
- + }
- + if (CG(context).used_stack + 2 > CG(active_op_array)->used_stack) {
- + CG(active_op_array)->used_stack = CG(context).used_stack + 2;
- + }
- }
- /* }}} */
- diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
- index e46c1a3..def6341 100644
- --- a/Zend/zend_compile.h
- +++ b/Zend/zend_compile.h
- @@ -59,6 +59,8 @@ typedef struct _zend_compiler_context {
- int literals_size;
- int current_brk_cont;
- int backpatch_count;
- + int nested_calls;
- + int used_stack;
- HashTable *labels;
- } zend_compiler_context;
- @@ -279,6 +281,9 @@ struct _zend_op_array {
- zend_uint T;
- + zend_uint nested_calls;
- + zend_uint used_stack;
- +
- zend_brk_cont_element *brk_cont_array;
- int last_brk_cont;
- @@ -369,11 +374,17 @@ typedef struct _list_llist_element {
- union _temp_variable;
- +typedef struct _call_slot {
- + zend_function *fbc;
- + zval *object;
- + zend_class_entry *called_scope;
- + zend_bool is_ctor_call;
- + zend_bool is_ctor_result_used;
- +} call_slot;
- +
- struct _zend_execute_data {
- struct _zend_op *opline;
- zend_function_state function_state;
- - zend_function *fbc; /* Function Being Called */
- - zend_class_entry *called_scope;
- zend_op_array *op_array;
- zval *object;
- union _temp_variable *Ts;
- @@ -386,8 +397,9 @@ struct _zend_execute_data {
- zend_class_entry *current_scope;
- zend_class_entry *current_called_scope;
- zval *current_this;
- - zval *current_object;
- struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
- + call_slot *call_slots;
- + call_slot *call;
- };
- #define EX(element) execute_data.element
- diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
- index 361afc6..5f04ba7 100644
- --- a/Zend/zend_execute.c
- +++ b/Zend/zend_execute.c
- @@ -1570,25 +1570,6 @@ void zend_free_compiled_variables(zval ***CVs, int num) /* {{{ */
- }
- /* }}} */
- -void** zend_copy_arguments(void **arguments_end) /* {{{ */
- -{
- - int arguments_count = (int) (zend_uintptr_t) *arguments_end;
- - size_t arguments_size = (arguments_count + 1) * sizeof(void **);
- - void **arguments_start = arguments_end - arguments_count;
- - void **copied_arguments_start = emalloc(arguments_size);
- - void **copied_arguments_end = copied_arguments_start + arguments_count;
- - int i;
- -
- - memcpy(copied_arguments_start, arguments_start, arguments_size);
- -
- - for (i = 0; i < arguments_count; i++) {
- - Z_ADDREF_P((zval *) arguments_start[i]);
- - }
- -
- - return copied_arguments_end;
- -}
- -/* }}} */
- -
- /*
- * Local variables:
- * tab-width: 4
- diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
- index 4594eba..fdd9f56 100644
- --- a/Zend/zend_execute.h
- +++ b/Zend/zend_execute.h
- @@ -50,14 +50,14 @@ typedef union _temp_variable {
- BEGIN_EXTERN_C()
- struct _zend_fcall_info;
- -ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
- +ZEND_API extern void (*zend_execute_ex)(zend_execute_data *execute_data TSRMLS_DC);
- ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, struct _zend_fcall_info *fci, int return_value_used TSRMLS_DC);
- void init_executor(TSRMLS_D);
- void shutdown_executor(TSRMLS_D);
- void shutdown_destructors(TSRMLS_D);
- zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC);
- -ZEND_API void execute(zend_op_array *op_array TSRMLS_DC);
- +ZEND_API void zend_execute(zend_op_array *op_array TSRMLS_DC);
- ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC);
- ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, struct _zend_fcall_info *fci, int return_value_used TSRMLS_DC);
- ZEND_API int zend_is_true(zval *op);
- @@ -222,12 +222,6 @@ static zend_always_inline void **zend_vm_stack_top(TSRMLS_D)
- static zend_always_inline void zend_vm_stack_push(void *ptr TSRMLS_DC)
- {
- - ZEND_VM_STACK_GROW_IF_NEEDED(1);
- - *(EG(argument_stack)->top++) = ptr;
- -}
- -
- -static zend_always_inline void zend_vm_stack_push_nocheck(void *ptr TSRMLS_DC)
- -{
- *(EG(argument_stack)->top++) = ptr;
- }
- @@ -235,11 +229,6 @@ static zend_always_inline void *zend_vm_stack_pop(TSRMLS_D)
- {
- void *el = *(--EG(argument_stack)->top);
- - if (UNEXPECTED(EG(argument_stack)->top == ZEND_VM_STACK_ELEMETS(EG(argument_stack)))) {
- - zend_vm_stack p = EG(argument_stack);
- - EG(argument_stack) = p->prev;
- - efree(p);
- - }
- return el;
- }
- @@ -272,6 +261,12 @@ static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC)
- return ret;
- }
- +static zend_always_inline void** zend_vm_stack_frame_base(zend_execute_data *ex)
- +{
- + return (void**)((char*)ex->call_slots +
- + ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * ex->op_array->nested_calls);
- +}
- +
- static zend_always_inline void zend_vm_stack_free_int(void *ptr TSRMLS_DC)
- {
- if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (void**)ptr)) {
- @@ -302,35 +297,6 @@ static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC)
- }
- }
- -static zend_always_inline void** zend_vm_stack_push_args(int count TSRMLS_DC)
- -{
- -
- - if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count) ||
- - UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) {
- - zend_vm_stack p = EG(argument_stack);
- -
- - zend_vm_stack_extend(count + 1 TSRMLS_CC);
- -
- - EG(argument_stack)->top += count;
- - *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count;
- - while (count-- > 0) {
- - void *data = *(--p->top);
- -
- - if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) {
- - zend_vm_stack r = p;
- -
- - EG(argument_stack)->prev = p->prev;
- - p = p->prev;
- - efree(r);
- - }
- - *(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count) = data;
- - }
- - return EG(argument_stack)->top++;
- - }
- - *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count;
- - return EG(argument_stack)->top++;
- -}
- -
- static zend_always_inline void zend_vm_stack_clear_multiple(TSRMLS_D)
- {
- void **p = EG(argument_stack)->top - 1;
- @@ -344,9 +310,19 @@ static zend_always_inline void zend_vm_stack_clear_multiple(TSRMLS_D)
- zend_vm_stack_free_int(p TSRMLS_CC);
- }
- -static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_DC)
- +static zend_always_inline int zend_vm_stack_get_args_count_ex(zend_execute_data *ex)
- +{
- + if (ex) {
- + void **p = ex->function_state.arguments;
- + return (int)(zend_uintptr_t) *p;
- + } else {
- + return 0;
- + }
- +}
- +
- +static zend_always_inline zval** zend_vm_stack_get_arg_ex(zend_execute_data *ex, int requested_arg)
- {
- - void **p = EG(current_execute_data)->prev_execute_data->function_state.arguments;
- + void **p = ex->function_state.arguments;
- int arg_count = (int)(zend_uintptr_t) *p;
- if (UNEXPECTED(requested_arg > arg_count)) {
- @@ -355,25 +331,14 @@ static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_
- return (zval**)p - arg_count + requested_arg - 1;
- }
- -static zend_always_inline void zend_arg_types_stack_2_pop(zend_ptr_stack *stack, zval **object, zend_function **fbc)
- +static zend_always_inline int zend_vm_stack_get_args_count(TSRMLS_D)
- {
- - void *a, *b;
- -
- - zend_ptr_stack_2_pop(stack, &a, &b);
- -
- - *object = (zval *) a;
- - *fbc = (zend_function *) b;
- + return zend_vm_stack_get_args_count_ex(EG(current_execute_data)->prev_execute_data);
- }
- -static zend_always_inline void zend_arg_types_stack_3_pop(zend_ptr_stack *stack, zend_class_entry **called_scope, zval **object, zend_function **fbc)
- +static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_DC)
- {
- - void *a, *b, *c;
- -
- - zend_ptr_stack_3_pop(stack, &a, &b, &c);
- -
- - *called_scope = (zend_class_entry *) a;
- - *object = (zval *) b;
- - *fbc = (zend_function *) c;
- + return zend_vm_stack_get_arg_ex(EG(current_execute_data)->prev_execute_data, requested_arg);
- }
- void execute_new_code(TSRMLS_D);
- @@ -436,7 +401,6 @@ ZEND_API int zend_do_fcall(ZEND_OPCODE_HANDLER_ARGS);
- void zend_clean_and_cache_symbol_table(HashTable *symbol_table TSRMLS_DC);
- void zend_free_compiled_variables(zval ***CVs, int num);
- -void **zend_copy_arguments(void **arguments_end);
- #define CACHED_PTR(num) \
- EG(active_op_array)->run_time_cache[(num)]
- diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
- index 9787966..3df0ca2 100644
- --- a/Zend/zend_execute_API.c
- +++ b/Zend/zend_execute_API.c
- @@ -38,7 +38,7 @@
- #include <sys/time.h>
- #endif
- -ZEND_API void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
- +ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data TSRMLS_DC);
- ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, zend_fcall_info *fci, int return_value_used TSRMLS_DC);
- /* true globals */
- @@ -137,7 +137,6 @@ void init_executor(TSRMLS_D) /* {{{ */
- INIT_ZVAL(EG(error_zval));
- EG(uninitialized_zval_ptr)=&EG(uninitialized_zval);
- EG(error_zval_ptr)=&EG(error_zval);
- - zend_ptr_stack_init(&EG(arg_types_stack));
- /* destroys stack frame, therefore makes core dumps worthless */
- #if 0&&ZEND_DEBUG
- original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
- @@ -293,10 +292,10 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
- } zend_end_try();
- zend_try {
- - zend_vm_stack_destroy(TSRMLS_C);
- -
- zend_objects_store_free_object_storage(&EG(objects_store) TSRMLS_CC);
- + zend_vm_stack_destroy(TSRMLS_C);
- +
- /* Destroy all op arrays */
- if (EG(full_tables_cleanup)) {
- zend_hash_reverse_apply(EG(function_table), (apply_func_t) clean_non_persistent_function_full TSRMLS_CC);
- @@ -324,7 +323,6 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
- zend_hash_destroy(&EG(included_files));
- - zend_ptr_stack_destroy(&EG(arg_types_stack));
- zend_stack_destroy(&EG(user_error_handlers_error_reporting));
- zend_ptr_stack_destroy(&EG(user_error_handlers));
- zend_ptr_stack_destroy(&EG(user_exception_handlers));
- @@ -862,7 +860,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
- !ARG_MAY_BE_SENT_BY_REF(EX(function_state).function, i + 1)) {
- if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) {
- /* hack to clean up the stack */
- - zend_vm_stack_push_nocheck((void *) (zend_uintptr_t)i TSRMLS_CC);
- + zend_vm_stack_push((void *) (zend_uintptr_t)i TSRMLS_CC);
- zend_vm_stack_clear_multiple(TSRMLS_C);
- }
- @@ -899,11 +897,11 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
- *param = **(fci->params[i]);
- INIT_PZVAL(param);
- }
- - zend_vm_stack_push_nocheck(param TSRMLS_CC);
- + zend_vm_stack_push(param TSRMLS_CC);
- }
- EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
- - zend_vm_stack_push_nocheck((void*)(zend_uintptr_t)fci->param_count TSRMLS_CC);
- + zend_vm_stack_push((void*)(zend_uintptr_t)fci->param_count TSRMLS_CC);
- current_scope = EG(scope);
- EG(scope) = calling_scope;
- diff --git a/Zend/zend_extensions.h b/Zend/zend_extensions.h
- index 703e03c..17804cb 100644
- --- a/Zend/zend_extensions.h
- +++ b/Zend/zend_extensions.h
- @@ -28,7 +28,7 @@
- /* The first number is the engine version and the rest is the date.
- * This way engine 2/3 API no. is always greater than engine 1 API no..
- */
- -#define ZEND_EXTENSION_API_NO 220121113
- +#define ZEND_EXTENSION_API_NO 220121128
- typedef struct _zend_extension_version_info {
- int zend_extension_api_no;
- diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
- index 1895305..493e99d 100644
- --- a/Zend/zend_generators.c
- +++ b/Zend/zend_generators.c
- @@ -32,41 +32,7 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
- if (generator->execute_data) {
- zend_execute_data *execute_data = generator->execute_data;
- zend_op_array *op_array = execute_data->op_array;
- -
- - 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;
- - }
- - }
- - }
- + void **stack_frame;
- if (!execute_data->symbol_table) {
- zend_free_compiled_variables(execute_data->CVs, op_array->last_var);
- @@ -78,10 +44,6 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
- zval_ptr_dtor(&execute_data->current_this);
- }
- - if (execute_data->object) {
- - zval_ptr_dtor(&execute_data->object);
- - }
- -
- /* If the generator is closed before it can finish execution (reach
- * a return statement) we have to free loop variables manually, as
- * we don't know whether the SWITCH_FREE / FREE opcodes have run */
- @@ -120,32 +82,20 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
- }
- /* Clear any backed up stack arguments */
- - if (generator->backed_up_stack) {
- - zval **zvals = (zval **) generator->backed_up_stack;
- - size_t zval_num = generator->backed_up_stack_size / sizeof(zval *);
- - int i;
- -
- - for (i = 0; i < zval_num; i++) {
- - zval_ptr_dtor(&zvals[i]);
- + if (generator->stack != EG(argument_stack)) {
- + stack_frame = zend_vm_stack_frame_base(execute_data);
- + while (generator->stack->top != stack_frame) {
- + zval_ptr_dtor((zval**)stack_frame);
- + stack_frame++;
- }
- -
- - efree(generator->backed_up_stack);
- }
- - if (generator->backed_up_arg_types_stack) {
- - /* The arg types stack contains three elements per call: fbc, object
- - * and called_scope. Here we traverse the stack from top to bottom
- - * and dtor the object. */
- - int i = generator->backed_up_arg_types_stack_count / 3;
- - while (i--) {
- - zval *object = (zval *) generator->backed_up_arg_types_stack[3*i + 1];
- - if (object) {
- - zval_ptr_dtor(&object);
- - }
- + while (execute_data->call >= execute_data->call_slots) {
- + if (execute_data->call->object) {
- + zval_ptr_dtor(&execute_data->call->object);
- }
- -
- - efree(generator->backed_up_arg_types_stack);
- - }
- + execute_data->call--;
- + }
- /* We have added an additional stack frame in prev_execute_data, so we
- * have to free it. It also contains the arguments passed to the
- @@ -162,11 +112,7 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
- for (i = 0; i < arguments_count; ++i) {
- zval_ptr_dtor(arguments_start + i);
- }
- -
- - efree(arguments_start);
- }
- -
- - efree(prev_execute_data);
- }
- /* Free a clone of closure */
- @@ -175,7 +121,11 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
- efree(op_array);
- }
- - efree(execute_data);
- + efree(generator->stack);
- + if (generator->stack == EG(argument_stack)) {
- + /* abnormal exit for running generator */
- + EG(argument_stack) = NULL;
- + }
- generator->execute_data = NULL;
- }
- @@ -210,27 +160,39 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
- zend_execute_data *execute_data = orig->execute_data;
- zend_op_array *op_array = execute_data->op_array;
- HashTable *symbol_table = execute_data->symbol_table;
- -
- - /* Alloc separate execution context, as well as separate sections for
- - * compiled variables and temporary variables */
- - size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data));
- - size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (symbol_table ? 1 : 2));
- - size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T;
- - size_t total_size = execute_data_size + CVs_size + Ts_size;
- -
- - clone->execute_data = emalloc(total_size);
- -
- - /* Copy the zend_execute_data struct */
- - memcpy(clone->execute_data, execute_data, execute_data_size);
- -
- - /* Set the pointers to the memory segments for the compiled and
- - * temporary variables (which are located after the execute_data) */
- - clone->execute_data->CVs = (zval ***) ((char *) clone->execute_data + execute_data_size);
- - clone->execute_data->Ts = (temp_variable *) ((char *) clone->execute_data->CVs + CVs_size);
- -
- - /* Zero out the compiled variables section */
- - memset(clone->execute_data->CVs, 0, sizeof(zval **) * op_array->last_var);
- -
- + zend_execute_data *current_execute_data;
- + zend_op **opline_ptr;
- + HashTable *current_symbol_table;
- + zend_vm_stack current_stack;
- + zval *current_this;
- + void **stack_frame, **orig_stack_frame;
- +
- + /* Create new execution context. We have to back up and restore
- + * EG(current_execute_data), EG(opline_ptr), EG(active_symbol_table)
- + * and EG(This) here because the function modifies or uses them */
- + current_execute_data = EG(current_execute_data);
- + EG(current_execute_data) = execute_data->prev_execute_data;
- + opline_ptr = EG(opline_ptr);
- + current_symbol_table = EG(active_symbol_table);
- + EG(active_symbol_table) = execute_data->symbol_table;
- + current_this = EG(This);
- + EG(This) = NULL;
- + current_stack = EG(argument_stack);
- + clone->execute_data = zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC);
- + clone->stack = EG(argument_stack);
- + EG(argument_stack) = current_stack;
- + EG(This) = current_this;
- + EG(active_symbol_table) = current_symbol_table;
- + EG(current_execute_data) = current_execute_data;
- + EG(opline_ptr) = opline_ptr;
- +
- + /* copy */
- + clone->execute_data->opline = execute_data->opline;
- + clone->execute_data->function_state = execute_data->function_state;
- + clone->execute_data->current_scope = execute_data->current_scope;
- + clone->execute_data->current_called_scope = execute_data->current_called_scope;
- + clone->execute_data->fast_ret = execute_data->fast_ret;
- +
- if (!symbol_table) {
- int i;
- @@ -238,7 +200,7 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
- for (i = 0; i < op_array->last_var; i++) {
- if (execute_data->CVs[i]) {
- clone->execute_data->CVs[i] = (zval **) clone->execute_data->CVs + op_array->last_var + i;
- - *clone->execute_data->CVs[i] = (zval *) orig->execute_data->CVs[op_array->last_var + i];
- + *clone->execute_data->CVs[i] = (zval *) execute_data->CVs[op_array->last_var + i];
- Z_ADDREF_PP(clone->execute_data->CVs[i]);
- }
- }
- @@ -259,8 +221,39 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
- }
- }
- + /* Copy nested-calls stack */
- + if (execute_data->call) {
- + clone->execute_data->call = clone->execute_data->call_slots +
- + (execute_data->call - execute_data->call_slots);
- + } else {
- + clone->execute_data->call = NULL;
- + }
- + memcpy(clone->execute_data->call_slots, execute_data->call_slots, sizeof(call_slot) * op_array->nested_calls);
- + if (clone->execute_data->call >= clone->execute_data->call_slots) {
- + call_slot *call = clone->execute_data->call;
- +
- + while (call >= clone->execute_data->call_slots) {
- + if (call->object) {
- + Z_ADDREF_P(call->object);
- + }
- + call--;
- + }
- + }
- +
- /* Copy the temporary variables */
- - memcpy(clone->execute_data->Ts, orig->execute_data->Ts, Ts_size);
- + memcpy(clone->execute_data->Ts, execute_data->Ts, sizeof(temp_variable) * op_array->T);
- +
- + /* Copy arguments passed on stack */
- + stack_frame = zend_vm_stack_frame_base(clone->execute_data);
- + orig_stack_frame = zend_vm_stack_frame_base(execute_data);
- + clone->stack->top = stack_frame + (orig->stack->top - orig_stack_frame);
- + if (clone->stack->top != stack_frame) {
- + memcpy(stack_frame, orig_stack_frame, sizeof(zval*) * (orig->stack->top - orig_stack_frame));
- + while (clone->stack->top != stack_frame) {
- + Z_ADDREF_PP((zval**)stack_frame);
- + stack_frame++;
- + }
- + }
- /* Add references to loop variables */
- {
- @@ -286,42 +279,6 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
- }
- }
- - if (orig->backed_up_stack) {
- - /* Copy backed up stack */
- - clone->backed_up_stack = emalloc(orig->backed_up_stack_size);
- - memcpy(clone->backed_up_stack, orig->backed_up_stack, orig->backed_up_stack_size);
- -
- - /* Add refs to stack variables */
- - {
- - zval **zvals = (zval **) orig->backed_up_stack;
- - size_t zval_num = orig->backed_up_stack_size / sizeof(zval *);
- - int i;
- -
- - for (i = 0; i < zval_num; i++) {
- - Z_ADDREF_P(zvals[i]);
- - }
- - }
- - }
- -
- - if (orig->backed_up_arg_types_stack) {
- - size_t stack_size = orig->backed_up_arg_types_stack_count * sizeof(void *);
- -
- - clone->backed_up_arg_types_stack = emalloc(stack_size);
- - memcpy(clone->backed_up_arg_types_stack, orig->backed_up_arg_types_stack, stack_size);
- -
- - /* We have to add refs to the objects in the arg types stack (the
- - * object is always the second element of a three-pack. */
- - {
- - int i, stack_frames = clone->backed_up_arg_types_stack_count / 3;
- - for (i = 0; i < stack_frames; i++) {
- - zval *object = (zval *) clone->backed_up_arg_types_stack[3*i + 1];
- - if (object) {
- - Z_ADDREF_P(object);
- - }
- - }
- - }
- - }
- -
- /* Update the send_target to use the temporary variable with the same
- * offset as the original generator, but in our temporary variable
- * memory segment. */
- @@ -334,24 +291,14 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
- }
- if (execute_data->current_this) {
- + clone->execute_data->current_this = execute_data->current_this;
- Z_ADDREF_P(execute_data->current_this);
- }
- if (execute_data->object) {
- + clone->execute_data->object = execute_data->object;
- Z_ADDREF_P(execute_data->object);
- }
- -
- - /* Prev execute data contains an additional stack frame (for proper
- - * backtraces) which has to be copied. */
- - clone->execute_data->prev_execute_data = emalloc(sizeof(zend_execute_data));
- - memcpy(clone->execute_data->prev_execute_data, execute_data->prev_execute_data, sizeof(zend_execute_data));
- -
- - /* It also contains the arguments passed to the generator, which also
- - * have to be copied */
- - if (execute_data->prev_execute_data->function_state.arguments) {
- - clone->execute_data->prev_execute_data->function_state.arguments
- - = zend_copy_arguments(execute_data->prev_execute_data->function_state.arguments);
- - }
- }
- /* The value and key are known not to be references, so simply add refs */
- @@ -399,7 +346,9 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
- zend_generator *generator;
- zend_execute_data *current_execute_data;
- zend_op **opline_ptr;
- + HashTable *current_symbol_table;
- zend_execute_data *execute_data;
- + zend_vm_stack current_stack = EG(argument_stack);
- /* Create a clone of closure, because it may be destroyed */
- if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
- @@ -410,11 +359,14 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
- }
- /* Create new execution context. We have to back up and restore
- - * EG(current_execute_data) and EG(opline_ptr) here because the function
- - * modifies it. */
- + * EG(current_execute_data), EG(opline_ptr) and EG(active_symbol_table)
- + * here because the function modifies or uses them */
- current_execute_data = EG(current_execute_data);
- opline_ptr = EG(opline_ptr);
- + current_symbol_table = EG(active_symbol_table);
- + EG(active_symbol_table) = NULL;
- execute_data = zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC);
- + EG(active_symbol_table) = current_symbol_table;
- EG(current_execute_data) = current_execute_data;
- EG(opline_ptr) = opline_ptr;
- @@ -434,18 +386,8 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
- /* Save execution context in generator object. */
- generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC);
- generator->execute_data = execute_data;
- -
- - /* We have to add another stack frame so the generator function shows
- - * up in backtraces and func_get_all() can access the function
- - * arguments. */
- - execute_data->prev_execute_data = emalloc(sizeof(zend_execute_data));
- - memset(execute_data->prev_execute_data, 0, sizeof(zend_execute_data));
- - execute_data->prev_execute_data->function_state.function = (zend_function *) op_array;
- - if (EG(current_execute_data)) {
- - execute_data->prev_execute_data->function_state.arguments = zend_copy_arguments(EG(current_execute_data)->function_state.arguments);
- - } else {
- - execute_data->prev_execute_data->function_state.arguments = NULL;
- - }
- + generator->stack = EG(argument_stack);
- + EG(argument_stack) = current_stack;
- return return_value;
- }
- @@ -487,28 +429,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
- zval *original_This = EG(This);
- zend_class_entry *original_scope = EG(scope);
- zend_class_entry *original_called_scope = EG(called_scope);
- - int original_arg_types_stack_count = EG(arg_types_stack).top;
- -
- - /* Remember the current stack position so we can back up pushed args */
- - generator->original_stack_top = zend_vm_stack_top(TSRMLS_C);
- -
- - /* If there is a backed up stack copy it to the VM stack */
- - if (generator->backed_up_stack) {
- - void *stack = zend_vm_stack_alloc(generator->backed_up_stack_size TSRMLS_CC);
- - memcpy(stack, generator->backed_up_stack, generator->backed_up_stack_size);
- - efree(generator->backed_up_stack);
- - generator->backed_up_stack = NULL;
- - }
- -
- - if (generator->backed_up_arg_types_stack) {
- - zend_ptr_stack_push_from_memory(
- - &EG(arg_types_stack),
- - generator->backed_up_arg_types_stack_count,
- - generator->backed_up_arg_types_stack
- - );
- - efree(generator->backed_up_arg_types_stack);
- - generator->backed_up_arg_types_stack = NULL;
- - }
- + zend_vm_stack original_stack = EG(argument_stack);
- /* We (mis)use the return_value_ptr_ptr to provide the generator object
- * to the executor, so YIELD will be able to set the yielded value */
- @@ -522,6 +443,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
- EG(This) = generator->execute_data->current_this;
- EG(scope) = generator->execute_data->current_scope;
- EG(called_scope) = generator->execute_data->current_called_scope;
- + EG(argument_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()).
- @@ -533,7 +455,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
- /* Resume execution */
- generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING;
- - execute_ex(generator->execute_data TSRMLS_CC);
- + zend_execute_ex(generator->execute_data TSRMLS_CC);
- generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING;
- /* Restore executor globals */
- @@ -545,27 +467,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
- EG(This) = original_This;
- EG(scope) = original_scope;
- EG(called_scope) = original_called_scope;
- -
- - /* The stack top before and after the execution differ, i.e. there are
- - * arguments pushed to the stack. */
- - if (generator->original_stack_top != zend_vm_stack_top(TSRMLS_C)) {
- - generator->backed_up_stack_size = (zend_vm_stack_top(TSRMLS_C) - generator->original_stack_top) * sizeof(void *);
- - generator->backed_up_stack = emalloc(generator->backed_up_stack_size);
- - memcpy(generator->backed_up_stack, generator->original_stack_top, generator->backed_up_stack_size);
- - zend_vm_stack_free(generator->original_stack_top TSRMLS_CC);
- - }
- -
- - if (original_arg_types_stack_count != EG(arg_types_stack).top) {
- - generator->backed_up_arg_types_stack_count =
- - EG(arg_types_stack).top - original_arg_types_stack_count;
- -
- - generator->backed_up_arg_types_stack = emalloc(generator->backed_up_arg_types_stack_count * sizeof(void *));
- - zend_ptr_stack_pop_into_memory(
- - &EG(arg_types_stack),
- - generator->backed_up_arg_types_stack_count,
- - generator->backed_up_arg_types_stack
- - );
- - }
- + EG(argument_stack) = original_stack;
- /* If an exception was thrown in the generator we have to internally
- * rethrow it in the parent scope. */
- @@ -741,21 +643,11 @@ ZEND_METHOD(Generator, __wakeup)
- /* get_iterator implementation */
- -typedef struct _zend_generator_iterator {
- - zend_object_iterator intern;
- -
- - /* The generator object zval has to be stored, because the iterator is
- - * holding a ref to it, which has to be dtored. */
- - zval *object;
- -} zend_generator_iterator;
- -
- static void zend_generator_iterator_dtor(zend_object_iterator *iterator TSRMLS_DC) /* {{{ */
- {
- zval *object = ((zend_generator_iterator *) iterator)->object;
- zval_ptr_dtor(&object);
- -
- - efree(iterator);
- }
- /* }}} */
- @@ -854,7 +746,7 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob
- return NULL;
- }
- - iterator = emalloc(sizeof(zend_generator_iterator));
- + iterator = &generator->iterator;
- iterator->intern.funcs = &zend_generator_iterator_functions;
- iterator->intern.data = (void *) generator;
- diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h
- index 3dc3e6f..90f8160 100644
- --- a/Zend/zend_generators.h
- +++ b/Zend/zend_generators.h
- @@ -25,25 +25,24 @@ BEGIN_EXTERN_C()
- extern ZEND_API zend_class_entry *zend_ce_generator;
- END_EXTERN_C()
- +typedef struct _zend_generator_iterator {
- + zend_object_iterator intern;
- +
- + /* The generator object zval has to be stored, because the iterator is
- + * holding a ref to it, which has to be dtored. */
- + zval *object;
- +} zend_generator_iterator;
- +
- typedef struct _zend_generator {
- zend_object std;
- + zend_generator_iterator iterator;
- +
- /* The suspended execution context. */
- zend_execute_data *execute_data;
- - /* If the execution is suspended during a function call there may be
- - * arguments pushed to the stack, so it has to be backed up. */
- - void *backed_up_stack;
- - size_t backed_up_stack_size;
- -
- - /* For method calls PHP also pushes various type information on a second
- - * stack, which also needs to be backed up. */
- - void **backed_up_arg_types_stack;
- - int backed_up_arg_types_stack_count;
- -
- - /* The original stack top before resuming the generator. This is required
- - * for proper cleanup during exception handling. */
- - void **original_stack_top;
- + /* The separate stack used by generator */
- + zend_vm_stack stack;
- /* Current value */
- zval *value;
- diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
- index e5aba0d..6ad9768 100644
- --- a/Zend/zend_globals.h
- +++ b/Zend/zend_globals.h
- @@ -167,8 +167,6 @@ struct _zend_executor_globals {
- zval error_zval;
- zval *error_zval_ptr;
- - zend_ptr_stack arg_types_stack;
- -
- /* symbol table cache */
- HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
- HashTable **symtable_cache_limit;
- diff --git a/Zend/zend_modules.h b/Zend/zend_modules.h
- index 442535b..bfea3e0 100644
- --- a/Zend/zend_modules.h
- +++ b/Zend/zend_modules.h
- @@ -33,7 +33,7 @@
- #define ZEND_MODULE_INFO_FUNC_ARGS zend_module_entry *zend_module TSRMLS_DC
- #define ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU zend_module TSRMLS_CC
- -#define ZEND_MODULE_API_NO 20121113
- +#define ZEND_MODULE_API_NO 20121128
- #ifdef ZTS
- #define USING_ZTS 1
- #else
- diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
- index 563c843..2fd8f52 100644
- --- a/Zend/zend_opcode.c
- +++ b/Zend/zend_opcode.c
- @@ -70,6 +70,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
- op_array->T = 0;
- + op_array->nested_calls = 0;
- + op_array->used_stack = 0;
- +
- op_array->function_name = NULL;
- op_array->filename = zend_get_compiled_filename(TSRMLS_C);
- op_array->doc_comment = NULL;
- @@ -541,6 +544,15 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
- /* generate a FAST_CALL to finaly 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);
- @@ -567,6 +579,14 @@ 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);
- @@ -622,6 +642,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:
- 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 4ae4ca1..966827d 100644
- --- a/Zend/zend_vm_def.h
- +++ b/Zend/zend_vm_def.h
- @@ -1161,7 +1161,7 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)
- USE_OPLINE
- ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type,
- - ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R);
- + ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R);
- }
- ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)
- @@ -1283,7 +1283,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
- SAVE_OPLINE();
- - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
- + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
- container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
- if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
- zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
- @@ -1519,7 +1519,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
- {
- USE_OPLINE
- - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
- + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
- /* Behave like FETCH_OBJ_W */
- zend_free_op free_op1, free_op2;
- zval *property;
- @@ -1889,7 +1889,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
- EX(function_state).function = (zend_function *) EX(op_array);
- EX(function_state).arguments = NULL;
- - EX(object) = EX(current_object);
- EG(opline_ptr) = &EX(opline);
- EG(active_op_array) = EX(op_array);
- @@ -1925,8 +1924,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
- EX(function_state).arguments = NULL;
- if (EG(This)) {
- - if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
- - if (IS_CTOR_USED(EX(called_scope))) {
- + if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) {
- + if (EX(call)->is_ctor_result_used) {
- Z_DELREF_P(EG(This));
- }
- if (Z_REFCOUNT_P(EG(This)) == 1) {
- @@ -1939,8 +1938,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
- EG(scope) = EX(current_scope);
- EG(called_scope) = EX(current_called_scope);
- - EX(object) = EX(current_object);
- - EX(called_scope) = DECODE_CTOR(EX(called_scope));
- + EX(call)--;
- zend_vm_stack_clear_multiple(TSRMLS_C);
- @@ -1966,6 +1964,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
- zend_function *fbc = EX(function_state).function;
- SAVE_OPLINE();
- + EX(object) = EX(call)->object;
- if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) {
- if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) {
- zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name);
- @@ -2000,11 +1999,11 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
- EX(current_called_scope) = EG(called_scope);
- EG(This) = EX(object);
- EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL;
- - EG(called_scope) = EX(called_scope);
- + EG(called_scope) = EX(call)->called_scope;
- }
- - zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc));
- - EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
- + EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
- + zend_vm_stack_push((void*)(zend_uintptr_t)opline->extended_value TSRMLS_CC);
- LOAD_OPLINE();
- if (fbc->type == ZEND_INTERNAL_FUNCTION) {
- @@ -2054,7 +2053,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
- if (RETURN_VALUE_USED(opline)) {
- EX_T(opline->result.var).var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC);
- }
- - } else if (EXPECTED(zend_execute == execute)) {
- + } else if (EXPECTED(zend_execute_ex == execute_ex)) {
- if (EXPECTED(EG(exception) == NULL)) {
- ZEND_VM_ENTER();
- }
- @@ -2100,8 +2099,8 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
- if (should_change_scope) {
- if (EG(This)) {
- - if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
- - if (IS_CTOR_USED(EX(called_scope))) {
- + if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) {
- + if (EX(call)->is_ctor_result_used) {
- Z_DELREF_P(EG(This));
- }
- if (Z_REFCOUNT_P(EG(This)) == 1) {
- @@ -2115,8 +2114,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
- EG(called_scope) = EX(current_called_scope);
- }
- - EX(object) = EX(current_object);
- - EX(called_scope) = DECODE_CTOR(EX(called_scope));
- + EX(call)--;
- zend_vm_stack_clear_multiple(TSRMLS_C);
- @@ -2463,9 +2461,9 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)
- char *function_name_strval;
- int function_name_strlen;
- zend_free_op free_op1, free_op2;
- + call_slot *call = EX(call_slots) + opline->result.num;
- SAVE_OPLINE();
- - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
- function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
- @@ -2477,49 +2475,51 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)
- function_name_strval = Z_STRVAL_P(function_name);
- function_name_strlen = Z_STRLEN_P(function_name);
- - EX(object) = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R);
- + call->object = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R);
- - if (EXPECTED(EX(object) != NULL) &&
- - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) {
- - EX(called_scope) = Z_OBJCE_P(EX(object));
- + if (EXPECTED(call->object != NULL) &&
- + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) {
- + call->called_scope = Z_OBJCE_P(call->object);
- if (OP2_TYPE != IS_CONST ||
- - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) {
- - zval *object = EX(object);
- + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) {
- + zval *object = call->object;
- - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) {
- + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) {
- zend_error_noreturn(E_ERROR, "Object does not support method calls");
- }
- /* First, locate the function. */
- - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
- - if (UNEXPECTED(EX(fbc) == NULL)) {
- - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval);
- + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
- + if (UNEXPECTED(call->fbc == NULL)) {
- + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval);
- }
- if (OP2_TYPE == IS_CONST &&
- - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) &&
- - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
- - EXPECTED(EX(object) == object)) {
- - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc));
- + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) &&
- + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
- + EXPECTED(call->object == object)) {
- + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc);
- }
- }
- } else {
- zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
- }
- - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
- - EX(object) = NULL;
- + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
- + call->object = NULL;
- } else {
- - if (!PZVAL_IS_REF(EX(object))) {
- - Z_ADDREF_P(EX(object)); /* For $this pointer */
- + if (!PZVAL_IS_REF(call->object)) {
- + Z_ADDREF_P(call->object); /* For $this pointer */
- } else {
- zval *this_ptr;
- ALLOC_ZVAL(this_ptr);
- - INIT_PZVAL_COPY(this_ptr, EX(object));
- + INIT_PZVAL_COPY(this_ptr, call->object);
- zval_copy_ctor(this_ptr);
- - EX(object) = this_ptr;
- + call->object = this_ptr;
- }
- }
- + call->is_ctor_call = 0;
- + EX(call) = call;
- FREE_OP2();
- FREE_OP1_IF_VAR();
- @@ -2533,9 +2533,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
- USE_OPLINE
- zval *function_name;
- zend_class_entry *ce;
- + call_slot *call = EX(call_slots) + opline->result.num;
- SAVE_OPLINE();
- - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
- if (OP1_TYPE == IS_CONST) {
- /* no function found. try a static method in class */
- @@ -2549,24 +2549,24 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
- }
- CACHE_PTR(opline->op1.literal->cache_slot, ce);
- }
- - EX(called_scope) = ce;
- + call->called_scope = ce;
- } else {
- ce = EX_T(opline->op1.var).class_entry;
- if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) {
- - EX(called_scope) = EG(called_scope);
- + call->called_scope = EG(called_scope);
- } else {
- - EX(called_scope) = ce;
- + call->called_scope = ce;
- }
- }
- if (OP1_TYPE == IS_CONST &&
- OP2_TYPE == IS_CONST &&
- CACHED_PTR(opline->op2.literal->cache_slot)) {
- - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
- + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
- } else if (OP1_TYPE != IS_CONST &&
- OP2_TYPE == IS_CONST &&
- - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) {
- + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) {
- /* do nothing */
- } else if (OP2_TYPE != IS_UNUSED) {
- char *function_name_strval = NULL;
- @@ -2589,20 +2589,20 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
- if (function_name_strval) {
- if (ce->get_static_method) {
- - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC);
- + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC);
- } else {
- - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
- + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
- }
- - if (UNEXPECTED(EX(fbc) == NULL)) {
- + if (UNEXPECTED(call->fbc == NULL)) {
- zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);
- }
- if (OP2_TYPE == IS_CONST &&
- - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) &&
- - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
- + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) &&
- + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
- if (OP1_TYPE == IS_CONST) {
- - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
- + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
- } else {
- - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc));
- + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc);
- }
- }
- }
- @@ -2616,29 +2616,31 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
- if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) {
- zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name);
- }
- - EX(fbc) = ce->constructor;
- + call->fbc = ce->constructor;
- }
- - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
- - EX(object) = NULL;
- + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) {
- + call->object = NULL;
- } else {
- if (EG(This) &&
- Z_OBJ_HT_P(EG(This))->get_class_entry &&
- !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
- /* We are calling method of the other (incompatible) class,
- but passing $this. This is done for compatibility with php-4. */
- - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
- - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name);
- + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
- + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name, call->fbc->common.function_name);
- } else {
- /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
- - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name);
- + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name, call->fbc->common.function_name);
- }
- }
- - if ((EX(object) = EG(This))) {
- - Z_ADDREF_P(EX(object));
- - EX(called_scope) = Z_OBJCE_P(EX(object));
- + if ((call->object = EG(This))) {
- + Z_ADDREF_P(call->object);
- + call->called_scope = Z_OBJCE_P(call->object);
- }
- }
- + call->is_ctor_call = 0;
- + EX(call) = call;
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
- @@ -2648,19 +2650,21 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
- {
- USE_OPLINE
- zval *function_name;
- - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
- + call_slot *call = EX(call_slots) + opline->result.num;
- if (OP2_TYPE == IS_CONST) {
- function_name = (zval*)(opline->op2.literal+1);
- if (CACHED_PTR(opline->op2.literal->cache_slot)) {
- - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
- - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) {
- + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
- + } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) {
- SAVE_OPLINE();
- zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
- } else {
- - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
- + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
- }
- - EX(object) = NULL;
- + call->object = NULL;
- + call->is_ctor_call = 0;
- + EX(call) = call;
- /*CHECK_EXCEPTION();*/
- ZEND_VM_NEXT_OPCODE();
- } else {
- @@ -2680,28 +2684,32 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
- } else {
- lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
- }
- - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) {
- + if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) {
- zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
- }
- efree(lcname);
- FREE_OP2();
- - EX(object) = NULL;
- + call->object = NULL;
- + call->is_ctor_call = 0;
- + EX(call) = call;
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
- } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR &&
- EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
- Z_OBJ_HANDLER_P(function_name, get_closure) &&
- - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
- - if (EX(object)) {
- - Z_ADDREF_P(EX(object));
- + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) {
- + if (call->object) {
- + Z_ADDREF_P(call->object);
- }
- if (OP2_TYPE == IS_VAR && OP2_FREE &&
- - EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
- + call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
- /* Delay closure destruction until its invocation */
- - EX(fbc)->common.prototype = (zend_function*)function_name;
- + call->fbc->common.prototype = (zend_function*)function_name;
- } else {
- FREE_OP2();
- }
- + call->is_ctor_call = 0;
- + EX(call) = call;
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
- } else if (OP2_TYPE != IS_CONST &&
- @@ -2732,41 +2740,43 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
- }
- - EX(called_scope) = ce;
- - EX(object) = NULL;
- + call->called_scope = ce;
- + call->object = NULL;
- if (ce->get_static_method) {
- - EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
- + call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
- } else {
- - EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
- + call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
- }
- } else {
- - EX(object) = *obj;
- - ce = EX(called_scope) = Z_OBJCE_PP(obj);
- + call->object = *obj;
- + ce = call->called_scope = Z_OBJCE_PP(obj);
- - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
- - if (UNEXPECTED(EX(fbc) == NULL)) {
- - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
- + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
- + if (UNEXPECTED(call->fbc == NULL)) {
- + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_PP(method));
- }
- - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
- - EX(object) = NULL;
- + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
- + call->object = NULL;
- } else {
- - if (!PZVAL_IS_REF(EX(object))) {
- - Z_ADDREF_P(EX(object)); /* For $this pointer */
- + if (!PZVAL_IS_REF(call->object)) {
- + Z_ADDREF_P(call->object); /* For $this pointer */
- } else {
- zval *this_ptr;
- ALLOC_ZVAL(this_ptr);
- - INIT_PZVAL_COPY(this_ptr, EX(object));
- + INIT_PZVAL_COPY(this_ptr, call->object);
- zval_copy_ctor(this_ptr);
- - EX(object) = this_ptr;
- + call->object = this_ptr;
- }
- }
- }
- - if (UNEXPECTED(EX(fbc) == NULL)) {
- + if (UNEXPECTED(call->fbc == NULL)) {
- zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
- }
- + call->is_ctor_call = 0;
- + EX(call) = call;
- FREE_OP2();
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
- @@ -2781,31 +2791,32 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
- {
- USE_OPLINE
- zend_literal *func_name;
- -
- - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
- + call_slot *call = EX(call_slots) + opline->result.num;
- func_name = opline->op2.literal + 1;
- if (CACHED_PTR(opline->op2.literal->cache_slot)) {
- - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
- - } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE) {
- + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
- + } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE) {
- func_name++;
- - if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE)) {
- + if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE)) {
- SAVE_OPLINE();
- zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
- } else {
- - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
- + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
- }
- } else {
- - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
- + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
- }
- - EX(object) = NULL;
- + call->object = NULL;
- + call->is_ctor_call = 0;
- + EX(call) = call;
- ZEND_VM_NEXT_OPCODE();
- }
- ZEND_VM_HANDLER(61, ZEND_DO_FCALL_BY_NAME, ANY, ANY)
- {
- - EX(function_state).function = EX(fbc);
- + EX(function_state).function = EX(call)->fbc;
- ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper);
- }
- @@ -2814,8 +2825,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
- USE_OPLINE
- zend_free_op free_op1;
- zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R);
- -
- - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
- + call_slot *call = EX(call_slots) + opline->op2.num;
- if (CACHED_PTR(opline->op1.literal->cache_slot)) {
- EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
- @@ -2825,7 +2835,10 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
- } else {
- CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function);
- }
- - EX(object) = NULL;
- + call->fbc = EX(function_state).function;
- + call->object = NULL;
- + call->is_ctor_call = 0;
- + EX(call) = call;
- FREE_OP1();
- @@ -3052,7 +3065,7 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY)
- SAVE_OPLINE();
- if (opline->extended_value==ZEND_DO_FCALL_BY_NAME
- - && ARG_MUST_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
- + && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
- zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num);
- }
- {
- @@ -3113,7 +3126,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
- if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) {
- ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
- }
- - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
- + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
- ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
- }
- @@ -3139,7 +3152,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
- if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ?
- !(opline->extended_value & ZEND_ARG_SEND_SILENT) :
- - !ARG_MAY_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
- + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
- zend_error(E_STRICT, "Only variables should be passed by reference");
- }
- ALLOC_ZVAL(valptr);
- @@ -3175,7 +3188,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY)
- ZEND_VM_NEXT_OPCODE();
- }
- - if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
- + if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
- ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
- }
- @@ -3194,7 +3207,7 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY)
- USE_OPLINE
- if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME)
- - && ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
- + && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
- ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
- }
- SAVE_OPLINE();
- @@ -3400,17 +3413,20 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY)
- }
- ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.opline_num);
- } else {
- + call_slot *call = EX(call_slots) + opline->extended_value;
- +
- if (RETURN_VALUE_USED(opline)) {
- PZVAL_LOCK(object_zval);
- AI_SET_PTR(&EX_T(opline->result.var), object_zval);
- }
- - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline)));
- -
- /* We are not handling overloaded classes right now */
- - EX(object) = object_zval;
- - EX(fbc) = constructor;
- - EX(called_scope) = EX_T(opline->op1.var).class_entry;
- + call->fbc = constructor;
- + call->object = object_zval;
- + call->called_scope = EX_T(opline->op1.var).class_entry;
- + call->is_ctor_call = 1;
- + call->is_ctor_result_used = RETURN_VALUE_USED(opline);
- + EX(call) = call;
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
- @@ -3829,8 +3845,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY)
- EG(return_value_ptr_ptr) = NULL;
- }
- - EX(current_object) = EX(object);
- -
- EX(function_state).function = (zend_function *) new_op_array;
- EX(object) = NULL;
- @@ -3838,14 +3852,13 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY)
- zend_rebuild_symbol_table(TSRMLS_C);
- }
- - if (EXPECTED(zend_execute == execute)) {
- + if (EXPECTED(zend_execute_ex == execute_ex)) {
- ZEND_VM_ENTER();
- } else {
- zend_execute(new_op_array TSRMLS_CC);
- }
- EX(function_state).function = (zend_function *) EX(op_array);
- - EX(object) = EX(current_object);
- EG(opline_ptr) = &EX(opline);
- EG(active_op_array) = EX(op_array);
- @@ -5022,19 +5035,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
- /* Figure out where the next stack frame (which maybe contains pushed
- * arguments that have to be dtor'ed) starts */
- - if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
- - /* The generator object is stored in return_value_ptr_ptr */
- - zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
- -
- - /* For generators the next stack frame is conveniently stored in the
- - * generator object. */
- - stack_frame = generator->original_stack_top;
- - } else {
- - /* In all other cases the next stack frame starts after the temporary
- - * variables section of the current execution context */
- - stack_frame = (void **) ((char *) EX_Ts() +
- - ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * EX(op_array)->T);
- - }
- + stack_frame = zend_vm_stack_frame_base(EXECUTE_DATA);
- /* If the exception was thrown during a function call there might be
- * arguments pushed to the stack that have to be dtor'ed. */
- @@ -5056,21 +5057,23 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
- }
- }
- - while (EX(fbc)) {
- - EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack));
- - if (EX(object)) {
- - if (IS_CTOR_CALL(EX(called_scope))) {
- - if (IS_CTOR_USED(EX(called_scope))) {
- - Z_DELREF_P(EX(object));
- - }
- - if (Z_REFCOUNT_P(EX(object)) == 1) {
- - zend_object_store_ctor_failed(EX(object) TSRMLS_CC);
- + if (EX(call) >= EX(call_slots)) {
- + call_slot *call = EX(call);
- + do {
- + if (call->object) {
- + if (call->is_ctor_call) {
- + if (call->is_ctor_result_used) {
- + Z_DELREF_P(call->object);
- + }
- + if (Z_REFCOUNT_P(call->object) == 1) {
- + zend_object_store_ctor_failed(call->object TSRMLS_CC);
- + }
- }
- + zval_ptr_dtor(&call->object);
- }
- - zval_ptr_dtor(&EX(object));
- - }
- - EX(called_scope) = DECODE_CTOR(EX(called_scope));
- - zend_arg_types_stack_2_pop(&EG(arg_types_stack), &EX(object), &EX(fbc));
- + call--;
- + } while (call >= EX(call_slots));
- + EX(call) = NULL;
- }
- for (i=0; i<EX(op_array)->last_brk_cont; i++) {
- @@ -5240,6 +5243,19 @@ 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.skl b/Zend/zend_vm_execute.skl
- index e2d5dd1..85d3dfb 100644
- --- a/Zend/zend_vm_execute.skl
- +++ b/Zend/zend_vm_execute.skl
- @@ -1,6 +1,49 @@
- {%DEFINES%}
- -zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) {
- +/*
- + * Stack Frame Layout (the whole stack frame is allocated at once)
- + * ==================
- + *
- + * +========================================+
- + * | zend_execute_data |<---+
- + * | EX(function_state).arguments |--+ |
- + * | ... | | |
- + * | ARGUMENT [1] | | |
- + * | ... | | |
- + * | ARGUMENT [ARGS_NUMBER] | | |
- + * | ARGS_NUMBER |<-+ |
- + * +========================================+ |
- + * |
- + * +========================================+ |
- + * EG(current_execute_data) -> | zend_execute_data | |
- + * | EX(prev_execute_data) |----+
- + * +----------------------------------------+
- + * EX(Ts) ---------> | EX(Ts)[0] |
- + * | ... |
- + * | EX(Tx)[op_arrat->T] |
- + * +----------------------------------------+
- + * EX(CVs) --------> | EX(CVs)[0] |--+
- + * | ... | |
- + * | EX(CVs)[op_array->last_var] | |
- + * +----------------------------------------+ |
- + * | Optional slot for CV[0] zval* |<-+
- + * | ... |
- + * | ... for CV [op_array->last_var] zval* |
- + * +----------------------------------------+
- + * EX(call_slots) -> | EX(call_slots)[0] |
- + * | ... |
- + * | EX(call_slots)[op_array->nested_calls] |
- + * +----------------------------------------+
- + * zend_vm_stack_frame_base -> | ARGUMENTS STACK [0] |
- + * | ... |
- + * zend_vm_stack_top --------> | ... |
- + * | ... |
- + * | ARGUMENTS STACK [op_array->used_stack] |
- + * +----------------------------------------+
- + */
- +
- +zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC)
- +{
- zend_execute_data *execute_data;
- /*
- @@ -15,7 +58,9 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra
- size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data));
- size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2));
- size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T;
- - size_t total_size = execute_data_size + CVs_size + Ts_size;
- + size_t call_slots_size = ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * op_array->nested_calls;
- + size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * op_array->used_stack;
- + size_t total_size = execute_data_size + Ts_size + CVs_size + call_slots_size + stack_size;
- /*
- * Normally the execute_data is allocated on the VM stack (because it does
- @@ -27,23 +72,58 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra
- * by replacing a pointer.
- */
- if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
- - execute_data = emalloc(total_size);
- + /* Prepend the regular stack frame with copy on prev_execute_data
- + * and passed arguments
- + */
- + int args_count = zend_vm_stack_get_args_count_ex(EG(current_execute_data));
- + size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * (args_count + 1);
- +
- + total_size += args_size + execute_data_size;
- +
- + EG(argument_stack) = zend_vm_stack_new_page((total_size + (sizeof(void*) - 1)) / sizeof(void*));
- + EG(argument_stack)->prev = NULL;
- + execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size + execute_data_size);
- +
- + /* copy prev_execute_data */
- + EX(prev_execute_data) = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size);
- + memset(EX(prev_execute_data), 0, sizeof(zend_execute_data));
- + EX(prev_execute_data)->function_state.function = (zend_function*)op_array;
- + EX(prev_execute_data)->function_state.arguments = (void**)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * args_count);
- +
- + /* copy arguemnts */
- + *EX(prev_execute_data)->function_state.arguments = (void*)(zend_uintptr_t)args_count;
- + if (args_count > 0) {
- + zval **arg_src = (zval**)zend_vm_stack_get_arg_ex(EG(current_execute_data), 1);
- + zval **arg_dst = (zval**)zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1);
- + int i;
- +
- + for (i = 0; i < args_count; i++) {
- + arg_dst[i] = arg_src[i];
- + Z_ADDREF_P(arg_dst[i]);
- + }
- + }
- } else {
- execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC);
- + EX(prev_execute_data) = EG(current_execute_data);
- }
- - EX(CVs) = (zval ***) ((char *) execute_data + execute_data_size);
- + EX(Ts) = (temp_variable *) ((char *) execute_data + execute_data_size);
- +
- + EX(CVs) = (zval ***) ((char *) EX(Ts) + Ts_size);
- memset(EX(CVs), 0, sizeof(zval **) * op_array->last_var);
- - EX(Ts) = (temp_variable *) ((char *) EX(CVs) + CVs_size);
- + EX(call_slots) = (call_slot*)((char *) EX(CVs) + CVs_size);
- +
- +
- + EX(op_array) = op_array;
- +
- + EG(argument_stack)->top = zend_vm_stack_frame_base(execute_data);
- - EX(fbc) = NULL;
- - EX(called_scope) = NULL;
- EX(object) = NULL;
- + EX(current_this) = NULL;
- EX(old_error_reporting) = NULL;
- - EX(op_array) = op_array;
- EX(symbol_table) = EG(active_symbol_table);
- - EX(prev_execute_data) = EG(current_execute_data);
- + EX(call) = NULL;
- EG(current_execute_data) = execute_data;
- EX(nested) = nested;
- @@ -103,12 +183,12 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data TSRMLS_DC)
- zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
- }
- -ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
- +ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
- {
- if (EG(exception)) {
- return;
- }
- - {%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC);
- + zend_{%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC);
- }
- {%EXTERNAL_EXECUTOR%}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement