]> granicus.if.org Git - php/commitdiff
Avoid unnecessary reference counter incrementation on $this when call methods
authorDmitry Stogov <dmitry@zend.com>
Thu, 7 May 2015 13:28:23 +0000 (16:28 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 7 May 2015 13:28:23 +0000 (16:28 +0300)
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute_API.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 575dbe0803f7a8cd0af1ec7a802a213c0534a923..8c1e49df3d7fbb17b4d3b37d9cf9af2e2ce0e056 100644 (file)
@@ -454,6 +454,7 @@ struct _zend_execute_data {
 #define ZEND_CALL_CTOR               (1 << 3)
 #define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4)
 #define ZEND_CALL_CLOSURE            (1 << 5)
+#define ZEND_CALL_RELEASE_THIS       (1 << 6)
 
 #define ZEND_CALL_INFO(call) \
        (Z_TYPE_INFO((call)->This) >> 24)
index 648b80c069401cf6d887451cad8128c3215a6f04..26415b0d7cfc80856a5402b87a704286f8254e14 100644 (file)
@@ -2067,6 +2067,7 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data
        zend_execute_data *execute_data;
        uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
        size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval);
+       uint32_t call_info;
 
        EG(vm_stack) = zend_vm_stack_new_page(
                EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE(1)) ?
@@ -2076,8 +2077,12 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data
        EG(vm_stack_top) = EG(vm_stack)->top;
        EG(vm_stack_end) = EG(vm_stack)->end;
 
+       call_info = ZEND_CALL_TOP_FUNCTION | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS));
+       if (Z_OBJ(call->This)) {
+               call_info |= ZEND_CALL_RELEASE_THIS;
+       }
        execute_data = zend_vm_stack_push_call_frame(
-               ZEND_CALL_TOP_FUNCTION | (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE),
+               call_info,
                (zend_function*)op_array,
                num_args,
                call->called_scope,
index ab32d9ad12d81b84b89d9f7455d5bec29283ef36..a7ab662c997b066dab08fac74c18f19343704ba6 100644 (file)
@@ -825,12 +825,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
        if (func->common.fn_flags & ZEND_ACC_STATIC) {
                fci->object = NULL;
        }
-       if (!fci->object) {
-               Z_OBJ(call->This) = NULL;
-       } else {
-               Z_OBJ(call->This) = fci->object;
-               GC_REFCOUNT(fci->object)++;
-       }
+       Z_OBJ(call->This) = fci->object;
 
        if (func->type == ZEND_USER_FUNCTION) {
                int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
@@ -868,7 +863,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
                }
                EG(current_execute_data) = call->prev_execute_data;
                zend_vm_stack_free_args(call);
-               zend_vm_stack_free_call_frame(call);
 
                /*  We shouldn't fix bad extensions here,
                        because it can break proper ones (Bug #34045)
@@ -899,7 +893,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
                }
 
                zend_vm_stack_free_args(call);
-               zend_vm_stack_free_call_frame(call);
 
                if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
                        zend_string_release(func->common.function_name);
@@ -912,11 +905,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
                }
        }
 
-       if (fci->object) {
-               OBJ_RELEASE(fci->object);
-       }
-
        EG(scope) = orig_scope;
+       zend_vm_stack_free_call_frame(call);
+
        if (EG(current_execute_data) == &dummy_execute_data) {
                EG(current_execute_data) = dummy_execute_data.prev_execute_data;
        }
index e00ee07d8454cceea284b54af2dac1c9a7ae97d7..3cbd5143a50a4fc3ad501de5e8cb641714da3eec 100644 (file)
@@ -2401,12 +2401,15 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
                if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
                        OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype);
                }
-               object = Z_OBJ(old_execute_data->This);
-               zend_vm_stack_free_call_frame(old_execute_data);
-
-               if (object) {
+               if (call_info & ZEND_CALL_RELEASE_THIS) {
+                       object = Z_OBJ(old_execute_data->This);
+#if 0
                        if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
                                if (!(EX(opline)->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) {
+#else
+                       if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+                               if (!(call_info & ZEND_CALL_CTOR_RESULT_UNUSED)) {
+#endif
                                        GC_REFCOUNT(object)--;
                                }
                                if (GC_REFCOUNT(object) == 1) {
@@ -2417,6 +2420,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
                }
                EG(scope) = EX(func)->op_array.scope;
 
+               zend_vm_stack_free_call_frame(old_execute_data);
+
                if (UNEXPECTED(EG(exception) != NULL)) {
                        const zend_op *old_opline = EX(opline);
                        zend_throw_exception_internal(NULL);
@@ -2882,6 +2887,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -2959,13 +2965,15 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (OP1_TYPE & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -3070,7 +3078,6 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMPVAR|UNUSE
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -3175,9 +3182,6 @@ ZEND_VM_C_LABEL(try_function_name):
            EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
                Z_OBJ_HANDLER_P(function_name, get_closure) &&
                Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object) == SUCCESS) {
-               if (object) {
-                       GC_REFCOUNT(object)++;
-               }
                if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
                        /* Delay closure destruction until its invocation */
                        ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
@@ -3262,6 +3266,7 @@ ZEND_VM_C_LABEL(try_function_name):
                        if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
                                object = NULL;
                        } else {
+                               call_info |= ZEND_CALL_RELEASE_THIS;
                                GC_REFCOUNT(object)++; /* For $this pointer */
                        }
                }
@@ -3318,6 +3323,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
                called_scope = fcc.called_scope;
                object = fcc.object;
                if (object) {
+                       call_info |= ZEND_CALL_RELEASE_THIS;
                        GC_REFCOUNT(object)++; /* For $this pointer */
                } else if (func->common.scope &&
                           !(func->common.fn_flags & ZEND_ACC_STATIC)) {
@@ -3595,7 +3601,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
        USE_OPLINE
        zend_execute_data *call = EX(call);
        zend_function *fbc = call->func;
-       zend_object *object = Z_OBJ(call->This);
+       zend_object *object;
        zval *ret;
 
        SAVE_OPLINE();
@@ -3628,8 +3634,6 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
                        } else {
                                zend_vm_stack_free_args(call);
                        }
-
-                       zend_vm_stack_free_call_frame(call);
                } else {
                        ret = NULL;
                        call->symbol_table = NULL;
@@ -3670,7 +3674,6 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
                                if (UNEXPECTED(EG(exception) != NULL)) {
                                        EG(current_execute_data) = call->prev_execute_data;
                                        zend_vm_stack_free_args(call);
-                                       zend_vm_stack_free_call_frame(call);
                                        if (RETURN_VALUE_USED(opline)) {
                                                ZVAL_UNDEF(EX_VAR(opline->result.var));
                                        }
@@ -3704,7 +3707,6 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
 
                EG(current_execute_data) = call->prev_execute_data;
                zend_vm_stack_free_args(call);
-               zend_vm_stack_free_call_frame(call);
 
                if (!RETURN_VALUE_USED(opline)) {
                        zval_ptr_dtor(EX_VAR(opline->result.var));
@@ -3721,6 +3723,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
                ZVAL_NULL(EX_VAR(opline->result.var));
 
                /* Not sure what should be done here if it's a static method */
+               object = Z_OBJ(call->This);
                if (EXPECTED(object != NULL)) {
                        call->prev_execute_data = execute_data;
                        EG(current_execute_data) = call;
@@ -3744,8 +3747,6 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
 
                zend_vm_stack_free_args(call);
 
-               zend_vm_stack_free_call_frame(call);
-
                if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
                        zend_string_release(fbc->common.function_name);
                }
@@ -3759,9 +3760,15 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
        }
 
 ZEND_VM_C_LABEL(fcall_end_change_scope):
-       if (object) {
+       if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
+               object = Z_OBJ(call->This);
+#if 0
                if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) {
                        if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) {
+#else
+               if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) {
+                       if (!(ZEND_CALL_INFO(call) & ZEND_CALL_CTOR_RESULT_UNUSED)) {
+#endif
                                GC_REFCOUNT(object)--;
                        }
                        if (GC_REFCOUNT(object) == 1) {
@@ -3773,6 +3780,7 @@ ZEND_VM_C_LABEL(fcall_end_change_scope):
        EG(scope) = EX(func)->op_array.scope;
 
 ZEND_VM_C_LABEL(fcall_end):
+       zend_vm_stack_free_call_frame(call);
        if (UNEXPECTED(EG(exception) != NULL)) {
                zend_throw_exception_internal(NULL);
                if (RETURN_VALUE_USED(opline)) {
@@ -4891,7 +4899,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, CONST|VAR, ANY)
        } else {
                /* We are not handling overloaded classes right now */
                zend_execute_data *call = zend_vm_stack_push_call_frame(
-                               ZEND_CALL_FUNCTION | ZEND_CALL_CTOR |
+                               ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR |
                                (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED),
                        constructor,
                        opline->extended_value,
@@ -7121,7 +7129,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
 
                        zend_vm_stack_free_args(EX(call));
 
-                       if (Z_OBJ(call->This)) {
+                       if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
                                if (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR) {
                                        if (!(ZEND_CALL_INFO(call) & ZEND_CALL_CTOR_RESULT_UNUSED)) {
                                                GC_REFCOUNT(Z_OBJ(call->This))--;
@@ -7882,7 +7890,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
        zend_function *fbc = EX(func);
        zend_object *object = Z_OBJ(EX(This));
        zval *ret = EX(return_value);
-       zend_call_kind call_kind = EX_CALL_KIND();
+       uint32_t call_info = EX_CALL_INFO() & (ZEND_CALL_NESTED | ZEND_CALL_TOP | ZEND_CALL_RELEASE_THIS);
        zend_class_entry *scope = EX(called_scope);
        uint32_t num_args = EX_NUM_ARGS();
        zend_execute_data *call;
@@ -7907,7 +7915,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
        call = execute_data;
        execute_data = EG(current_execute_data) = EX(prev_execute_data);
        zend_vm_stack_free_call_frame(call);
-       call = zend_vm_stack_push_call_frame(call_kind, fbc->common.prototype, 2, scope, object);
+       call = zend_vm_stack_push_call_frame(call_info, fbc->common.prototype, 2, scope, object);
        call->prev_execute_data = execute_data;
 
        ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name);
@@ -7981,7 +7989,6 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
                EG(current_execute_data) = call->prev_execute_data;
 
                zend_vm_stack_free_args(call);
-               zend_vm_stack_free_call_frame(call);
 
                if (ret == &retval) {
                        zval_ptr_dtor(ret);
@@ -7991,16 +7998,18 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
 ZEND_VM_C_LABEL(call_trampoline_end):
        execute_data = EG(current_execute_data);
 
-       if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_kind & ZEND_CALL_TOP)) {
+       if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) {
                ZEND_VM_RETURN();
        }
 
        opline = EX(opline);
 
-       if (object) {
+       if (call_info & ZEND_CALL_RELEASE_THIS) {
+               object = Z_OBJ(call->This);
                OBJ_RELEASE(object);
        }
        EG(scope) = EX(func)->op_array.scope;
+       zend_vm_stack_free_call_frame(call);
 
        if (UNEXPECTED(EG(exception) != NULL)) {
                zend_throw_exception_internal(NULL);
index 85075af2a6fd1c3c2f2125c4159d55ac8e77c3db..73e2a4a6ca5ee3a1a8d7c80d6ea15e62408a8631 100644 (file)
@@ -452,12 +452,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
                if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
                        OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype);
                }
-               object = Z_OBJ(old_execute_data->This);
-               zend_vm_stack_free_call_frame(old_execute_data);
-
-               if (object) {
+               if (call_info & ZEND_CALL_RELEASE_THIS) {
+                       object = Z_OBJ(old_execute_data->This);
+#if 0
                        if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
                                if (!(EX(opline)->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) {
+#else
+                       if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+                               if (!(call_info & ZEND_CALL_CTOR_RESULT_UNUSED)) {
+#endif
                                        GC_REFCOUNT(object)--;
                                }
                                if (GC_REFCOUNT(object) == 1) {
@@ -468,6 +471,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
                }
                EG(scope) = EX(func)->op_array.scope;
 
+               zend_vm_stack_free_call_frame(old_execute_data);
+
                if (UNEXPECTED(EG(exception) != NULL)) {
                        const zend_op *old_opline = EX(opline);
                        zend_throw_exception_internal(NULL);
@@ -718,7 +723,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
        USE_OPLINE
        zend_execute_data *call = EX(call);
        zend_function *fbc = call->func;
-       zend_object *object = Z_OBJ(call->This);
+       zend_object *object;
        zval *ret;
 
        SAVE_OPLINE();
@@ -751,8 +756,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
                        } else {
                                zend_vm_stack_free_args(call);
                        }
-
-                       zend_vm_stack_free_call_frame(call);
                } else {
                        ret = NULL;
                        call->symbol_table = NULL;
@@ -793,7 +796,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
                                if (UNEXPECTED(EG(exception) != NULL)) {
                                        EG(current_execute_data) = call->prev_execute_data;
                                        zend_vm_stack_free_args(call);
-                                       zend_vm_stack_free_call_frame(call);
                                        if (RETURN_VALUE_USED(opline)) {
                                                ZVAL_UNDEF(EX_VAR(opline->result.var));
                                        }
@@ -827,7 +829,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
 
                EG(current_execute_data) = call->prev_execute_data;
                zend_vm_stack_free_args(call);
-               zend_vm_stack_free_call_frame(call);
 
                if (!RETURN_VALUE_USED(opline)) {
                        zval_ptr_dtor(EX_VAR(opline->result.var));
@@ -844,6 +845,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
                ZVAL_NULL(EX_VAR(opline->result.var));
 
                /* Not sure what should be done here if it's a static method */
+               object = Z_OBJ(call->This);
                if (EXPECTED(object != NULL)) {
                        call->prev_execute_data = execute_data;
                        EG(current_execute_data) = call;
@@ -867,8 +869,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
 
                zend_vm_stack_free_args(call);
 
-               zend_vm_stack_free_call_frame(call);
-
                if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
                        zend_string_release(fbc->common.function_name);
                }
@@ -882,9 +882,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
        }
 
 fcall_end_change_scope:
-       if (object) {
+       if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
+               object = Z_OBJ(call->This);
+#if 0
                if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) {
                        if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) {
+#else
+               if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) {
+                       if (!(ZEND_CALL_INFO(call) & ZEND_CALL_CTOR_RESULT_UNUSED)) {
+#endif
                                GC_REFCOUNT(object)--;
                        }
                        if (GC_REFCOUNT(object) == 1) {
@@ -896,6 +902,7 @@ fcall_end_change_scope:
        EG(scope) = EX(func)->op_array.scope;
 
 fcall_end:
+       zend_vm_stack_free_call_frame(call);
        if (UNEXPECTED(EG(exception) != NULL)) {
                zend_throw_exception_internal(NULL);
                if (RETURN_VALUE_USED(opline)) {
@@ -1571,7 +1578,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
 
                        zend_vm_stack_free_args(EX(call));
 
-                       if (Z_OBJ(call->This)) {
+                       if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
                                if (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR) {
                                        if (!(ZEND_CALL_INFO(call) & ZEND_CALL_CTOR_RESULT_UNUSED)) {
                                                GC_REFCOUNT(Z_OBJ(call->This))--;
@@ -1829,7 +1836,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
        zend_function *fbc = EX(func);
        zend_object *object = Z_OBJ(EX(This));
        zval *ret = EX(return_value);
-       zend_call_kind call_kind = EX_CALL_KIND();
+       uint32_t call_info = EX_CALL_INFO() & (ZEND_CALL_NESTED | ZEND_CALL_TOP | ZEND_CALL_RELEASE_THIS);
        zend_class_entry *scope = EX(called_scope);
        uint32_t num_args = EX_NUM_ARGS();
        zend_execute_data *call;
@@ -1854,7 +1861,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
        call = execute_data;
        execute_data = EG(current_execute_data) = EX(prev_execute_data);
        zend_vm_stack_free_call_frame(call);
-       call = zend_vm_stack_push_call_frame(call_kind, fbc->common.prototype, 2, scope, object);
+       call = zend_vm_stack_push_call_frame(call_info, fbc->common.prototype, 2, scope, object);
        call->prev_execute_data = execute_data;
 
        ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name);
@@ -1928,7 +1935,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
                EG(current_execute_data) = call->prev_execute_data;
 
                zend_vm_stack_free_args(call);
-               zend_vm_stack_free_call_frame(call);
 
                if (ret == &retval) {
                        zval_ptr_dtor(ret);
@@ -1938,16 +1944,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
 call_trampoline_end:
        execute_data = EG(current_execute_data);
 
-       if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_kind & ZEND_CALL_TOP)) {
+       if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) {
                ZEND_VM_RETURN();
        }
 
        opline = EX(opline);
 
-       if (object) {
+       if (call_info & ZEND_CALL_RELEASE_THIS) {
+               object = Z_OBJ(call->This);
                OBJ_RELEASE(object);
        }
        EG(scope) = EX(func)->op_array.scope;
+       zend_vm_stack_free_call_frame(call);
 
        if (UNEXPECTED(EG(exception) != NULL)) {
                zend_throw_exception_internal(NULL);
@@ -2070,9 +2078,6 @@ try_function_name:
            EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
                Z_OBJ_HANDLER_P(function_name, get_closure) &&
                Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object) == SUCCESS) {
-               if (object) {
-                       GC_REFCOUNT(object)++;
-               }
                if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
                        /* Delay closure destruction until its invocation */
                        ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
@@ -2157,6 +2162,7 @@ try_function_name:
                        if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
                                object = NULL;
                        } else {
+                               call_info |= ZEND_CALL_RELEASE_THIS;
                                GC_REFCOUNT(object)++; /* For $this pointer */
                        }
                }
@@ -2482,9 +2488,6 @@ try_function_name:
            EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
                Z_OBJ_HANDLER_P(function_name, get_closure) &&
                Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object) == SUCCESS) {
-               if (object) {
-                       GC_REFCOUNT(object)++;
-               }
                if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
                        /* Delay closure destruction until its invocation */
                        ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
@@ -2569,6 +2572,7 @@ try_function_name:
                        if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
                                object = NULL;
                        } else {
+                               call_info |= ZEND_CALL_RELEASE_THIS;
                                GC_REFCOUNT(object)++; /* For $this pointer */
                        }
                }
@@ -2676,9 +2680,6 @@ try_function_name:
            EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
                Z_OBJ_HANDLER_P(function_name, get_closure) &&
                Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object) == SUCCESS) {
-               if (object) {
-                       GC_REFCOUNT(object)++;
-               }
                if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
                        /* Delay closure destruction until its invocation */
                        ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
@@ -2763,6 +2764,7 @@ try_function_name:
                        if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
                                object = NULL;
                        } else {
+                               call_info |= ZEND_CALL_RELEASE_THIS;
                                GC_REFCOUNT(object)++; /* For $this pointer */
                        }
                }
@@ -3356,7 +3358,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_HANDLER(ZEND_OP
        } else {
                /* We are not handling overloaded classes right now */
                zend_execute_data *call = zend_vm_stack_push_call_frame(
-                               ZEND_CALL_FUNCTION | ZEND_CALL_CTOR |
+                               ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR |
                                (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED),
                        constructor,
                        opline->extended_value,
@@ -5398,6 +5400,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CO
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -5475,13 +5478,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CO
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_CONST & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -5584,7 +5589,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -5654,6 +5658,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
                called_scope = fcc.called_scope;
                object = fcc.object;
                if (object) {
+                       call_info |= ZEND_CALL_RELEASE_THIS;
                        GC_REFCOUNT(object)++; /* For $this pointer */
                } else if (func->common.scope &&
                           !(func->common.fn_flags & ZEND_ACC_STATIC)) {
@@ -7573,7 +7578,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -9036,6 +9040,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CV
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -9113,13 +9118,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CV
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_CONST & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -9222,7 +9229,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -9292,6 +9298,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H
                called_scope = fcc.called_scope;
                object = fcc.object;
                if (object) {
+                       call_info |= ZEND_CALL_RELEASE_THIS;
                        GC_REFCOUNT(object)++; /* For $this pointer */
                } else if (func->common.scope &&
                           !(func->common.fn_flags & ZEND_ACC_STATIC)) {
@@ -10761,6 +10768,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_TM
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -10838,13 +10846,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_TM
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_CONST & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -10948,7 +10958,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -11018,6 +11027,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV
                called_scope = fcc.called_scope;
                object = fcc.object;
                if (object) {
+                       call_info |= ZEND_CALL_RELEASE_THIS;
                        GC_REFCOUNT(object)++; /* For $this pointer */
                } else if (func->common.scope &&
                           !(func->common.fn_flags & ZEND_ACC_STATIC)) {
@@ -15064,7 +15074,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_HANDLER(ZEND_OPCO
        } else {
                /* We are not handling overloaded classes right now */
                zend_execute_data *call = zend_vm_stack_push_call_frame(
-                               ZEND_CALL_FUNCTION | ZEND_CALL_CTOR |
+                               ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR |
                                (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED),
                        constructor,
                        opline->extended_value,
@@ -17304,7 +17314,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -18914,7 +18923,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -20611,7 +20619,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -22255,7 +22262,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
        if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
                if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
                        object = Z_OBJ(EX(This));
-                       GC_REFCOUNT(object)++;
                }
                if (!object) {
                        if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
@@ -23618,6 +23624,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -23695,13 +23702,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_UNUSED & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -26009,6 +26018,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -26086,13 +26096,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_UNUSED & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -27522,6 +27534,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -27599,13 +27612,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_UNUSED & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -31799,6 +31814,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -31876,13 +31892,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_CV & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -36856,6 +36874,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -36933,13 +36952,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_CV & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -39414,6 +39435,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -39491,13 +39513,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if (IS_CV & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -41555,6 +41579,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -41632,13 +41657,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if ((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -43614,6 +43641,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -43691,13 +43719,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if ((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -44661,6 +44691,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T
        zend_class_entry *called_scope;
        zend_object *obj;
        zend_execute_data *call;
+       uint32_t call_info;
 
        SAVE_OPLINE();
 
@@ -44738,13 +44769,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T
                }
        }
 
+       call_info = ZEND_CALL_NESTED_FUNCTION;
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
                obj = NULL;
-       } else {
+       } else if ((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_TMP_VAR)) {
+               call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
                GC_REFCOUNT(obj)++; /* For $this pointer */
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                fbc, opline->extended_value, called_scope, obj);
        call->prev_execute_data = EX(call);
        EX(call) = call;