From: Dmitry Stogov Date: Tue, 8 Sep 2020 18:03:51 +0000 (+0300) Subject: JIT for IN_ARRAY instruction. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b106463d371f53b6db768b6bf3e42301b93a1296;p=php JIT for IN_ARRAY instruction. --- diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 9abd39dcec..718117a56a 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2810,6 +2810,36 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op 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: diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index f79710daf8..8da6e899df 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1518,6 +1518,12 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin } 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() ??? @@ -4210,6 +4216,36 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par 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 diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 26751aa7fc..f44a472b95 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -12754,6 +12754,50 @@ static int zend_jit_fetch_constant(dasm_State **Dst, const zend_op *opline) 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);