If no refcounted arguments are passed, then destruction code is not triggered at all.
(Full rebuild required)
#define ZEND_CALL_CODE (1 << 0)
#define ZEND_CALL_NESTED (0 << 1)
#define ZEND_CALL_TOP (1 << 1)
-#define ZEND_CALL_CTOR (1 << 2)
-#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 3)
+#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_INFO(call) \
(Z_TYPE_INFO((call)->This) >> 24)
num_args = EX_NUM_ARGS();
if (UNEXPECTED(num_args > first_extra_arg)) {
zval *end, *src, *dst;
+ uint32_t type_flags = 0;
if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
dst = src + (op_array->last_var + op_array->T - first_extra_arg);
if (EXPECTED(src != dst)) {
do {
+ type_flags |= Z_TYPE_INFO_P(src);
ZVAL_COPY_VALUE(dst, src);
ZVAL_UNDEF(src);
src--;
dst--;
} while (src != end);
+ } else {
+ do {
+ type_flags |= Z_TYPE_INFO_P(src);
+ src--;
+ } while (src != end);
}
+ ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
} else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
EX(opline) += num_args;
num_args = EX_NUM_ARGS();
if (UNEXPECTED(num_args > first_extra_arg)) {
zval *end, *src, *dst;
+ uint32_t type_flags = 0;
if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
dst = src + (op_array->last_var + op_array->T - first_extra_arg);
if (EXPECTED(src != dst)) {
do {
+ type_flags |= Z_TYPE_INFO_P(src);
ZVAL_COPY_VALUE(dst, src);
ZVAL_UNDEF(src);
src--;
dst--;
} while (src != end);
+ } else {
+ do {
+ type_flags |= Z_TYPE_INFO_P(src);
+ src--;
+ } while (src != end);
}
+ ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
} else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
EX(opline) += num_args;
static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call)
{
- uint32_t first_extra_arg = call->func->op_array.num_args;
-
- if (UNEXPECTED(ZEND_CALL_NUM_ARGS(call) > first_extra_arg)) {
- 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) - first_extra_arg);
+ if (ZEND_CALL_INFO(call) & 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 {
p--;
zval_ptr_dtor_nogc(p);
#define Z_COUNTED_P(zval_p) Z_COUNTED(*(zval_p))
#define Z_TYPE_FLAGS_SHIFT 8
-#define Z_CONST_FLAGS_SHIFT 8
+#define Z_CONST_FLAGS_SHIFT 16
#define GC_REFCOUNT(p) ((zend_refcounted*)(p))->refcount
#define GC_TYPE(p) ((zend_refcounted*)(p))->u.v.type
/* zval.u1.v.type_flags */
#define IS_TYPE_CONSTANT (1<<0)
-#define IS_TYPE_REFCOUNTED (1<<1)
-#define IS_TYPE_COLLECTABLE (1<<2)
-#define IS_TYPE_COPYABLE (1<<3)
-#define IS_TYPE_IMMUTABLE (1<<4)
+#define IS_TYPE_IMMUTABLE (1<<1)
+#define IS_TYPE_REFCOUNTED (1<<2)
+#define IS_TYPE_COLLECTABLE (1<<3)
+#define IS_TYPE_COPYABLE (1<<4)
/* extended types */
#define IS_INTERNED_STRING_EX IS_STRING