diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 387f4c8865157..2849c7f7b117f 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2647,6 +2647,31 @@ static bool zend_jit_next_is_send_result(const zend_op *opline) return 0; } +static bool zend_can_jit_compound_binary_op(zend_uchar op, uint32_t op1_info, uint32_t op2_info) +{ + switch (op) { + case ZEND_POW: + case ZEND_DIV: + // TODO: check for division by zero ??? + return false; + case ZEND_ADD: + case ZEND_SUB: + case ZEND_MUL: + return (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) + && (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)); + case ZEND_BW_OR: + case ZEND_BW_AND: + case ZEND_BW_XOR: + case ZEND_SL: + case ZEND_SR: + case ZEND_MOD: + return (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG); + case ZEND_CONCAT: + return (op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING); + EMPTY_SWITCH_DEFAULT_CASE() + } +} + static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *rt_opline) { int b, i, end; @@ -3058,11 +3083,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } goto done; case ZEND_ASSIGN_OP: - if (opline->extended_value == ZEND_POW - || opline->extended_value == ZEND_DIV) { - // TODO: check for division by zero ??? - break; - } if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) { break; } @@ -3074,29 +3094,9 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) { break; } - if (opline->extended_value == ZEND_ADD - || opline->extended_value == ZEND_SUB - || opline->extended_value == ZEND_MUL - || opline->extended_value == ZEND_DIV) { - if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) - || !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) { - break; - } - } else if (opline->extended_value == ZEND_BW_OR - || opline->extended_value == ZEND_BW_AND - || opline->extended_value == ZEND_BW_XOR - || opline->extended_value == ZEND_SL - || opline->extended_value == ZEND_SR - || opline->extended_value == ZEND_MOD) { - if (!(op1_info & MAY_BE_LONG) - || !(op2_info & MAY_BE_LONG)) { - break; - } - } else if (opline->extended_value == ZEND_CONCAT) { - if (!(op1_info & MAY_BE_STRING) - || !(op2_info & MAY_BE_STRING)) { - break; - } + if (!zend_can_jit_compound_binary_op( + opline->extended_value, op1_info, op2_info)) { + break; } op1_def_info = OP1_DEF_INFO(); if (!zend_jit_assign_op(&dasm_state, opline, @@ -3108,17 +3108,16 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } goto done; case ZEND_ASSIGN_DIM_OP: - if (opline->extended_value == ZEND_POW - || opline->extended_value == ZEND_DIV) { - // TODO: check for division by zero ??? - break; - } if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) { break; } if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) { break; } + if (!zend_can_jit_compound_binary_op( + opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) { + break; + } if (!zend_jit_assign_dim_op(&dasm_state, opline, OP1_INFO(), OP1_DEF_INFO(), OP1_REG_ADDR(), OP2_INFO(), OP1_DATA_INFO(), OP1_DATA_RANGE(), @@ -3183,11 +3182,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } goto done; case ZEND_ASSIGN_OBJ_OP: - if (opline->extended_value == ZEND_POW - || opline->extended_value == ZEND_DIV) { - // TODO: check for division by zero ??? - break; - } if (opline->result_type != IS_UNUSED) { break; } @@ -3199,6 +3193,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) { break; } + if (!zend_can_jit_compound_binary_op( + opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) { + break; + } ce = NULL; ce_is_instanceof = 0; if (opline->op1_type == IS_UNUSED) { diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index e0dbcd6731946..b8694c58b0a99 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -4316,11 +4316,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } goto done; case ZEND_ASSIGN_OP: - if (opline->extended_value == ZEND_POW - || opline->extended_value == ZEND_DIV) { - // TODO: check for division by zero ??? - break; - } if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) { break; } @@ -4331,29 +4326,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) { break; } - if (opline->extended_value == ZEND_ADD - || opline->extended_value == ZEND_SUB - || opline->extended_value == ZEND_MUL - || opline->extended_value == ZEND_DIV) { - if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) - || !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) { - break; - } - } else if (opline->extended_value == ZEND_BW_OR - || opline->extended_value == ZEND_BW_AND - || opline->extended_value == ZEND_BW_XOR - || opline->extended_value == ZEND_SL - || opline->extended_value == ZEND_SR - || opline->extended_value == ZEND_MOD) { - if (!(op1_info & MAY_BE_LONG) - || !(op2_info & MAY_BE_LONG)) { - break; - } - } else if (opline->extended_value == ZEND_CONCAT) { - if (!(op1_info & MAY_BE_STRING) - || !(op2_info & MAY_BE_STRING)) { - break; - } + if (!zend_can_jit_compound_binary_op( + opline->extended_value, op1_info, op2_info)) { + break; } op1_def_info = OP1_DEF_INFO(); if (op1_def_info & MAY_BE_GUARD @@ -4383,6 +4358,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par if (opline->result_type != IS_UNUSED) { break; } + if (!zend_can_jit_compound_binary_op( + opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) { + break; + } op1_info = OP1_INFO(); op1_addr = OP1_REG_ADDR(); if (opline->op1_type == IS_VAR) { @@ -4489,11 +4468,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } goto done; case ZEND_ASSIGN_OBJ_OP: - if (opline->extended_value == ZEND_POW - || opline->extended_value == ZEND_DIV) { - // TODO: check for division by zero ??? - break; - } if (opline->result_type != IS_UNUSED) { break; } @@ -4502,6 +4476,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') { break; } + if (!zend_can_jit_compound_binary_op( + opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) { + break; + } ce = NULL; ce_is_instanceof = 0; delayed_fetch_this = 0; diff --git a/ext/opcache/tests/jit/assign_dim_op_001.phpt b/ext/opcache/tests/jit/assign_dim_op_001.phpt index 86fdd94181b53..a533cbe9c283b 100644 --- a/ext/opcache/tests/jit/assign_dim_op_001.phpt +++ b/ext/opcache/tests/jit/assign_dim_op_001.phpt @@ -41,6 +41,9 @@ function false_to_array_nested_invalid_index($a) { $a[[]][0] += 1; return $a; } +function modulo_string($a) { + $a[] %= ""; +} false_to_array(false); false_to_array_append(false); @@ -56,6 +59,11 @@ try { } catch (Error $e) { echo $e->getMessage(), "\n"; } +try { + var_dump(modulo_string([])); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} ?> --EXPECTF-- @@ -97,3 +105,4 @@ array(1) { Deprecated: Automatic conversion of false to array is deprecated in %s on line %d Illegal offset type +Unsupported operand types: null % string