]> granicus.if.org Git - php/commitdiff
Uinified call frame handling for user and internal functions.
authorDmitry Stogov <dmitry@zend.com>
Wed, 2 Jul 2014 18:01:25 +0000 (22:01 +0400)
committerDmitry Stogov <dmitry@zend.com>
Wed, 2 Jul 2014 18:01:25 +0000 (22:01 +0400)
Now EG(current_execute_data) always point to the call frame of the currently executed function.

Zend/zend.h
Zend/zend_API.c
Zend/zend_builtin_functions.c
Zend/zend_closures.c
Zend/zend_execute.c
Zend/zend_execute.h
Zend/zend_execute_API.c
Zend/zend_generators.c
Zend/zend_object_handlers.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index f21ba92d617b266e1018962a6a4b783bcd8ca05f..1ddcdb5aeb54c151dd55f69096f1f1ec63f5daaa 100644 (file)
@@ -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));
index 6b469c2b0a034fe404e11e79626d720984526c75..a1b90836294730259fbf794523e0881c0b9d32cb 100644 (file)
@@ -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);
 
index df81c5d666995de01c6ac6f72cfbc3b322d0bea6..d6ca5c76d59806bf4f5d157a717b1f9d8a235c04 100644 (file)
@@ -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);
 
index 053a5eb199a33f7eb266cabda01260f5102a4530..29c1328f2cbd00cfc1437b3f3f1c27dcb93d9166 100644 (file)
@@ -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());
index 5318bbe2d3b584eb3f0e294a5be0a8bee1a5d27e..1500640f9b684e9c94352fc23db4c21e3d986a69 100644 (file)
@@ -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);
index 40f42ae2dda5ef70f702473ec9ac69a15135aec6..9bcdbc3f30bcde0372894504986a27c4d163a15c 100644 (file)
@@ -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);
 
 
index 2ba582942ab7e58f7087db8e0bde00649983edf4..e91812d1955454f32da2e044b3fc391dc44fba54 100644 (file)
@@ -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 &&
index f4847b0839df2b1c55fb1ae17d9be47aff2b86ca..a487e2016a2e5c8a29da3274920564d68b3aa05c 100644 (file)
@@ -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 */
index e38fbfc6408597287e87423e4950acae354658e3..8a43e054e96611541b6dcd9229db243325bfe6e9 100644 (file)
@@ -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);
index f0da4eeded0f0c28689facb80ce96aff0cc464cd..b2d920d7536313ab2461d9384b8a00de336c8abb 100644 (file)
@@ -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");
                }
index 3f373a1a9807d98d92943787a7d52dbccdb4616b..2543e252c09856033ce6594fdf24bb737b03fdb5 100644 (file)
@@ -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");
                }