1
0
mirror of https://github.com/php/php-src.git synced 2026-04-29 11:13:36 +02:00

JIT: Optimize zend_vm_stack_free_args()

Avoid code genearation for destructors of immutable parameters of internal functions that cannot be changed in place.
Keep destructors for immutable array parameters, because few function may modufy them in-pace.
This commit is contained in:
Dmitry Stogov
2021-08-29 17:49:54 +03:00
parent b49d340f74
commit 67d6c2db9f
4 changed files with 67 additions and 16 deletions
+1
View File
@@ -130,6 +130,7 @@ static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op
static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags);
static const void *zend_jit_trace_get_exit_addr(uint32_t n);
static void zend_jit_trace_add_code(const void *start, uint32_t size);
static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info);
#if ZEND_JIT_TARGET_ARM64
static zend_jit_trace_info *zend_jit_get_current_trace_info(void);
+5 -3
View File
@@ -9311,9 +9311,11 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend
| // zend_vm_stack_free_args(call);
if (func && !unknown_num_args) {
for (i = 0; i < call_num_args; i++ ) {
uint32_t offset = EX_NUM_TO_VAR(i);
zend_jit_addr arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
| ZVAL_PTR_DTOR arg_addr, (MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN), 0, 1, opline, ZREG_TMP1, ZREG_TMP2
if (zend_jit_needs_arg_dtor(func, i, call_info)) {
uint32_t offset = EX_NUM_TO_VAR(i);
zend_jit_addr arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
| ZVAL_PTR_DTOR arg_addr, (MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN), 0, 1, opline, ZREG_TMP1, ZREG_TMP2
}
}
} else {
| mov FCARG1x, RX
+57 -11
View File
@@ -444,6 +444,8 @@ static zend_always_inline size_t zend_jit_trace_frame_size(const zend_op_array *
{
if (op_array && op_array->type == ZEND_USER_FUNCTION) {
return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE((op_array->last_var + op_array->T) * sizeof(zend_jit_trace_stack)));
} else if (op_array) {
return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE(op_array->num_args * sizeof(zend_jit_trace_stack)));
} else {
return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack));
}
@@ -465,8 +467,7 @@ static void zend_jit_trace_send_type(const zend_op *opline, zend_jit_trace_stack
const zend_op_array *op_array = &call->func->op_array;
uint32_t arg_num = opline->op2.num;
if (op_array->type != ZEND_USER_FUNCTION
|| arg_num > op_array->num_args) {
if (arg_num > op_array->num_args) {
return;
}
if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
@@ -484,6 +485,52 @@ static void zend_jit_trace_send_type(const zend_op *opline, zend_jit_trace_stack
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type, 1);
}
static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info)
{
if (func
&& func->type == ZEND_INTERNAL_FUNCTION
&& (func->internal_function.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0
&& arg_num < func->internal_function.num_args) {
const zend_internal_arg_info *arg_info = &func->internal_function.arg_info[arg_num];
if (ZEND_ARG_SEND_MODE(arg_info) == ZEND_SEND_BY_VAL
&& ZEND_TYPE_IS_SET(arg_info->type)
&& (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_ANY) != MAY_BE_ANY) {
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
&& JIT_G(current_frame)
&& JIT_G(current_frame)->call
&& JIT_G(current_frame)->call->func) {
uint32_t type = STACK_TYPE(JIT_G(current_frame)->call->stack, arg_num);
if (type != IS_UNKNOWN
&& type < IS_STRING
&& ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type)) {
return 0;
}
}
if (call_info && arg_num < call_info->num_args && call_info->arg_info[arg_num].opline) {
const zend_op *opline = call_info->arg_info[arg_num].opline;
if (opline->opcode == ZEND_SEND_VAL && opline->op1_type == IS_CONST) {
zval *zv = RT_CONSTANT(opline, opline->op1);
if (!Z_REFCOUNTED_P(zv)) {
uint32_t type = Z_TYPE_P(zv);
// TODO: few functions (e.g. pcntl_exec) modify arrays in-place ???
if (type != IS_ARRAY
&& (ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type))) {
return 0;
}
}
}
}
}
}
return 1;
}
static zend_ssa *zend_jit_trace_build_ssa(const zend_op_array *op_array, zend_script *script)
{
zend_jit_op_array_trace_extension *jit_extension;
@@ -3707,9 +3754,7 @@ static bool zend_jit_trace_next_is_send_result(const zend_op *oplin
&& (opline+1)->op2_type != IS_CONST /* Named parameters not supported in JIT */
&& (opline+1)->op1.var == opline->result.var) {
if (frame->call
&& frame->call->func
&& frame->call->func->type == ZEND_USER_FUNCTION) {
if (frame->call && frame->call->func) {
uint8_t res_type = (p+1)->op1_type;
if (res_type != IS_UNKNOWN && !(res_type & IS_TRACE_REFERENCE) ) {
@@ -4726,9 +4771,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op1_info, OP1_REG_ADDR())) {
goto jit_failure;
}
if (frame->call
&& frame->call->func
&& frame->call->func->type == ZEND_USER_FUNCTION) {
if (frame->call && frame->call->func) {
if (opline->op1_type == IS_CONST) {
zend_jit_trace_send_type(opline, frame->call, Z_TYPE_P(RT_CONSTANT(opline, opline->op1)));
} else if (op1_type != IS_UNKNOWN) {
@@ -4787,9 +4830,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
&& ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
ssa->var_info[ssa_op->op1_def].guarded_reference = ssa->var_info[ssa_op->op1_use].guarded_reference;
}
if (frame->call
&& frame->call->func
&& frame->call->func->type == ZEND_USER_FUNCTION) {
if (frame->call && frame->call->func) {
if ((opline->opcode == ZEND_SEND_VAR_EX
|| opline->opcode == ZEND_SEND_FUNC_ARG)
&& ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
@@ -6294,6 +6335,11 @@ done:
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
}
}
} else {
ZEND_ASSERT(p->func->type == ZEND_INTERNAL_FUNCTION);
for (i = 0; i < p->op_array->num_args; i++) {
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
}
}
if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) {
int skip_guard = 0;
+4 -2
View File
@@ -9950,8 +9950,10 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend
| // zend_vm_stack_free_args(call);
if (func && !unknown_num_args) {
for (i = 0; i < call_num_args; i++ ) {
uint32_t offset = EX_NUM_TO_VAR(i);
| ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, 1, opline
if (zend_jit_needs_arg_dtor(func, i, call_info)) {
uint32_t offset = EX_NUM_TO_VAR(i);
| ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, 1, opline
}
}
} else {
| mov FCARG1a, RX