Skip to content

Commit 71cc1f1

Browse files
committed
Add zend_jit_trace support for ZEND_COUNT
1 parent a489362 commit 71cc1f1

File tree

4 files changed

+66
-38
lines changed

4 files changed

+66
-38
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3215,7 +3215,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
32153215
if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
32163216
break;
32173217
}
3218-
if (!zend_jit_count(&dasm_state, opline, op_array, op1_info)) {
3218+
if (!zend_jit_count(&dasm_state, opline, op1_info, OP1_REG_ADDR())) {
32193219
goto jit_failure;
32203220
}
32213221
goto done;

ext/opcache/jit/zend_jit_trace.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
15811581
/* break missing intentionally */
15821582
case ZEND_ECHO:
15831583
case ZEND_STRLEN:
1584+
case ZEND_COUNT:
15841585
case ZEND_QM_ASSIGN:
15851586
case ZEND_FE_RESET_R:
15861587
case ZEND_FE_FETCH_R:
@@ -5497,6 +5498,33 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
54975498
goto jit_failure;
54985499
}
54995500
goto done;
5501+
case ZEND_COUNT:
5502+
op1_info = OP1_INFO();
5503+
CHECK_OP1_TRACE_TYPE();
5504+
if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
5505+
break;
5506+
}
5507+
op1_info = OP1_INFO();
5508+
op1_addr = OP1_REG_ADDR();
5509+
if (orig_op1_type == (IS_TRACE_REFERENCE|IS_ARRAY)) {
5510+
if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5511+
!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5512+
goto jit_failure;
5513+
}
5514+
if (opline->op1_type == IS_CV
5515+
&& ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5516+
ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5517+
}
5518+
} else {
5519+
CHECK_OP1_TRACE_TYPE();
5520+
if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
5521+
break;
5522+
}
5523+
}
5524+
if (!zend_jit_count(&dasm_state, opline, op1_info, op1_addr)) {
5525+
goto jit_failure;
5526+
}
5527+
goto done;
55005528
case ZEND_FETCH_THIS:
55015529
delayed_fetch_this = 0;
55025530
if (ssa_op->result_def >= 0 && opline->result_type != IS_CV) {

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14249,6 +14249,37 @@ static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1
1424914249
return 1;
1425014250
}
1425114251

14252+
static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
14253+
{
14254+
zend_jit_addr res_addr = RES_ADDR();
14255+
14256+
if (opline->op1_type == IS_CONST) {
14257+
return 0;
14258+
/*
14259+
zval *zv;
14260+
zend_long count;
14261+
14262+
zv = RT_CONSTANT(opline, opline->op1);
14263+
ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
14264+
count = zend_hash_num_elements(Z_ARRVAL_P(zv));
14265+
14266+
| SET_ZVAL_LVAL res_addr, count
14267+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14268+
*/
14269+
} else {
14270+
ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
14271+
// Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
14272+
14273+
| GET_ZVAL_PTR r0, op1_addr
14274+
// Sign-extend the 32-bit value to a potentially 64-bit zend_long
14275+
| mov eax, dword [r0 + offsetof(HashTable, nNumOfElements)]
14276+
| SET_ZVAL_LVAL res_addr, r0
14277+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14278+
| FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
14279+
}
14280+
return 1;
14281+
}
14282+
1425214283
static int zend_jit_load_this(dasm_State **Dst, uint32_t var)
1425314284
{
1425414285
zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
@@ -15024,43 +15055,6 @@ static int zend_jit_fetch_constant(dasm_State **Dst,
1502415055
return 1;
1502515056
}
1502615057

15027-
static int zend_jit_count(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
15028-
{
15029-
zend_jit_addr res_addr = RES_ADDR();
15030-
15031-
if (opline->op1_type == IS_CONST) {
15032-
zval *zv;
15033-
size_t count;
15034-
15035-
zv = RT_CONSTANT(opline, opline->op1);
15036-
ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
15037-
count = zend_array_count(Z_ARRVAL_P(zv));
15038-
15039-
| SET_ZVAL_LVAL res_addr, count
15040-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
15041-
} else {
15042-
zend_jit_addr op1_addr = OP1_ADDR();
15043-
15044-
ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
15045-
// Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
15046-
15047-
| GET_ZVAL_PTR FCARG1a, op1_addr
15048-
| mov r0, [FCARG1a + offsetof(HashTable, nNumOfElements)]
15049-
| SET_ZVAL_LVAL res_addr, r0
15050-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
15051-
if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
15052-
// Temporary expressions need to be freed.
15053-
// Anything containing objects or resources might throw when freed due to the destructors.
15054-
zend_bool gc = (op1_info & (MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) != 0;
15055-
| ZVAL_PTR_DTOR op1_addr, op1_info, gc, 0, opline
15056-
if (gc) {
15057-
zend_jit_check_exception(Dst);
15058-
}
15059-
}
15060-
}
15061-
return 1;
15062-
}
15063-
1506415058
static int zend_jit_in_array(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
1506515059
{
1506615060
HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));

ext/opcache/tests/jit/count_001.phpt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ class C {
2626
echo count($a) . "\n";
2727
}
2828
}
29+
public static function count_ref(array &$ref): int {
30+
return count($ref);
31+
}
2932
}
3033
C::foo();
34+
$x = ['x', 'y', 'z', 'a', new stdClass()];
35+
echo C::count_ref($x), "\n";
3136
--EXPECT--
3237
0
3338
1
@@ -36,3 +41,4 @@ C::foo();
3641
2
3742
3
3843
4
44+
5

0 commit comments

Comments
 (0)