@@ -12749,25 +12749,62 @@ static int zend_jit_fetch_dim_read(zend_jit_ctx *jit,
1274912749 ir_IF_TRUE(if_type);
1275012750 }
1275112751 }
12752- jit_SET_EX_OPLINE(jit, opline);
1275312752 str_ref = jit_Z_PTR(jit, op1_addr);
12754- if (opline->opcode != ZEND_FETCH_DIM_IS) {
12755- ir_ref ref;
1275612753
12757- if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12758- ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12759- str_ref, jit_Z_LVAL(jit, op2_addr));
12760- } else {
12761- ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12762- str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12763- }
12754+ /* Inlined offset read for integer offsets into strings. */
12755+ if (opline->opcode != ZEND_FETCH_DIM_IS
12756+ && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING
12757+ && (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12758+ ir_ref offset_ref = jit_Z_LVAL(jit, op2_addr);
12759+ ir_ref len_ref = ir_LOAD_L(ir_ADD_OFFSET(str_ref, offsetof(zend_string, len)));
12760+ ir_ref real_offset_ref = offset_ref;
12761+ if (!op2_range || op2_range->min < 0) {
12762+ // JIT: if (offset < 0) offset += ZSTR_LEN(str);
12763+ /* Branchless way to add -1 for negative offsets to the string length. */
12764+ real_offset_ref = ir_ADD_L(offset_ref,
12765+ ir_AND_L(len_ref,
12766+ ir_SAR_L(offset_ref, ir_CONST_LONG(SIZEOF_ZEND_LONG * 8 - 1))));
12767+ }
12768+
12769+ /* An offset that is still negative wraps around and fails this check as well. */
12770+ ir_ref if_in_range = ir_IF(ir_ULT(real_offset_ref, len_ref));
12771+
12772+ ir_IF_TRUE(if_in_range);
12773+ // JIT: result = ZSTR_CHAR((uint8_t)ZSTR_VAL(str)[offset]);
12774+ ir_ref ref = ir_LOAD_A(
12775+ ir_ADD_A(
12776+ ir_CONST_ADDR(zend_one_char_string),
12777+ ir_MUL_A(
12778+ ir_ZEXT_A(
12779+ ir_LOAD_U8(
12780+ ir_ADD_A(ir_ADD_OFFSET(str_ref, offsetof(zend_string, val)),
12781+ ir_BITCAST_A(real_offset_ref)))),
12782+ ir_CONST_ADDR(sizeof(zend_string*)))));
12783+ ir_ref fast_path = ir_END();
12784+
12785+ ir_IF_FALSE_cold(if_in_range);
12786+ jit_SET_EX_OPLINE(jit, opline);
12787+ ir_ref slow_ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12788+ str_ref, offset_ref);
12789+
12790+ ir_MERGE_WITH(fast_path);
12791+ ref = ir_PHI_2(IR_ADDR, slow_ref, ref);
1276412792 jit_set_Z_PTR(jit, res_addr, ref);
1276512793 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
1276612794 } else {
12767- ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12768- str_ref,
12769- jit_ZVAL_ADDR(jit, op2_addr),
12770- jit_ZVAL_ADDR(jit, res_addr));
12795+ jit_SET_EX_OPLINE(jit, opline);
12796+ if (opline->opcode != ZEND_FETCH_DIM_IS) {
12797+ ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12798+ str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12799+
12800+ jit_set_Z_PTR(jit, res_addr, ref);
12801+ jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12802+ } else {
12803+ ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12804+ str_ref,
12805+ jit_ZVAL_ADDR(jit, op2_addr),
12806+ jit_ZVAL_ADDR(jit, res_addr));
12807+ }
1277112808 }
1277212809 ir_END_list(end_inputs);
1277312810 }
0 commit comments