From afc93e44e5e356787c765b103bf133bcda5b640b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 17 Aug 2020 20:48:48 +0300 Subject: [PATCH] JIT for ZEND_ISSET_ISEMPTY_CV --- ext/opcache/jit/zend_jit.c | 27 ++++++++++++ ext/opcache/jit/zend_jit_trace.c | 36 ++++++++++++++++ ext/opcache/jit/zend_jit_x86.dasc | 69 +++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 90bed235d2..e66afd9d2b 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2790,6 +2790,33 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op goto jit_failure; } goto done; + case ZEND_ISSET_ISEMPTY_CV: + if ((opline->extended_value & ZEND_ISEMPTY)) { + // TODO: support for empty() ??? + 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_isset_isempty_cv(&dasm_state, opline, op_array, + 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: if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) { diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index cdddc56602..0d2e187f0d 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1486,6 +1486,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin case ZEND_JMPNZ_EX: case ZEND_BOOL: case ZEND_BOOL_NOT: + case ZEND_ISSET_ISEMPTY_CV: ADD_OP1_TRACE_GUARD(); break; case ZEND_ISSET_ISEMPTY_DIM_OBJ: @@ -3912,6 +3913,41 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par goto jit_failure; } goto done; + case ZEND_ISSET_ISEMPTY_CV: + if ((opline->extended_value & ZEND_ISEMPTY)) { + // TODO: support for empty() ??? + break; + } + op1_info = OP1_INFO(); + op1_addr = OP1_REG_ADDR(); + if (orig_op1_type != IS_UNKNOWN + && (orig_op1_type & IS_TRACE_REFERENCE)) { + if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr, 1)) { + goto jit_failure; + } + } else { + CHECK_OP1_TRACE_TYPE(); + } + 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(opline, exit_opline, p + 1, 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_isset_isempty_cv(&dasm_state, opline, op_array, + 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 8933c0890e..b92783c109 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -12159,6 +12159,75 @@ static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *op return 1; } +static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, 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) +{ + zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); + + // TODO: support for empty() ??? + ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY)); + + if (op1_info & MAY_BE_REF) { + if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) { + | LOAD_ZVAL_ADDR FCARG1a, op1_addr + op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0); + } + | ZVAL_DEREF FCARG1a, op1_info + |1: + } + + if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) { + if (exit_addr) { + ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ); + } else if (smart_branch_opcode) { + if (smart_branch_opcode == ZEND_JMPNZ) { + | jmp =>target_label + } else if (smart_branch_opcode == ZEND_JMPZNZ) { + | jmp =>target_label2 + } + } else { + | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE + } + } else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) { + if (exit_addr) { + ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ); + } else if (smart_branch_opcode) { + if (smart_branch_opcode != ZEND_JMPNZ) { + | jmp =>target_label + } + } else { + | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE + } + } else { + ZEND_ASSERT(Z_MODE(op1_addr) == IS_MEM_ZVAL); + | cmp byte [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)+offsetof(zval, u1.v.type)], IS_NULL + if (exit_addr) { + if (smart_branch_opcode == ZEND_JMPNZ) { + | jg &exit_addr + } else { + | jle &exit_addr + } + } else if (smart_branch_opcode) { + if (smart_branch_opcode == ZEND_JMPZ) { + | jle =>target_label + } else if (smart_branch_opcode == ZEND_JMPNZ) { + | jg =>target_label + } else if (smart_branch_opcode == ZEND_JMPZNZ) { + | jle =>target_label + | jmp =>target_label2 + } else { + ZEND_UNREACHABLE(); + } + } else { + | setg 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, opline, NULL, 0); -- 2.50.1