From 65e2ed6e50d210adb50de47ef7ac3b75af069f62 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 24 Apr 2014 15:53:20 +0400 Subject: [PATCH] Redesigned zend_execute_data layout now EX(object), EX(scope) and EX(called_scope) arr properties of the current function execution co ntext. They are set during zend_execute_data initialization and never changed. --- Zend/zend_builtin_functions.c | 45 +++++++++--- Zend/zend_compile.h | 25 +++---- Zend/zend_execute.c | 68 +++++++++-------- Zend/zend_execute_API.c | 34 +++------ Zend/zend_generators.c | 17 ++--- Zend/zend_vm_def.h | 131 ++++++++++++++++++++------------- Zend/zend_vm_execute.h | 134 ++++++++++++++++++++-------------- sapi/phpdbg/phpdbg.c | 1 - sapi/phpdbg/phpdbg_frame.c | 12 +-- 9 files changed, 257 insertions(+), 210 deletions(-) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 22076104f0..1d066deb41 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1991,6 +1991,7 @@ void debug_print_backtrace_args(zval *arg_array TSRMLS_DC) ZEND_FUNCTION(debug_print_backtrace) { zend_execute_data *ptr, *skip; + zend_object *object; int lineno, frameno = 0; const char *function_name; const char *filename; @@ -2010,6 +2011,7 @@ ZEND_FUNCTION(debug_print_backtrace) ptr = EG(current_execute_data); /* skip debug_backtrace() */ + object = ptr->object; ptr = ptr->prev_execute_data; while (ptr && (limit == 0 || frameno < limit)) { @@ -2037,11 +2039,18 @@ ZEND_FUNCTION(debug_print_backtrace) lineno = 0; } + /* $this may be passed into regular internal functions */ + if (object && + ptr->function_state.function->type == ZEND_INTERNAL_FUNCTION && + !ptr->function_state.function->common.scope) { + object = NULL; + } + function_name = (ptr->function_state.function->common.scope && ptr->function_state.function->common.scope->trait_aliases) ? zend_resolve_method_name( - ptr->object ? - zend_get_class_entry(ptr->object TSRMLS_CC) : + object ? + zend_get_class_entry(object TSRMLS_CC) : ptr->function_state.function->common.scope, ptr->function_state.function)->val : (ptr->function_state.function->common.function_name ? @@ -2049,11 +2058,11 @@ ZEND_FUNCTION(debug_print_backtrace) NULL); if (function_name) { - if (ptr->object) { + if (object) { if (ptr->function_state.function->common.scope) { class_name = ptr->function_state.function->common.scope->name; } else { - class_name = zend_get_object_classname(ptr->object TSRMLS_CC); + class_name = zend_get_object_classname(object TSRMLS_CC); } call_type = "->"; @@ -2141,6 +2150,7 @@ ZEND_FUNCTION(debug_print_backtrace) } } include_filename = filename; + object = skip->object; ptr = skip->prev_execute_data; ++indent; } @@ -2151,6 +2161,7 @@ ZEND_FUNCTION(debug_print_backtrace) ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit TSRMLS_DC) { zend_execute_data *ptr, *skip; + zend_object *object = Z_OBJ(EG(This)); int lineno, frameno = 0; const char *function_name; const char *filename; @@ -2162,11 +2173,13 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int /* skip "new Exception()" */ if (ptr && (skip_last == 0) && ptr->opline && (ptr->opline->opcode == ZEND_NEW)) { + object = ptr->object; ptr = ptr->prev_execute_data; } /* skip debug_backtrace() */ if (skip_last-- && ptr) { + object = ptr->object; ptr = ptr->prev_execute_data; } @@ -2217,11 +2230,18 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int filename = NULL; } + /* $this may be passed into regular internal functions */ + if (object && + ptr->function_state.function->type == ZEND_INTERNAL_FUNCTION && + !ptr->function_state.function->common.scope) { + object = NULL; + } + function_name = (ptr->function_state.function->common.scope && ptr->function_state.function->common.scope->trait_aliases) ? zend_resolve_method_name( - ptr->object ? - zend_get_class_entry(ptr->object TSRMLS_CC) : + object ? + zend_get_class_entry(object TSRMLS_CC) : ptr->function_state.function->common.scope, ptr->function_state.function)->val : (ptr->function_state.function->common.function_name ? @@ -2231,19 +2251,19 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int if (function_name) { add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char*)function_name); - if (ptr->object) { + if (object) { if (ptr->function_state.function->common.scope) { add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(ptr->function_state.function->common.scope->name)); } else { - class_name = zend_get_object_classname(ptr->object TSRMLS_CC); + class_name = zend_get_object_classname(object TSRMLS_CC); add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(class_name)); } if ((options & DEBUG_BACKTRACE_PROVIDE_OBJECT) != 0) { - zval object; - ZVAL_OBJ(&object, ptr->object); - add_assoc_zval_ex(&stack_frame, "object", sizeof("object")-1, &object); - Z_ADDREF(object); + zval zv; + ZVAL_OBJ(&zv, object); + add_assoc_zval_ex(&stack_frame, "object", sizeof("object")-1, &zv); + Z_ADDREF(zv); } add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "->"); @@ -2314,6 +2334,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int include_filename = filename; + object = skip->object; ptr = skip->prev_execute_data; } } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 35559a21d4..24f06c426f 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -374,20 +374,19 @@ typedef enum _vm_frame_kind { } vm_frame_kind; struct _zend_execute_data { - struct _zend_op *opline; - void **run_time_cache; - zend_function_state function_state; - zend_op_array *op_array; - zend_object *object; - zend_array *symbol_table; - struct _zend_execute_data *prev_execute_data; + struct _zend_op *opline; /* executed opline */ + zend_op_array *op_array; /* executed op_array */ + zend_function_state function_state; /* called function and arguments */ + zend_object *object; /* current $this */ + zend_class_entry *scope; /* function scope (self) */ + zend_class_entry *called_scope; /* function called scope (static) */ + zend_array *symbol_table; + void **run_time_cache; + zend_execute_data *prev_execute_data; + zval *return_value; + vm_frame_kind frame_kind; + // TODO: simplify call sequence and remove call_* ??? zval old_error_reporting; - vm_frame_kind frame_kind; - zval *return_value; - // TODO: simplify call sequence and remove current_* and call_* ??? - zend_class_entry *current_scope; - zend_class_entry *current_called_scope; - zend_object *current_this; struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */ zend_object *delayed_exception; call_slot *call_slots; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 2866f841d6..2dc3c22414 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1624,52 +1624,50 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array EX(prev_execute_data) = EG(current_execute_data); } - do { - /* Initialize CV variables */ - zval *var = EX_VAR_NUM(0); - zval *end = var + op_array->last_var; - - while (var != end) { - ZVAL_UNDEF(var); - var++; - } - } while (0); - + EX(return_value) = return_value; + EX(frame_kind) = frame_kind; + ZVAL_UNDEF(&EX(old_error_reporting)); + EX(delayed_exception) = NULL; EX(call_slots) = (call_slot*)((char *)execute_data + execute_data_size + vars_size); + EX(call) = NULL; - + EG(opline_ptr) = &EX(opline); + EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; + EX(function_state).function = (zend_function *) op_array; + EX(function_state).arguments = NULL; EX(op_array) = op_array; - - EG(argument_stack)->top = (zval*)zend_vm_stack_frame_base(execute_data); - - EX(object) = NULL; - EX(current_this) = NULL; - ZVAL_UNDEF(&EX(old_error_reporting)); + EX(object) = Z_OBJ(EG(This)); + EX(scope) = EG(scope); + EX(called_scope) = EG(called_scope); EX(symbol_table) = EG(active_symbol_table); - EX(call) = NULL; - EG(current_execute_data) = execute_data; - EX(frame_kind) = frame_kind; - EX(delayed_exception) = NULL; - EX(return_value) = return_value; - - if (!op_array->run_time_cache && op_array->last_cache_slot) { - op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); - } - EX(run_time_cache) = op_array->run_time_cache; if (EX(symbol_table)) { zend_attach_symbol_table(execute_data); - } + } else { + do { + /* Initialize CV variables */ + zval *var = EX_VAR_NUM(0); + zval *end = var + op_array->last_var; + + while (var != end) { + ZVAL_UNDEF(var); + var++; + } + } while (0); - if (op_array->this_var != -1 && Z_OBJ(EG(This))) { - ZVAL_COPY(EX_VAR(op_array->this_var), &EG(This)); + if (op_array->this_var != -1 && Z_OBJ(EG(This))) { + ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EG(This))); + Z_ADDREF(EG(This)); + } } - EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; - EG(opline_ptr) = &EX(opline); + if (!op_array->run_time_cache && op_array->last_cache_slot) { + op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); + } + EX(run_time_cache) = op_array->run_time_cache; - EX(function_state).function = (zend_function *) op_array; - EX(function_state).arguments = NULL; + EG(argument_stack)->top = (zval*)zend_vm_stack_frame_base(execute_data); + EG(current_execute_data) = execute_data; return execute_data; } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 0091fea00d..d2fefa7f71 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -770,11 +770,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_array *calling_symbol_table; zend_op_array *original_op_array; zend_op **original_opline_ptr; - zend_class_entry *current_scope; - zend_class_entry *current_called_scope; zend_class_entry *calling_scope = NULL; zend_class_entry *called_scope = NULL; - zend_object *current_this; zend_execute_data execute_data; zend_fcall_info_cache fci_cache_local; zval tmp; @@ -800,9 +797,11 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS /* 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(op_array) = NULL; EX(opline) = NULL; - EX(object) = NULL; } else { /* This only happens when we're called outside any execute()'s * It shouldn't be strictly necessary to NULL execute_data out, @@ -842,7 +841,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS EX(function_state).function = fci_cache->function_handler; calling_scope = fci_cache->calling_scope; called_scope = fci_cache->called_scope; - EX(object) = fci->object = fci_cache->object; + fci->object = fci_cache->object; if (fci->object && (!EG(objects_store).object_buckets || !IS_OBJ_VALID(EG(objects_store).object_buckets[fci->object->handle]))) { @@ -916,18 +915,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS ZVAL_LONG(&tmp, fci->param_count); zend_vm_stack_push(&tmp TSRMLS_CC); - current_scope = EG(scope); EG(scope) = calling_scope; - - current_this = Z_OBJ(EG(This)); - - current_called_scope = EG(called_scope); - if (called_scope) { - EG(called_scope) = called_scope; - } else if (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION) { - EG(called_scope) = NULL; - } - + EG(called_scope) = called_scope; if (!fci->object || (EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { Z_OBJ(EG(This)) = NULL; @@ -1016,9 +1005,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS if (Z_OBJ(EG(This))) { zval_ptr_dtor(&EG(This)); } - EG(called_scope) = current_called_scope; - EG(scope) = current_scope; - Z_OBJ(EG(This)) = current_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); if (EG(exception)) { @@ -1711,12 +1701,6 @@ ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ } ex->symbol_table = EG(active_symbol_table); - - if (ex->op_array->this_var != -1 && - Z_TYPE_P(EX_VAR_2(ex, ex->op_array->this_var)) == IS_UNDEF && - Z_OBJ(EG(This))) { - ZVAL_COPY_VALUE(EX_VAR_2(ex, ex->op_array->this_var), &EG(This)); - } for (i = 0; i < ex->op_array->last_var; i++) { zval zv; diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 74df4cdb7b..0f19e84041 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -118,8 +118,8 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished zend_clean_and_cache_symbol_table(execute_data->symbol_table TSRMLS_CC); } - if (execute_data->current_this) { - OBJ_RELEASE(execute_data->current_this); + if (execute_data->object) { + OBJ_RELEASE(execute_data->object); } /* A fatal error / die occurred during the generator execution. Trying to clean @@ -298,13 +298,8 @@ ZEND_API void zend_generator_create_zval(zend_op_array *op_array, zval *return_v Z_ADDREF(EG(This)); } - /* Back up executor globals. */ - execute_data->current_scope = EG(scope); - execute_data->current_called_scope = EG(called_scope); - execute_data->symbol_table = EG(active_symbol_table); - execute_data->current_this = Z_OBJ(EG(This)); - /* Save execution context in generator object. */ + execute_data->prev_execute_data->object = Z_OBJ_P(return_value); generator = (zend_generator *) Z_OBJ_P(return_value); generator->execute_data = execute_data; generator->stack = EG(argument_stack); @@ -355,9 +350,9 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ EG(opline_ptr) = &generator->execute_data->opline; EG(active_op_array) = generator->execute_data->op_array; EG(active_symbol_table) = generator->execute_data->symbol_table; - Z_OBJ(EG(This)) = generator->execute_data->current_this; - EG(scope) = generator->execute_data->current_scope; - EG(called_scope) = generator->execute_data->current_called_scope; + Z_OBJ(EG(This)) = generator->execute_data->object; + EG(scope) = generator->execute_data->scope; + EG(called_scope) = generator->execute_data->called_scope; EG(argument_stack) = generator->stack; /* We want the backtrace to look as if the generator function was diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7808b441fd..2d4771c004 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1805,11 +1805,15 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); } } - zval_ptr_dtor(&EG(This)); + if (!Z_DELREF(EG(This))) { + _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); + } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { + gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); + } } - Z_OBJ(EG(This)) = EX(current_this); - EG(scope) = EX(current_scope); - EG(called_scope) = EX(current_called_scope); + Z_OBJ(EG(This)) = EX(object); + EG(scope) = EX(scope); + EG(called_scope) = EX(called_scope); EX(call)--; @@ -1878,12 +1882,12 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) { USE_OPLINE - zend_bool should_change_scope = 0; zend_function *fbc = EX(function_state).function; + zend_object *object; zend_uint num_args; SAVE_OPLINE(); - EX(object) = EX(call)->object; + 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->val, fbc->common.function_name->val); @@ -1900,7 +1904,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) } if (fbc->common.scope && !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !EX(object)) { + !object) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { /* FIXME: output identifiers properly */ @@ -1915,17 +1919,6 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) } } - if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) { - should_change_scope = 1; - EX(current_this) = Z_OBJ(EG(This)); - EX(current_scope) = EG(scope); - EX(current_called_scope) = EG(called_scope); - Z_OBJ(EG(This)) = EX(object); -//??? EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; - EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; - } - if (UNEXPECTED(EX(call)->num_additional_args != 0)) { num_args = opline->extended_value + EX(call)->num_additional_args; EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); @@ -1940,6 +1933,17 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) LOAD_OPLINE(); if (fbc->type == ZEND_INTERNAL_FUNCTION) { + int should_change_scope = 0; + zval *ret; + + if (fbc->common.scope) { + should_change_scope = 1; + Z_OBJ(EG(This)) = object; +//??? EG(scope) = (object) ? NULL : fbc->common.scope; + EG(scope) = fbc->common.scope; + EG(called_scope) = EX(call)->called_scope; + } + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { zend_uint i; zval *p = EX(function_state).arguments - num_args; @@ -1947,30 +1951,44 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) for (i = 0; i < num_args; ++i, ++p) { zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); } + if (UNEXPECTED(EG(exception) != NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + if (UNEXPECTED(should_change_scope)) { + ZEND_VM_C_GOTO(fcall_end_change_scope); + } else { + ZEND_VM_C_GOTO(fcall_end); + } + } } - if (EXPECTED(EG(exception) == NULL)) { - zval *ret = EX_VAR(opline->result.var); + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + if (!zend_execute_internal) { + /* saves one function call if zend_execute_internal is not used */ + fbc->internal_function.handler(num_args, ret TSRMLS_CC); + } else { + zend_execute_internal(execute_data, NULL TSRMLS_CC); + } - if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(num_args, ret TSRMLS_CC); - } else { - zend_execute_internal(execute_data, NULL TSRMLS_CC); - } + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(ret); + } - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(ret); - } - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); + if (UNEXPECTED(should_change_scope)) { + ZEND_VM_C_GOTO(fcall_end_change_scope); + } else { + ZEND_VM_C_GOTO(fcall_end); } } else if (fbc->type == ZEND_USER_FUNCTION) { zval *return_value = NULL; + Z_OBJ(EG(This)) = object; + EG(scope) = fbc->common.scope; + EG(called_scope) = EX(call)->called_scope; EG(active_symbol_table) = NULL; EG(active_op_array) = &fbc->op_array; if (RETURN_VALUE_USED(opline)) { @@ -2000,11 +2018,16 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ + Z_OBJ(EG(This)) = object; +//??? EG(scope) = NULL; + EG(scope) = fbc->common.scope; + EG(called_scope) = EX(call)->called_scope; + ZVAL_NULL(EX_VAR(opline->result.var)); /* Not sure what should be done here if it's a static method */ - if (EXPECTED(EX(object) != NULL)) { - EX(object)->handlers->call_method(fbc->common.function_name, EX(object), num_args, EX_VAR(opline->result.var) TSRMLS_CC); + if (EXPECTED(object != NULL)) { + object->handlers->call_method(fbc->common.function_name, object, num_args, EX_VAR(opline->result.var) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } @@ -2023,26 +2046,31 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) } } - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - - if (should_change_scope) { - if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { - Z_DELREF(EG(This)); - } - if (Z_REFCOUNT(EG(This)) == 1) { - zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); - } +ZEND_VM_C_LABEL(fcall_end_change_scope): + if (Z_OBJ(EG(This))) { + if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { + if (EX(call)->is_ctor_result_used) { + Z_DELREF(EG(This)); + } + if (Z_REFCOUNT(EG(This)) == 1) { + zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); } - zval_ptr_dtor(&EG(This)); } - Z_OBJ(EG(This)) = EX(current_this); - EG(scope) = EX(current_scope); - EG(called_scope) = EX(current_called_scope); + if (!Z_DELREF(EG(This))) { + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; + _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); + } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { + gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); + } } + Z_OBJ(EG(This)) = EX(object); + EG(scope) = EX(scope); + EG(called_scope) = EX(called_scope); +ZEND_VM_C_LABEL(fcall_end): + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; EX(call)--; zend_vm_stack_clear_multiple(1 TSRMLS_CC); @@ -3923,7 +3951,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) } EX(function_state).function = (zend_function *) new_op_array; - EX(object) = NULL; if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c0ff942e20..1ec6d97343 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -414,11 +414,15 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); } } - zval_ptr_dtor(&EG(This)); + if (!Z_DELREF(EG(This))) { + _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); + } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { + gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); + } } - Z_OBJ(EG(This)) = EX(current_this); - EG(scope) = EX(current_scope); - EG(called_scope) = EX(current_called_scope); + Z_OBJ(EG(This)) = EX(object); + EG(scope) = EX(scope); + EG(called_scope) = EX(called_scope); EX(call)--; @@ -487,12 +491,12 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_bool should_change_scope = 0; zend_function *fbc = EX(function_state).function; + zend_object *object; zend_uint num_args; SAVE_OPLINE(); - EX(object) = EX(call)->object; + 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->val, fbc->common.function_name->val); @@ -509,7 +513,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } if (fbc->common.scope && !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !EX(object)) { + !object) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { /* FIXME: output identifiers properly */ @@ -524,17 +528,6 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } } - if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) { - should_change_scope = 1; - EX(current_this) = Z_OBJ(EG(This)); - EX(current_scope) = EG(scope); - EX(current_called_scope) = EG(called_scope); - Z_OBJ(EG(This)) = EX(object); -//??? EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; - EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; - } - if (UNEXPECTED(EX(call)->num_additional_args != 0)) { num_args = opline->extended_value + EX(call)->num_additional_args; EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); @@ -549,6 +542,17 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR LOAD_OPLINE(); if (fbc->type == ZEND_INTERNAL_FUNCTION) { + int should_change_scope = 0; + zval *ret; + + if (fbc->common.scope) { + should_change_scope = 1; + Z_OBJ(EG(This)) = object; +//??? EG(scope) = (object) ? NULL : fbc->common.scope; + EG(scope) = fbc->common.scope; + EG(called_scope) = EX(call)->called_scope; + } + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { zend_uint i; zval *p = EX(function_state).arguments - num_args; @@ -556,30 +560,44 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR for (i = 0; i < num_args; ++i, ++p) { zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); } + if (UNEXPECTED(EG(exception) != NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + if (UNEXPECTED(should_change_scope)) { + goto fcall_end_change_scope; + } else { + goto fcall_end; + } + } } - if (EXPECTED(EG(exception) == NULL)) { - zval *ret = EX_VAR(opline->result.var); + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + if (!zend_execute_internal) { + /* saves one function call if zend_execute_internal is not used */ + fbc->internal_function.handler(num_args, ret TSRMLS_CC); + } else { + zend_execute_internal(execute_data, NULL TSRMLS_CC); + } - if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(num_args, ret TSRMLS_CC); - } else { - zend_execute_internal(execute_data, NULL TSRMLS_CC); - } + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(ret); + } - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(ret); - } - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); + if (UNEXPECTED(should_change_scope)) { + goto fcall_end_change_scope; + } else { + goto fcall_end; } } else if (fbc->type == ZEND_USER_FUNCTION) { zval *return_value = NULL; + Z_OBJ(EG(This)) = object; + EG(scope) = fbc->common.scope; + EG(called_scope) = EX(call)->called_scope; EG(active_symbol_table) = NULL; EG(active_op_array) = &fbc->op_array; if (RETURN_VALUE_USED(opline)) { @@ -609,11 +627,16 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ + Z_OBJ(EG(This)) = object; +//??? EG(scope) = NULL; + EG(scope) = fbc->common.scope; + EG(called_scope) = EX(call)->called_scope; + ZVAL_NULL(EX_VAR(opline->result.var)); /* Not sure what should be done here if it's a static method */ - if (EXPECTED(EX(object) != NULL)) { - EX(object)->handlers->call_method(fbc->common.function_name, EX(object), num_args, EX_VAR(opline->result.var) TSRMLS_CC); + if (EXPECTED(object != NULL)) { + object->handlers->call_method(fbc->common.function_name, object, num_args, EX_VAR(opline->result.var) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } @@ -632,26 +655,31 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } } - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - - if (should_change_scope) { - if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { - Z_DELREF(EG(This)); - } - if (Z_REFCOUNT(EG(This)) == 1) { - zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); - } +fcall_end_change_scope: + if (Z_OBJ(EG(This))) { + if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { + if (EX(call)->is_ctor_result_used) { + Z_DELREF(EG(This)); + } + if (Z_REFCOUNT(EG(This)) == 1) { + zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); } - zval_ptr_dtor(&EG(This)); } - Z_OBJ(EG(This)) = EX(current_this); - EG(scope) = EX(current_scope); - EG(called_scope) = EX(current_called_scope); + if (!Z_DELREF(EG(This))) { + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; + _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); + } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { + gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); + } } + Z_OBJ(EG(This)) = EX(object); + EG(scope) = EX(scope); + EG(called_scope) = EX(called_scope); +fcall_end: + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; EX(call)--; zend_vm_stack_clear_multiple(1 TSRMLS_CC); @@ -2916,7 +2944,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA } EX(function_state).function = (zend_function *) new_op_array; - EX(object) = NULL; if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -7953,7 +7980,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND } EX(function_state).function = (zend_function *) new_op_array; - EX(object) = NULL; if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -13058,7 +13084,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND } EX(function_state).function = (zend_function *) new_op_array; - EX(object) = NULL; if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -29866,7 +29891,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL } EX(function_state).function = (zend_function *) new_op_array; - EX(object) = NULL; if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 64babced64..f20ad3f222 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -613,7 +613,6 @@ const char phpdbg_ini_hardcoded[] = /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */ #define INI_DEFAULT(name, value) \ - Z_SET_REFCOUNT(tmp, 0); \ ZVAL_STRINGL(&tmp, value, sizeof(value) - 1); \ zend_hash_str_update(configuration_hash, name, sizeof(name) - 1, &tmp); diff --git a/sapi/phpdbg/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c index 965e9bc2e2..2c2d9e6177 100644 --- a/sapi/phpdbg/phpdbg_frame.c +++ b/sapi/phpdbg/phpdbg_frame.c @@ -40,9 +40,9 @@ void phpdbg_restore_frame(TSRMLS_D) /* {{{ */ EG(opline_ptr) = &PHPDBG_EX(opline); EG(active_op_array) = PHPDBG_EX(op_array); EG(active_symbol_table) = PHPDBG_EX(symbol_table); - Z_OBJ(EG(This)) = PHPDBG_EX(current_this); - EG(scope) = PHPDBG_EX(current_scope); - EG(called_scope) = PHPDBG_EX(current_called_scope); + Z_OBJ(EG(This)) = PHPDBG_EX(object); + EG(scope) = PHPDBG_EX(scope); + EG(called_scope) = PHPDBG_EX(called_scope); } /* }}} */ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ @@ -82,9 +82,9 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ EG(opline_ptr) = &PHPDBG_EX(opline); EG(active_op_array) = PHPDBG_EX(op_array); EG(active_symbol_table) = PHPDBG_EX(symbol_table); - Z_OBJ(EG(This)) = PHPDBG_EX(current_this); - EG(scope) = PHPDBG_EX(current_scope); - EG(called_scope) = PHPDBG_EX(current_called_scope); + Z_OBJ(EG(This)) = PHPDBG_EX(object); + EG(scope) = PHPDBG_EX(scope); + EG(called_scope) = PHPDBG_EX(called_scope); } phpdbg_notice("Switched to frame #%d", frame); -- 2.50.1