From: Dmitry Stogov Date: Wed, 2 Jul 2014 18:01:25 +0000 (+0400) Subject: Uinified call frame handling for user and internal functions. X-Git-Tag: POST_PHPNG_MERGE~90^2~7 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=412ad4b25417d261c0a8c43f788d5c110593d891;p=php Uinified call frame handling for user and internal functions. Now EG(current_execute_data) always point to the call frame of the currently executed function. --- diff --git a/Zend/zend.h b/Zend/zend.h index f21ba92d61..1ddcdb5aeb 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -290,8 +290,9 @@ typedef enum { #define USED_RET() \ (!EG(current_execute_data) || \ - !EG(current_execute_data)->opline || \ - !(EG(current_execute_data)->opline->result_type & EXT_TYPE_UNUSED)) + !EG(current_execute_data)->prev_execute_data || \ + !EG(current_execute_data)->prev_execute_data->opline || \ + !(EG(current_execute_data)->prev_execute_data->opline->result_type & EXT_TYPE_UNUSED)) #if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX) && !defined(__osf__) void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((noreturn)); diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 6b469c2b0a..a1b9083629 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -49,8 +49,8 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ zval **param, *param_ptr; TSRMLS_FETCH(); - param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); - arg_count = EG(current_execute_data)->call->num_args; + param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1); + arg_count = EG(current_execute_data)->num_args; if (param_count>arg_count) { return FAILURE; @@ -85,8 +85,8 @@ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */ zval **param, *param_ptr; TSRMLS_FETCH(); - param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); - arg_count = EG(current_execute_data)->call->num_args; + param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1); + arg_count = EG(current_execute_data)->num_args; if (param_count>arg_count) { return FAILURE; @@ -109,8 +109,8 @@ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array zval *param_ptr; int arg_count; - param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); - arg_count = EG(current_execute_data)->call->num_args; + param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1); + arg_count = EG(current_execute_data)->num_args; if (param_count>arg_count) { return FAILURE; @@ -131,8 +131,8 @@ ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TS zval *param_ptr; int arg_count; - param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); - arg_count = EG(current_execute_data)->call->num_args; + param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1); + arg_count = EG(current_execute_data)->num_args; if (param_count>arg_count) { return FAILURE; @@ -803,7 +803,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, case '+': if (have_varargs) { if (!quiet) { - zend_function *active_function = EG(current_execute_data)->call->func; + zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted", class_name, @@ -823,7 +823,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, default: if (!quiet) { - zend_function *active_function = EG(current_execute_data)->call->func; + zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters", class_name, @@ -846,7 +846,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) { if (!quiet) { - zend_function *active_function = EG(current_execute_data)->call->func; + zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given", class_name, @@ -860,7 +860,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, return FAILURE; } - arg_count = EG(current_execute_data)->call->num_args; + arg_count = EG(current_execute_data)->num_args; if (num_args > arg_count) { zend_error(E_WARNING, "%s(): could not obtain parameters for parsing", @@ -884,7 +884,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (num_varargs > 0) { *n_varargs = num_varargs; - *varargs = ZEND_CALL_ARG(EG(current_execute_data)->call, i + 1); + *varargs = ZEND_CALL_ARG(EG(current_execute_data), i + 1); /* adjust how many args we have left and restart loop */ num_args += 1 - num_varargs; i += num_varargs; @@ -895,7 +895,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, } } - arg = ZEND_CALL_ARG(EG(current_execute_data)->call, i + 1); + arg = ZEND_CALL_ARG(EG(current_execute_data), i + 1); if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) { /* clean up varargs array if it was used */ @@ -966,7 +966,7 @@ ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr * Z_OBJ(EG(This)) to NULL when calling an internal function with common.scope == NULL. * In that case EG(This) would still be the $this from the calling code and we'd take the * wrong branch here. */ - zend_bool is_method = EG(current_execute_data)->call->func->common.scope != NULL; + zend_bool is_method = EG(current_execute_data)->func->common.scope != NULL; if (!is_method || !this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) { RETURN_IF_ZERO_ARGS(num_args, p, 0); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index df81c5d666..d6ca5c76d5 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -394,7 +394,7 @@ ZEND_FUNCTION(gc_disable) Get the number of arguments that were passed to the function */ ZEND_FUNCTION(func_num_args) { - zend_execute_data *ex = EG(current_execute_data); + zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; if (ex->frame_kind == VM_FRAME_NESTED_FUNCTION || ex->frame_kind == VM_FRAME_TOP_FUNCTION) { RETURN_LONG(ex->num_args); @@ -423,7 +423,7 @@ ZEND_FUNCTION(func_get_arg) RETURN_FALSE; } - ex = EG(current_execute_data); + ex = EG(current_execute_data)->prev_execute_data; if (ex->frame_kind != VM_FRAME_NESTED_FUNCTION && ex->frame_kind != VM_FRAME_TOP_FUNCTION) { zend_error(E_WARNING, "func_get_arg(): Called from the global scope - no function context"); RETURN_FALSE; @@ -456,7 +456,7 @@ ZEND_FUNCTION(func_get_args) zval *p; int arg_count, first_extra_arg; int i; - zend_execute_data *ex = EG(current_execute_data); + zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; if (ex->frame_kind != VM_FRAME_NESTED_FUNCTION && ex->frame_kind != VM_FRAME_TOP_FUNCTION) { zend_error(E_WARNING, "func_get_args(): Called from the global scope - no function context"); @@ -2054,7 +2054,7 @@ ZEND_FUNCTION(debug_print_backtrace) } ZVAL_UNDEF(&arg_array); - ptr = EG(current_execute_data); + ptr = EG(current_execute_data)->prev_execute_data; /* skip debug_backtrace() */ object = ptr->object; @@ -2078,7 +2078,15 @@ ZEND_FUNCTION(debug_print_backtrace) if (skip->func && ZEND_USER_CODE(skip->func->common.type)) { filename = skip->func->op_array.filename->val; - lineno = skip->opline->lineno; + if (skip->opline->opcode == ZEND_HANDLE_EXCEPTION) { + if (EG(opline_before_exception)) { + lineno = EG(opline_before_exception)->lineno; + } else { + lineno = skip->func->op_array.line_end; + } + } else { + lineno = skip->opline->lineno; + } } else { filename = NULL; lineno = 0; @@ -2223,17 +2231,22 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int zval stack_frame; ptr = EG(current_execute_data); - - /* skip "new Exception()" */ - if (ptr && (skip_last == 0) && ptr->opline && (ptr->opline->opcode == ZEND_NEW)) { - object = ptr->object; + if (!ptr->opline) { ptr = ptr->prev_execute_data; } - /* skip debug_backtrace() */ - if (skip_last-- && ptr) { - object = ptr->object; - ptr = ptr->prev_execute_data; + if (ptr) { + if (skip_last) { + /* skip debug_backtrace() */ + object = ptr->object; + ptr = ptr->prev_execute_data; + } else { + /* skip "new Exception()" */ + if (ptr->opline && (ptr->opline->opcode == ZEND_NEW)) { + object = ptr->object; + ptr = ptr->prev_execute_data; + } + } } array_init(return_value); @@ -2254,7 +2267,15 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int if (skip->func && ZEND_USER_CODE(skip->func->common.type)) { filename = skip->func->op_array.filename->val; - lineno = skip->opline->lineno; + if (skip->opline->opcode == ZEND_HANDLE_EXCEPTION) { + if (EG(opline_before_exception)) { + lineno = EG(opline_before_exception)->lineno; + } else { + lineno = skip->func->op_array.line_end; + } + } else { + lineno = skip->opline->lineno; + } add_assoc_string_ex(&stack_frame, "file", sizeof("file")-1, (char*)filename); add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, lineno); diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 053a5eb199..29c1328f2c 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -47,7 +47,7 @@ static zend_object_handlers closure_handlers; ZEND_METHOD(Closure, __invoke) /* {{{ */ { - zend_function *func = EG(current_execute_data)->call->func; + zend_function *func = EG(current_execute_data)->func; zval *arguments; arguments = emalloc(sizeof(zval) * ZEND_NUM_ARGS()); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 5318bbe2d3..1500640f9b 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -546,7 +546,7 @@ ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zen ZVAL_UNDEF(arg); } - if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { + if (zf->common.type == ZEND_USER_FUNCTION && ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->func->op_array.filename->val, ptr->opline->lineno); } else { zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind); diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 40f42ae2dd..9bcdbc3f30 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -272,35 +272,6 @@ static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data * } } -static zend_always_inline int zend_vm_stack_get_args_count_ex(zend_execute_data *ex) -{ - return ex->call->num_args; -} - -static zend_always_inline zval* zend_vm_stack_get_arg_ex(zend_execute_data *ex, int requested_arg) -{ - int arg_count = ex->call->num_args; - - if (UNEXPECTED(requested_arg > arg_count)) { - return NULL; - } - return ZEND_CALL_ARG(ex->call, requested_arg); -} - -static zend_always_inline int zend_vm_stack_get_args_count(TSRMLS_D) -{ - if (EG(current_execute_data)->prev_execute_data) { - return zend_vm_stack_get_args_count_ex(EG(current_execute_data)->prev_execute_data); - } else { - return 0; - } -} - -static zend_always_inline zval* zend_vm_stack_get_arg(int requested_arg TSRMLS_DC) -{ - return zend_vm_stack_get_arg_ex(EG(current_execute_data)->prev_execute_data, requested_arg); -} - void execute_new_code(TSRMLS_D); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 2ba582942a..e91812d195 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -401,11 +401,7 @@ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ return ""; } - if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { - func = EG(current_execute_data)->call->func; - } else { - func = EG(current_execute_data)->func; - } + func = EG(current_execute_data)->func; switch (func->type) { case ZEND_USER_FUNCTION: case ZEND_INTERNAL_FUNCTION: @@ -433,11 +429,7 @@ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ if (!zend_is_executing(TSRMLS_C)) { return NULL; } - if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { - func = EG(current_execute_data)->call->func; - } else { - func = EG(current_execute_data)->func; - } + func = EG(current_execute_data)->func; switch (func->type) { case ZEND_USER_FUNCTION: { zend_string *function_name = func->common.function_name; @@ -667,9 +659,11 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_op **original_opline_ptr; zend_class_entry *calling_scope = NULL; zend_class_entry *called_scope = NULL; - zend_execute_data execute_data; + zend_execute_data *call, dummy_execute_data; zend_fcall_info_cache fci_cache_local; zend_function *func; + zend_object *orig_object; + zend_class_entry *orig_scope, *orig_called_scope; zval tmp; ZVAL_UNDEF(fci->retval); @@ -690,20 +684,28 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS break; } + orig_object = Z_OBJ(EG(This)); + orig_scope = EG(scope); + orig_called_scope = EG(called_scope); + /* Initialize execute_data */ - if (EG(current_execute_data)) { - execute_data = *EG(current_execute_data); - EX(object) = Z_OBJ(EG(This)); - EX(scope) = EG(scope); - EX(called_scope) = EG(called_scope); - EX(func) = NULL; - EX(opline) = NULL; - } else { + if (!EG(current_execute_data)) { /* This only happens when we're called outside any execute()'s * It shouldn't be strictly necessary to NULL execute_data out, * but it may make bugs easier to spot */ - memset(&execute_data, 0, sizeof(zend_execute_data)); + memset(&dummy_execute_data, 0, sizeof(zend_execute_data)); + EG(current_execute_data) = &dummy_execute_data; + } else if (EG(current_execute_data)->opline && + EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL) { + /* Insert fake frame in case of include or magic calls */ + dummy_execute_data = *EG(current_execute_data); + dummy_execute_data.prev_execute_data = EG(current_execute_data); + dummy_execute_data.call = NULL; + dummy_execute_data.prev_nested_call = NULL; + dummy_execute_data.opline = NULL; + dummy_execute_data.func = NULL; + EG(current_execute_data) = &dummy_execute_data; } if (!fci_cache || !fci_cache->initialized) { @@ -722,6 +724,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS if (callable_name) { STR_RELEASE(callable_name); } + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } return FAILURE; } else if (error) { /* Capitalize the first latter of the error message */ @@ -735,13 +740,16 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } func = fci_cache->function_handler; - EX(call) = zend_vm_stack_push_call_frame(func, fci->param_count, ZEND_CALL_DONE, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC); + call = zend_vm_stack_push_call_frame(func, fci->param_count, ZEND_CALL_DONE, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC); calling_scope = fci_cache->calling_scope; called_scope = fci_cache->called_scope; fci->object = fci_cache->object; if (fci->object && (!EG(objects_store).object_buckets || !IS_OBJ_VALID(EG(objects_store).object_buckets[fci->object->handle]))) { + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } return FAILURE; } @@ -783,16 +791,19 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { if (i) { /* hack to clean up the stack */ - EX(call)->num_args = i; - zend_vm_stack_free_args(EX(call) TSRMLS_CC); + call->num_args = i; + zend_vm_stack_free_args(call TSRMLS_CC); } - zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC); + zend_vm_stack_free_call_frame(call TSRMLS_CC); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, func->common.scope ? func->common.scope->name->val : "", func->common.scope ? "::" : "", func->common.function_name->val); + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } return FAILURE; } @@ -808,33 +819,33 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } else if (Z_REFCOUNTED(fci->params[i])) { Z_ADDREF(fci->params[i]); } - param = ZEND_CALL_ARG(EX(call), i+1); + param = ZEND_CALL_ARG(call, i+1); ZVAL_COPY_VALUE(param, &fci->params[i]); } else if (Z_ISREF(fci->params[i]) && /* don't separate references for __call */ (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) { param = &tmp; - param = ZEND_CALL_ARG(EX(call), i+1); + param = ZEND_CALL_ARG(call, i+1); ZVAL_DUP(param, Z_REFVAL(fci->params[i])); } else { - param = ZEND_CALL_ARG(EX(call), i+1); + param = ZEND_CALL_ARG(call, i+1); ZVAL_COPY(param, &fci->params[i]); } } - EX(call)->num_args = fci->param_count; + call->num_args = fci->param_count; EG(scope) = calling_scope; EG(called_scope) = called_scope; if (!fci->object || (func->common.fn_flags & ZEND_ACC_STATIC)) { - Z_OBJ(EG(This)) = EX(call)->object = NULL; + Z_OBJ(EG(This)) = call->object = NULL; } else { Z_OBJ(EG(This)) = fci->object; Z_ADDREF(EG(This)); } - EX(prev_execute_data) = EG(current_execute_data); - EG(current_execute_data) = &execute_data; + call->prev_nested_call = EG(current_execute_data)->call; + EG(current_execute_data)->call = call; if (func->type == ZEND_USER_FUNCTION) { calling_symbol_table = EG(active_symbol_table); @@ -867,14 +878,20 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS if (func->common.scope) { EG(scope) = func->common.scope; } + call->opline = NULL; + call->call = NULL; + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; if (EXPECTED(zend_execute_internal == NULL)) { /* saves one function call if zend_execute_internal is not used */ func->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC); } else { - zend_execute_internal(&execute_data, fci TSRMLS_CC); + zend_execute_internal(call->prev_execute_data, fci TSRMLS_CC); } - zend_vm_stack_free_args(EX(call) TSRMLS_CC); - zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC); + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call TSRMLS_CC); + EG(current_execute_data)->call = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); /* We shouldn't fix bad extensions here, because it can break proper ones (Bug #34045) @@ -896,11 +913,20 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS /* Not sure what should be done here if it's a static method */ if (fci->object) { + call->opline = NULL; + call->call = NULL; + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; fci->object->handlers->call_method(func->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC); + EG(current_execute_data) = call->prev_execute_data; } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } + zend_vm_stack_free_args(call TSRMLS_CC); + EG(current_execute_data)->call = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { STR_RELEASE(func->common.function_name); } @@ -916,10 +942,12 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zval_ptr_dtor(&EG(This)); } - Z_OBJ(EG(This)) = EX(object); - EG(scope) = EX(scope); - EG(called_scope) = EX(called_scope); - EG(current_execute_data) = EX(prev_execute_data); + Z_OBJ(EG(This)) = orig_object; + EG(scope) = orig_scope; + EG(called_scope) = orig_called_scope; + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } if (EG(exception)) { zend_throw_exception_internal(NULL TSRMLS_CC); @@ -1689,10 +1717,15 @@ ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force TSRMLS if (!EG(active_symbol_table)) { int i; zend_execute_data *execute_data = EG(current_execute_data); - zend_op_array *op_array = &execute_data->func->op_array; + zend_op_array *op_array; zend_ulong h = STR_HASH_VAL(name); - if (op_array) { + while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) { + execute_data = execute_data->prev_execute_data; + } + + if (execute_data && execute_data->func) { + op_array = &execute_data->func->op_array; for (i = 0; i < op_array->last_var; i++) { if (op_array->vars[i]->h == h && op_array->vars[i]->len == name->len && @@ -1722,10 +1755,15 @@ ZEND_API int zend_set_local_var_str(const char *name, int len, zval *value, int if (!EG(active_symbol_table)) { int i; zend_execute_data *execute_data = EG(current_execute_data); - zend_op_array *op_array = &execute_data->func->op_array; + zend_op_array *op_array; zend_ulong h = zend_hash_func(name, len); - if (op_array) { + while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) { + execute_data = execute_data->prev_execute_data; + } + + if (execute_data && execute_data->func) { + op_array = &execute_data->func->op_array; for (i = 0; i < op_array->last_var; i++) { if (op_array->vars[i]->h == h && op_array->vars[i]->len == len && diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index f4847b0839..a487e2016a 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -321,7 +321,6 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ zend_class_entry *original_scope = EG(scope); zend_class_entry *original_called_scope = EG(called_scope); zend_vm_stack original_stack = EG(argument_stack); - zend_execute_data *prev_execute_data; original_This = Z_OBJ(EG(This)); @@ -339,17 +338,10 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ * called from whatever method we are current running (e.g. next()). * So we have to link generator call frame with caller call frames */ - prev_execute_data = original_execute_data; - if (prev_execute_data && - prev_execute_data->call && - (prev_execute_data->call->flags & ZEND_CALL_DONE)) { - prev_execute_data->call->prev_execute_data = prev_execute_data; - prev_execute_data = prev_execute_data->call; - } - generator->execute_data->prev_execute_data = prev_execute_data; - if (prev_execute_data) { - generator->execute_data->prev_nested_call = prev_execute_data->call; - prev_execute_data->call = generator->execute_data; + generator->execute_data->prev_execute_data = original_execute_data; + if (original_execute_data) { + generator->execute_data->prev_nested_call = original_execute_data->call; + original_execute_data->call = generator->execute_data; } /* Resume execution */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index e38fbfc640..8a43e054e9 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -905,7 +905,7 @@ static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { - zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->call->func; + zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->func; zval method_name, method_args; zval method_result; zend_class_entry *ce = Z_OBJCE_P(getThis()); @@ -1123,7 +1123,7 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { - zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->call->func; + zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->func; zval method_name, method_args; zval method_result; zend_class_entry *ce = EG(scope); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f0da4eeded..b2d920d753 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1774,8 +1774,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) vm_frame_kind frame_kind = EX(frame_kind); zend_execute_data *prev_nested_call; - EG(current_execute_data) = EX(prev_execute_data); - if (frame_kind == VM_FRAME_NESTED_FUNCTION) { i_free_compiled_variables(execute_data TSRMLS_CC); if (UNEXPECTED(EX(symbol_table) != NULL)) { @@ -1784,6 +1782,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(func)->op_array.prototype) { zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } + EG(current_execute_data) = EX(prev_execute_data); prev_nested_call = EX(prev_nested_call); zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); @@ -1829,6 +1828,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) zend_detach_symbol_table(execute_data); destroy_op_array(&EX(func)->op_array TSRMLS_CC); efree(EX(func)); + EG(current_execute_data) = EX(prev_execute_data); prev_nested_call = EX(prev_nested_call); zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); @@ -1868,6 +1868,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if ((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) && EX(func)->op_array.prototype) { zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } + EG(current_execute_data) = EX(prev_execute_data); prev_nested_call = EX(prev_nested_call); zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); @@ -2627,6 +2628,11 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) EG(called_scope) = call->called_scope; } + call->opline = NULL; + call->call = NULL; + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { zend_uint i; zval *p = ZEND_CALL_ARG(call, 1); @@ -2636,6 +2642,10 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) p++; } if (UNEXPECTED(EG(exception) != NULL)) { + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call TSRMLS_CC); + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); } @@ -2657,9 +2667,8 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) } else { zend_execute_internal(execute_data, NULL TSRMLS_CC); } - + EG(current_execute_data) = call->prev_execute_data; zend_vm_stack_free_args(call TSRMLS_CC); - EX(call) = call->prev_nested_call; zend_vm_stack_free_call_frame(call TSRMLS_CC); @@ -2721,7 +2730,12 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) /* Not sure what should be done here if it's a static method */ if (EXPECTED(call->object != NULL)) { + call->opline = NULL; + call->call = NULL; + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; call->object->handlers->call_method(fbc->common.function_name, call->object, call->num_args, EX_VAR(opline->result.var) TSRMLS_CC); + EG(current_execute_data) = call->prev_execute_data; } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3f373a1a98..2543e252c0 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -397,8 +397,6 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) vm_frame_kind frame_kind = EX(frame_kind); zend_execute_data *prev_nested_call; - EG(current_execute_data) = EX(prev_execute_data); - if (frame_kind == VM_FRAME_NESTED_FUNCTION) { i_free_compiled_variables(execute_data TSRMLS_CC); if (UNEXPECTED(EX(symbol_table) != NULL)) { @@ -407,6 +405,7 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(func)->op_array.prototype) { zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } + EG(current_execute_data) = EX(prev_execute_data); prev_nested_call = EX(prev_nested_call); zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); @@ -452,6 +451,7 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) zend_detach_symbol_table(execute_data); destroy_op_array(&EX(func)->op_array TSRMLS_CC); efree(EX(func)); + EG(current_execute_data) = EX(prev_execute_data); prev_nested_call = EX(prev_nested_call); zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); @@ -491,6 +491,7 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) if ((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) && EX(func)->op_array.prototype) { zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } + EG(current_execute_data) = EX(prev_execute_data); prev_nested_call = EX(prev_nested_call); zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); @@ -579,6 +580,11 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EG(called_scope) = call->called_scope; } + call->opline = NULL; + call->call = NULL; + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { zend_uint i; zval *p = ZEND_CALL_ARG(call, 1); @@ -588,6 +594,10 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) p++; } if (UNEXPECTED(EG(exception) != NULL)) { + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call TSRMLS_CC); + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); } @@ -609,9 +619,8 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { zend_execute_internal(execute_data, NULL TSRMLS_CC); } - + EG(current_execute_data) = call->prev_execute_data; zend_vm_stack_free_args(call TSRMLS_CC); - EX(call) = call->prev_nested_call; zend_vm_stack_free_call_frame(call TSRMLS_CC); @@ -673,7 +682,12 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Not sure what should be done here if it's a static method */ if (EXPECTED(call->object != NULL)) { + call->opline = NULL; + call->call = NULL; + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; call->object->handlers->call_method(fbc->common.function_name, call->object, call->num_args, EX_VAR(opline->result.var) TSRMLS_CC); + EG(current_execute_data) = call->prev_execute_data; } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); }