From 8e879b9f4452e88bb22cf323df0969ea0f4e3e28 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 18 Mar 2020 23:56:03 +0300 Subject: [PATCH] JIT for ZEND_CHECK_FUNC_ARG --- ext/opcache/Optimizer/zend_inference.c | 1 + ext/opcache/jit/zend_jit.c | 8 ++++ ext/opcache/jit/zend_jit_internal.h | 1 + ext/opcache/jit/zend_jit_trace.c | 15 +++++++ ext/opcache/jit/zend_jit_x86.dasc | 57 ++++++++++++++++++++++++++ 5 files changed, 82 insertions(+) diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index b6bf6eb474..34d6286769 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -4327,6 +4327,7 @@ int zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ case ZEND_FUNC_NUM_ARGS: case ZEND_FUNC_GET_ARGS: case ZEND_COPY_TMP: + case ZEND_CHECK_FUNC_ARG: return 0; case ZEND_INIT_FCALL: /* can't throw, because call is resolved at compile time */ diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index ccff9e097d..012b42b48c 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2480,6 +2480,14 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op goto jit_failure; } goto done; + case ZEND_CHECK_FUNC_ARG: + if (opline->op2.num > MAX_ARG_FLAG_NUM) { + break; + } + if (!zend_jit_check_func_arg(&dasm_state, opline, op_array)) { + goto jit_failure; + } + goto done; case ZEND_DO_UCALL: is_terminated = 1; /* break missing intentionally */ diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index 504cb67065..922f4b25ac 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -336,6 +336,7 @@ struct _zend_jit_trace_stack_frame { int8_t return_value_used; int8_t nested; int8_t num_args; + int8_t last_send_by_ref; }; int return_ssa_var; }; diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 242ab347da..ed4672d3fc 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1664,6 +1664,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par frame->return_value_used = -1; frame->nested = 0; frame->num_args = -1; + frame->last_send_by_ref = -1; stack = frame->stack; if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) { @@ -2232,6 +2233,17 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } } goto done; + case ZEND_CHECK_FUNC_ARG: + if (opline->op2.num > MAX_ARG_FLAG_NUM + && (!JIT_G(current_frame) + || !JIT_G(current_frame)->call + || !JIT_G(current_frame)->call->func)) { + break; + } + if (!zend_jit_check_func_arg(&dasm_state, opline, op_array)) { + goto jit_failure; + } + goto done; case ZEND_DO_UCALL: case ZEND_DO_ICALL: case ZEND_DO_FCALL_BY_NAME: @@ -2861,6 +2873,7 @@ done: call->func = (const zend_function*)op_array; call->nested = 0; call->num_args = -1; // TODO: should be possible to get the real number ??? + call->last_send_by_ref = -1; top = zend_jit_trace_call_frame(top, op_array); i = 0; while (i < p->op_array->num_args) { @@ -2908,6 +2921,7 @@ done: frame->return_value_used = -1; frame->nested = 0; frame->num_args = -1; + frame->last_send_by_ref = -1; stack = frame->stack; for (i = 0; i < op_array->last_var + op_array->T; i++) { /* Initialize abstract stack using SSA */ @@ -2937,6 +2951,7 @@ done: call->func = p->func; call->nested = 1; call->num_args = find_call_num_args(p-1); + call->last_send_by_ref = p->fake ? -1 : 0; frame->call = call; top = zend_jit_trace_call_frame(top, p->op_array); if (p->func->type == ZEND_USER_FUNCTION) { diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 2cb8955ff2..a9b0888ab1 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -8728,6 +8728,63 @@ static int zend_jit_send_var(dasm_State **Dst, const zend_op *opline, const zend return 1; } +static int zend_jit_check_func_arg(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array) +{ + uint32_t arg_num = opline->op2.num; + + if (zend_jit_trigger == ZEND_JIT_ON_HOT_TRACE + && JIT_G(current_frame) + && JIT_G(current_frame)->call + && JIT_G(current_frame)->call->func) { + if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) { + if (JIT_G(current_frame)->call->last_send_by_ref != 1) { + JIT_G(current_frame)->call->last_send_by_ref = 1; + | // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF); + || if (reuse_ip) { + | or dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF + || } else { + | mov r0, EX->call + | or dword [r0 + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF + || } + } + } else { + if (JIT_G(current_frame)->call->last_send_by_ref != 0) { + JIT_G(current_frame)->call->last_send_by_ref = 0; + | // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF); + || if (reuse_ip) { + | and dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF + || } else { + | mov r0, EX->call + | and dword [r0 + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF + || } + } + } + } else { + // if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2); + + if (!reuse_ip) { + zend_jit_start_reuse_ip(); + | // call = EX(call); + | mov RX, EX->call + } + | mov r0, EX:RX->func + | test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask + | jnz >1 + |.cold_code + |1: + | // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF); + | or dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF + | jmp >1 + |.code + | // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF); + | and dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF + |1: + } + + return 1; +} + static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2) { if (smart_branch_opcode) { -- 2.40.0