goto jit_failure;
}
goto done;
+ case ZEND_IN_ARRAY:
+ if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
+ break;
+ }
+ op1_info = OP1_INFO();
+ if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_STRING) {
+ break;
+ }
+ if ((opline->result_type & IS_TMP_VAR)
+ && (i + 1) <= end
+ && ((opline+1)->opcode == ZEND_JMPZ
+ || (opline+1)->opcode == ZEND_JMPNZ
+ || (opline+1)->opcode == ZEND_JMPZNZ)
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ smart_branch_opcode = (opline+1)->opcode;
+ target_label = ssa->cfg.blocks[b].successors[0];
+ target_label2 = ssa->cfg.blocks[b].successors[1];
+ } else {
+ smart_branch_opcode = 0;
+ target_label = target_label2 = (uint32_t)-1;
+ }
+ if (!zend_jit_in_array(&dasm_state, opline,
+ op1_info, OP1_REG_ADDR(),
+ smart_branch_opcode, target_label, target_label2,
+ NULL)) {
+ goto jit_failure;
+ }
+ goto done;
case ZEND_FETCH_DIM_R:
case ZEND_FETCH_DIM_IS:
case ZEND_FETCH_LIST_R:
}
ADD_OP1_TRACE_GUARD();
break;
+ case ZEND_IN_ARRAY:
+ if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
+ break;
+ }
+ ADD_OP1_TRACE_GUARD();
+ break;
case ZEND_ISSET_ISEMPTY_DIM_OBJ:
if ((opline->extended_value & ZEND_ISEMPTY)) {
// TODO: support for empty() ???
goto jit_failure;
}
goto done;
+ case ZEND_IN_ARRAY:
+ if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
+ break;
+ }
+ op1_info = OP1_INFO();
+ op1_addr = OP1_REG_ADDR();
+ CHECK_OP1_TRACE_TYPE();
+ if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_STRING) {
+ break;
+ }
+ if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
+ zend_bool exit_if_true = 0;
+ const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
+ uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
+
+ exit_addr = zend_jit_trace_get_exit_addr(exit_point);
+ if (!exit_addr) {
+ goto jit_failure;
+ }
+ smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
+ } else {
+ smart_branch_opcode = 0;
+ exit_addr = NULL;
+ }
+ if (!zend_jit_in_array(&dasm_state, opline,
+ op1_info, op1_addr,
+ smart_branch_opcode, -1, -1, exit_addr)) {
+ goto jit_failure;
+ }
+ goto done;
case ZEND_FETCH_DIM_FUNC_ARG:
if (!JIT_G(current_frame)
|| !JIT_G(current_frame)->call
return 1;
}
+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)
+{
+ HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
+ ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
+
+ | // result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
+ | LOAD_ADDR FCARG1a, ht
+ | GET_ZVAL_PTR FCARG2a, op1_addr
+ if (opline->op1_type != IS_CONST) {
+ | EXT_CALL zend_hash_find, r0
+ } else {
+ | EXT_CALL _zend_hash_find_known_hash, r0
+ }
+ | test r0, r0
+ if (exit_addr) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ | jz &exit_addr
+ } else {
+ | jnz &exit_addr
+ }
+ } else if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ | jz =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ | jnz =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ | jz =>target_label
+ | jmp =>target_label2
+ } else {
+ ZEND_UNREACHABLE();
+ }
+ } else {
+ | setnz al
+ | movzx eax, al
+ | lea eax, [eax + IS_FALSE]
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+
+ return 1;
+}
+
static zend_bool zend_jit_noref_guard(dasm_State **Dst, const zend_op *opline, zend_jit_addr var_addr)
{
int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);