Skip to content

Commit ab0b15b

Browse files
committed
Optimized destruction of extra arguments passed to user functions.
If no refcounted arguments are passed, then destruction code is not triggered at all. (Full rebuild required)
1 parent 4409b6d commit ab0b15b

File tree

4 files changed

+27
-12
lines changed

4 files changed

+27
-12
lines changed

Zend/zend_compile.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,9 @@ struct _zend_execute_data {
412412
#define ZEND_CALL_CODE (1 << 0)
413413
#define ZEND_CALL_NESTED (0 << 1)
414414
#define ZEND_CALL_TOP (1 << 1)
415-
#define ZEND_CALL_CTOR (1 << 2)
416-
#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 3)
415+
#define ZEND_CALL_FREE_EXTRA_ARGS (1 << 2) /* equal to IS_TYPE_REFCOUNTED */
416+
#define ZEND_CALL_CTOR (1 << 3)
417+
#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4)
417418

418419
#define ZEND_CALL_INFO(call) \
419420
(Z_TYPE_INFO((call)->This) >> 24)

Zend/zend_execute.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,7 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
16171617
num_args = EX_NUM_ARGS();
16181618
if (UNEXPECTED(num_args > first_extra_arg)) {
16191619
zval *end, *src, *dst;
1620+
uint32_t type_flags = 0;
16201621

16211622
if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
16221623
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
@@ -1629,12 +1630,19 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
16291630
dst = src + (op_array->last_var + op_array->T - first_extra_arg);
16301631
if (EXPECTED(src != dst)) {
16311632
do {
1633+
type_flags |= Z_TYPE_INFO_P(src);
16321634
ZVAL_COPY_VALUE(dst, src);
16331635
ZVAL_UNDEF(src);
16341636
src--;
16351637
dst--;
16361638
} while (src != end);
1639+
} else {
1640+
do {
1641+
type_flags |= Z_TYPE_INFO_P(src);
1642+
src--;
1643+
} while (src != end);
16371644
}
1645+
ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
16381646
} else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
16391647
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
16401648
EX(opline) += num_args;
@@ -1709,6 +1717,7 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
17091717
num_args = EX_NUM_ARGS();
17101718
if (UNEXPECTED(num_args > first_extra_arg)) {
17111719
zval *end, *src, *dst;
1720+
uint32_t type_flags = 0;
17121721

17131722
if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
17141723
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
@@ -1721,12 +1730,19 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
17211730
dst = src + (op_array->last_var + op_array->T - first_extra_arg);
17221731
if (EXPECTED(src != dst)) {
17231732
do {
1733+
type_flags |= Z_TYPE_INFO_P(src);
17241734
ZVAL_COPY_VALUE(dst, src);
17251735
ZVAL_UNDEF(src);
17261736
src--;
17271737
dst--;
17281738
} while (src != end);
1739+
} else {
1740+
do {
1741+
type_flags |= Z_TYPE_INFO_P(src);
1742+
src--;
1743+
} while (src != end);
17291744
}
1745+
ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
17301746
} else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
17311747
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
17321748
EX(opline) += num_args;

Zend/zend_execute.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,9 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint3
176176

177177
static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call)
178178
{
179-
uint32_t first_extra_arg = call->func->op_array.num_args;
180-
181-
if (UNEXPECTED(ZEND_CALL_NUM_ARGS(call) > first_extra_arg)) {
182-
zval *end = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
183-
zval *p = end + (ZEND_CALL_NUM_ARGS(call) - first_extra_arg);
179+
if (ZEND_CALL_INFO(call) & ZEND_CALL_FREE_EXTRA_ARGS) {
180+
zval *end = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
181+
zval *p = end + (ZEND_CALL_NUM_ARGS(call) - call->func->op_array.num_args);
184182
do {
185183
p--;
186184
zval_ptr_dtor_nogc(p);

Zend/zend_types.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
264264
#define Z_COUNTED_P(zval_p) Z_COUNTED(*(zval_p))
265265

266266
#define Z_TYPE_FLAGS_SHIFT 8
267-
#define Z_CONST_FLAGS_SHIFT 8
267+
#define Z_CONST_FLAGS_SHIFT 16
268268

269269
#define GC_REFCOUNT(p) ((zend_refcounted*)(p))->refcount
270270
#define GC_TYPE(p) ((zend_refcounted*)(p))->u.v.type
@@ -286,10 +286,10 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
286286

287287
/* zval.u1.v.type_flags */
288288
#define IS_TYPE_CONSTANT (1<<0)
289-
#define IS_TYPE_REFCOUNTED (1<<1)
290-
#define IS_TYPE_COLLECTABLE (1<<2)
291-
#define IS_TYPE_COPYABLE (1<<3)
292-
#define IS_TYPE_IMMUTABLE (1<<4)
289+
#define IS_TYPE_IMMUTABLE (1<<1)
290+
#define IS_TYPE_REFCOUNTED (1<<2)
291+
#define IS_TYPE_COLLECTABLE (1<<3)
292+
#define IS_TYPE_COPYABLE (1<<4)
293293

294294
/* extended types */
295295
#define IS_INTERNED_STRING_EX IS_STRING

0 commit comments

Comments
 (0)