]> granicus.if.org Git - php/commitdiff
Mark call frames to closures with ZEND_CALL_CLOSURE flag to avoid expensive check...
authorDmitry Stogov <dmitry@zend.com>
Thu, 16 Apr 2015 09:16:03 +0000 (12:16 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 16 Apr 2015 09:16:03 +0000 (12:16 +0300)
Zend/zend_compile.h
Zend/zend_execute.h
Zend/zend_execute_API.c
Zend/zend_generators.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 57b234a12a541e0415e069a1b25aa8ec78204ba3..980a06c1997ad5498618d284f3bde7c948644201 100644 (file)
@@ -429,19 +429,27 @@ struct _zend_execute_data {
 #define ZEND_CALL_FREE_EXTRA_ARGS    (1 << 2) /* equal to IS_TYPE_REFCOUNTED */
 #define ZEND_CALL_CTOR               (1 << 3)
 #define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4)
+#define ZEND_CALL_CLOSURE            (1 << 5)
 
 #define ZEND_CALL_INFO(call) \
        (Z_TYPE_INFO((call)->This) >> 24)
 
+#define ZEND_CALL_KIND_EX(call_info) \
+       (call_info & (ZEND_CALL_CODE | ZEND_CALL_TOP))
+
 #define ZEND_CALL_KIND(call) \
-       (ZEND_CALL_INFO(call) & (ZEND_CALL_CODE | ZEND_CALL_TOP))
+       ZEND_CALL_KIND_EX(ZEND_CALL_INFO(call))
 
 #define ZEND_SET_CALL_INFO(call, info) do { \
                Z_TYPE_INFO((call)->This) = IS_OBJECT_EX | ((info) << 24); \
        } while (0)
 
-#define ZEND_ADD_CALL_FLAG(call, info) do { \
-               Z_TYPE_INFO((call)->This) |= ((info) << 24); \
+#define ZEND_ADD_CALL_FLAG_EX(call_info, flag) do { \
+               call_info |= ((flag) << 24); \
+       } while (0)
+
+#define ZEND_ADD_CALL_FLAG(call, flag) do { \
+               ZEND_ADD_CALL_FLAG_EX(Z_TYPE_INFO((call)->This), flag); \
        } while (0)
 
 #define ZEND_CALL_NUM_ARGS(call) \
index add05f3139cc03f6ed69c8377d297816ae5c6c1c..f98faf91970857fc3f7a5fb4a2918cab48541a18 100644 (file)
@@ -192,9 +192,9 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint3
                func, num_args, called_scope, object);
 }
 
-static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call)
+static zend_always_inline void zend_vm_stack_free_extra_args_ex(uint32_t call_info, zend_execute_data *call)
 {
-       if (ZEND_CALL_INFO(call) & ZEND_CALL_FREE_EXTRA_ARGS) {
+       if (call_info & ZEND_CALL_FREE_EXTRA_ARGS) {
                zval *end = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
                zval *p = end + (ZEND_CALL_NUM_ARGS(call) - call->func->op_array.num_args);
                do {
@@ -204,6 +204,11 @@ static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *
        }
 }
 
+static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call)
+{
+       zend_vm_stack_free_extra_args_ex(ZEND_CALL_INFO(call), call);
+}
+
 static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call)
 {
        uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
index b710ae99c0bff9621107847501e6e359b5e5ceb0..ac9f4b1c5c10f991deded1e5a5d0d03681a2eb2b 100644 (file)
@@ -833,6 +833,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
                if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
                        ZEND_ASSERT(GC_TYPE(func->op_array.prototype) == IS_OBJECT);
                        GC_REFCOUNT(func->op_array.prototype)++;
+                       ZEND_ADD_CALL_FLAG(call, ZEND_CALL_CLOSURE);
                }
                if (EXPECTED((func->op_array.fn_flags & ZEND_ACC_GENERATOR) == 0)) {
                        zend_init_execute_data(call, &func->op_array, fci->retval);
index 98603200bf06a0cfc67c3d930e83e75c69f7f838..7d2472a1458d9ce45c6718f519098dc70a1cc214 100644 (file)
@@ -103,7 +103,6 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
 
        if (generator->execute_data) {
                zend_execute_data *execute_data = generator->execute_data;
-               zend_op_array *op_array = &execute_data->func->op_array;
 
                if (!execute_data->symbol_table) {
                        zend_free_compiled_variables(execute_data);
@@ -131,8 +130,8 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
                }
 
                /* Free closure object */
-               if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
-                       OBJ_RELEASE((zend_object *) op_array->prototype);
+               if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
+                       OBJ_RELEASE((zend_object *) EX(func)->common.prototype);
                }
 
                efree(generator->stack);
index 0dea57aced3e1d5f4e84b84af03e24f1f5e84097..28bde464a7482971efa4c1bca4b803d98596c78d 100644 (file)
@@ -2352,9 +2352,9 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV)
 ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
 {
        zend_execute_data *old_execute_data;
-       zend_call_kind call_kind = EX_CALL_KIND();
+       uint32_t call_info = EX_CALL_INFO();
 
-       if (call_kind == ZEND_CALL_NESTED_FUNCTION) {
+       if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_FUNCTION) {
                zend_object *object;
 
                i_free_compiled_variables(execute_data);
@@ -2364,7 +2364,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
                zend_vm_stack_free_extra_args(execute_data);
                old_execute_data = execute_data;
                execute_data = EG(current_execute_data) = EX(prev_execute_data);
-               if (UNEXPECTED(old_execute_data->func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
+               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);
@@ -2395,7 +2395,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
                LOAD_OPLINE();
                ZEND_VM_INC_OPCODE();
                ZEND_VM_LEAVE();
-       } else if (call_kind == ZEND_CALL_NESTED_CODE) {
+       } else if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_CODE) {
                zend_detach_symbol_table(execute_data);
                destroy_op_array(&EX(func)->op_array);
                efree_size(EX(func), sizeof(zend_op_array));
@@ -2413,14 +2413,14 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
                ZEND_VM_INC_OPCODE();
                ZEND_VM_LEAVE();
        } else {
-               if (call_kind == ZEND_CALL_TOP_FUNCTION) {
+               if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_TOP_FUNCTION) {
                        i_free_compiled_variables(execute_data);
                        if (UNEXPECTED(EX(symbol_table) != NULL)) {
                                zend_clean_and_cache_symbol_table(EX(symbol_table));
                        }
                        zend_vm_stack_free_extra_args(execute_data);
                        EG(current_execute_data) = EX(prev_execute_data);
-                       if (EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) {
+                       if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
                                OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
                        }
                } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ {
@@ -3112,6 +3112,7 @@ ZEND_VM_HANDLER(128, ZEND_INIT_DYNAMIC_CALL, ANY, CONST|TMPVAR|CV)
        zend_class_entry *called_scope;
        zend_object *object;
        zend_execute_data *call;
+       uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
 
        SAVE_OPLINE();
        function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
@@ -3147,6 +3148,7 @@ ZEND_VM_C_LABEL(try_function_name):
                        /* Delay closure destruction until its invocation */
                        ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
                        GC_REFCOUNT(fbc->common.prototype)++;
+                       call_info |= ZEND_CALL_CLOSURE;
                }
                FREE_OP2();
        } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
@@ -3241,7 +3243,7 @@ ZEND_VM_C_LABEL(try_function_name):
                FREE_OP2();
                HANDLE_EXCEPTION();
        }
-       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, object);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -3261,6 +3263,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
        zend_class_entry *called_scope;
        zend_object *object;
        zend_execute_data *call;
+       uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
 
        SAVE_OPLINE();
        function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
@@ -3276,6 +3279,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
                        }
                        ZEND_ASSERT(GC_TYPE(func->common.prototype) == IS_OBJECT);
                        GC_REFCOUNT(func->common.prototype)++;
+                       call_info |= ZEND_CALL_CLOSURE;
                }
                called_scope = fcc.called_scope;
                object = fcc.object;
@@ -3304,7 +3308,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
                object = NULL;
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                func, opline->extended_value, called_scope, object);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -4434,7 +4438,7 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY)
                        }
                }
                zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args)));
-               if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
+               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
                        OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                }
                if (Z_OBJ(EX(call)->This)) {
@@ -4481,7 +4485,7 @@ ZEND_VM_C_LABEL(send_array):
                                                        EX(call)->func->common.scope ? "::" : "",
                                                        EX(call)->func->common.function_name->val);
 
-                                               if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
+                                               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
                                                        OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                                                }
                                                if (Z_OBJ(EX(call)->This)) {
@@ -4539,7 +4543,7 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, ANY)
                                        EX(call)->func->common.scope ? "::" : "",
                                        EX(call)->func->common.function_name->val);
 
-                               if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
+                               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
                                        OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                                }
                                if (Z_OBJ(EX(call)->This)) {
index 6d4ee188d9fc92c1c116592b47a868d217b33579..c969a302cf8c992da1e04532d2a31ccc1a00e74d 100644 (file)
@@ -437,9 +437,9 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value)
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
 {
        zend_execute_data *old_execute_data;
-       zend_call_kind call_kind = EX_CALL_KIND();
+       uint32_t call_info = EX_CALL_INFO();
 
-       if (call_kind == ZEND_CALL_NESTED_FUNCTION) {
+       if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_FUNCTION) {
                zend_object *object;
 
                i_free_compiled_variables(execute_data);
@@ -449,7 +449,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
                zend_vm_stack_free_extra_args(execute_data);
                old_execute_data = execute_data;
                execute_data = EG(current_execute_data) = EX(prev_execute_data);
-               if (UNEXPECTED(old_execute_data->func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
+               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);
@@ -480,7 +480,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
                LOAD_OPLINE();
                ZEND_VM_INC_OPCODE();
                ZEND_VM_LEAVE();
-       } else if (call_kind == ZEND_CALL_NESTED_CODE) {
+       } else if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_CODE) {
                zend_detach_symbol_table(execute_data);
                destroy_op_array(&EX(func)->op_array);
                efree_size(EX(func), sizeof(zend_op_array));
@@ -498,14 +498,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
                ZEND_VM_INC_OPCODE();
                ZEND_VM_LEAVE();
        } else {
-               if (call_kind == ZEND_CALL_TOP_FUNCTION) {
+               if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_TOP_FUNCTION) {
                        i_free_compiled_variables(execute_data);
                        if (UNEXPECTED(EX(symbol_table) != NULL)) {
                                zend_clean_and_cache_symbol_table(EX(symbol_table));
                        }
                        zend_vm_stack_free_extra_args(execute_data);
                        EG(current_execute_data) = EX(prev_execute_data);
-                       if (EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) {
+                       if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
                                OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
                        }
                } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ {
@@ -1102,7 +1102,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O
                        }
                }
                zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args)));
-               if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
+               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
                        OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                }
                if (Z_OBJ(EX(call)->This)) {
@@ -1149,7 +1149,7 @@ send_array:
                                                        EX(call)->func->common.scope ? "::" : "",
                                                        EX(call)->func->common.function_name->val);
 
-                                               if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
+                                               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
                                                        OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                                                }
                                                if (Z_OBJ(EX(call)->This)) {
@@ -1988,6 +1988,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_H
        zend_class_entry *called_scope;
        zend_object *object;
        zend_execute_data *call;
+       uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
 
        SAVE_OPLINE();
        function_name = EX_CONSTANT(opline->op2);
@@ -2022,6 +2023,7 @@ try_function_name:
                        /* Delay closure destruction until its invocation */
                        ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
                        GC_REFCOUNT(fbc->common.prototype)++;
+                       call_info |= ZEND_CALL_CLOSURE;
                }
 
        } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
@@ -2116,7 +2118,7 @@ try_function_name:
 
                HANDLE_EXCEPTION();
        }
-       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, object);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -2392,6 +2394,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HAND
        zend_class_entry *called_scope;
        zend_object *object;
        zend_execute_data *call;
+       uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
 
        SAVE_OPLINE();
        function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
@@ -2426,6 +2429,7 @@ try_function_name:
                        /* Delay closure destruction until its invocation */
                        ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
                        GC_REFCOUNT(fbc->common.prototype)++;
+                       call_info |= ZEND_CALL_CLOSURE;
                }
 
        } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
@@ -2520,7 +2524,7 @@ try_function_name:
 
                HANDLE_EXCEPTION();
        }
-       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, object);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -2583,6 +2587,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_
        zend_class_entry *called_scope;
        zend_object *object;
        zend_execute_data *call;
+       uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
 
        SAVE_OPLINE();
        function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
@@ -2618,6 +2623,7 @@ try_function_name:
                        /* Delay closure destruction until its invocation */
                        ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
                        GC_REFCOUNT(fbc->common.prototype)++;
+                       call_info |= ZEND_CALL_CLOSURE;
                }
                zval_ptr_dtor_nogc(free_op2);
        } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
@@ -2712,7 +2718,7 @@ try_function_name:
                zval_ptr_dtor_nogc(free_op2);
                HANDLE_EXCEPTION();
        }
-       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, object);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -5428,6 +5434,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
        zend_class_entry *called_scope;
        zend_object *object;
        zend_execute_data *call;
+       uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
 
        SAVE_OPLINE();
        function_name = EX_CONSTANT(opline->op2);
@@ -5443,6 +5450,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
                        }
                        ZEND_ASSERT(GC_TYPE(func->common.prototype) == IS_OBJECT);
                        GC_REFCOUNT(func->common.prototype)++;
+                       call_info |= ZEND_CALL_CLOSURE;
                }
                called_scope = fcc.called_scope;
                object = fcc.object;
@@ -5471,7 +5479,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
                object = NULL;
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                func, opline->extended_value, called_scope, object);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -8890,6 +8898,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H
        zend_class_entry *called_scope;
        zend_object *object;
        zend_execute_data *call;
+       uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
 
        SAVE_OPLINE();
        function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
@@ -8905,6 +8914,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H
                        }
                        ZEND_ASSERT(GC_TYPE(func->common.prototype) == IS_OBJECT);
                        GC_REFCOUNT(func->common.prototype)++;
+                       call_info |= ZEND_CALL_CLOSURE;
                }
                called_scope = fcc.called_scope;
                object = fcc.object;
@@ -8933,7 +8943,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H
                object = NULL;
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                func, opline->extended_value, called_scope, object);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -10484,6 +10494,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV
        zend_class_entry *called_scope;
        zend_object *object;
        zend_execute_data *call;
+       uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
 
        SAVE_OPLINE();
        function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
@@ -10499,6 +10510,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV
                        }
                        ZEND_ASSERT(GC_TYPE(func->common.prototype) == IS_OBJECT);
                        GC_REFCOUNT(func->common.prototype)++;
+                       call_info |= ZEND_CALL_CLOSURE;
                }
                called_scope = fcc.called_scope;
                object = fcc.object;
@@ -10527,7 +10539,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV
                object = NULL;
        }
 
-       call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
+       call = zend_vm_stack_push_call_frame(call_info,
                func, opline->extended_value, called_scope, object);
        call->prev_execute_data = EX(call);
        EX(call) = call;
@@ -14431,7 +14443,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN
                                        EX(call)->func->common.scope ? "::" : "",
                                        EX(call)->func->common.function_name->val);
 
-                               if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
+                               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
                                        OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                                }
                                if (Z_OBJ(EX(call)->This)) {
@@ -28169,7 +28181,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND
                                        EX(call)->func->common.scope ? "::" : "",
                                        EX(call)->func->common.function_name->val);
 
-                               if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
+                               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
                                        OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                                }
                                if (Z_OBJ(EX(call)->This)) {