Skip to content

Commit 7793bc8

Browse files
committed
Improved type inference. Result of opcodes using ZVAL_COPY_DEREF can't be MAY_BE_REF.
1 parent 0778359 commit 7793bc8

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

ext/opcache/Optimizer/zend_inference.c

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,14 +2030,27 @@ static void handle_type_narrowing(const zend_op_array *op_array, zend_ssa *ssa,
20302030
}
20312031
}
20322032

2033-
uint32_t zend_array_element_type(uint32_t t1, int write, int insert)
2033+
uint32_t zend_array_element_type(zend_op *opline, uint32_t t1)
20342034
{
20352035
uint32_t tmp = 0;
2036+
int write = (opline->opcode != ZEND_FETCH_DIM_R
2037+
&& opline->opcode != ZEND_FETCH_DIM_IS
2038+
&& opline->opcode != ZEND_FETCH_LIST_R);
20362039

20372040
if (t1 & MAY_BE_OBJECT) {
2038-
tmp |= MAY_BE_ANY | MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2041+
if (!write) {
2042+
/* can't be REF because of ZVAL_COPY_DEREF() usage */
2043+
tmp |= MAY_BE_ANY | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2044+
} else {
2045+
tmp |= MAY_BE_ANY | MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2046+
}
20392047
}
20402048
if (t1 & MAY_BE_ARRAY) {
2049+
int insert = (opline->opcode == ZEND_FETCH_DIM_W
2050+
|| opline->opcode == ZEND_FETCH_DIM_RW
2051+
|| opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
2052+
|| opline->opcode == ZEND_FETCH_LIST_W)
2053+
&& opline->op2_type == IS_UNUSED;
20412054
if (insert) {
20422055
tmp |= MAY_BE_NULL;
20432056
} else {
@@ -2046,7 +2059,12 @@ uint32_t zend_array_element_type(uint32_t t1, int write, int insert)
20462059
tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
20472060
}
20482061
if (t1 & MAY_BE_ARRAY_OF_REF) {
2049-
tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN;
2062+
if (opline->opcode == ZEND_FETCH_DIM_R) {
2063+
/* can't be REF because of ZVAL_COPY_DEREF() usage */
2064+
tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2065+
} else {
2066+
tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN;
2067+
}
20502068
} else if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
20512069
tmp |= MAY_BE_RC1 | MAY_BE_RCN;
20522070
}
@@ -2467,7 +2485,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
24672485
tmp |= MAY_BE_REF;
24682486
}
24692487
orig = t1;
2470-
t1 = zend_array_element_type(t1, 1, 0);
2488+
t1 = zend_array_element_type(opline, t1);
24712489
t2 = OP1_DATA_INFO();
24722490
} else {
24732491
if (t1 & MAY_BE_REF) {
@@ -3278,11 +3296,8 @@ static int zend_update_type_info(const zend_op_array *op_array,
32783296
COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def);
32793297
}
32803298
/* FETCH_LIST on a string behaves like FETCH_R on null */
3281-
tmp = zend_array_element_type(
3282-
opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL),
3283-
opline->opcode != ZEND_FETCH_DIM_R && opline->opcode != ZEND_FETCH_DIM_IS
3284-
&& opline->opcode != ZEND_FETCH_LIST_R,
3285-
opline->op2_type == IS_UNUSED);
3299+
tmp = zend_array_element_type(opline,
3300+
opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL));
32863301
if (opline->opcode == ZEND_FETCH_DIM_W ||
32873302
opline->opcode == ZEND_FETCH_DIM_RW ||
32883303
opline->opcode == ZEND_FETCH_DIM_FUNC_ARG ||
@@ -3327,6 +3342,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
33273342
if (ssa_ops[i].result_def >= 0) {
33283343
tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
33293344
if (opline->opcode == ZEND_FETCH_OBJ_R || opline->opcode == ZEND_FETCH_OBJ_IS) {
3345+
/* can't be REF because of ZVAL_COPY_DEREF() usage */
33303346
tmp |= MAY_BE_RC1 | MAY_BE_RCN;
33313347
} else {
33323348
tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ERROR;
@@ -3431,6 +3447,14 @@ static int zend_update_type_info(const zend_op_array *op_array,
34313447
/* Forbidden opcodes */
34323448
ZEND_ASSERT(0);
34333449
break;
3450+
case ZEND_FETCH_R:
3451+
case ZEND_FETCH_IS:
3452+
case ZEND_FETCH_STATIC_PROP_R:
3453+
case ZEND_FETCH_STATIC_PROP_IS:
3454+
/* can't be REF because of ZVAL_COPY_DEREF() usage */
3455+
tmp = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3456+
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
3457+
break;
34343458
default:
34353459
unknown_opcode:
34363460
if (ssa_ops[i].op1_def >= 0) {

ext/opcache/Optimizer/zend_inference.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ss
245245
int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa);
246246
int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level);
247247

248-
uint32_t zend_array_element_type(uint32_t t1, int write, int insert);
248+
uint32_t zend_array_element_type(zend_op *opline, uint32_t t1);
249249

250250
int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp);
251251
void zend_inference_init_range(const zend_op_array *op_array, zend_ssa *ssa, int var, zend_bool underflow, zend_long min, zend_long max, zend_bool overflow);

0 commit comments

Comments
 (0)