diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 61f29da22ec..aedf2816f7e 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -3304,7 +3304,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op case ZEND_INIT_FCALL: case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: - if (!zend_jit_init_fcall(&dasm_state, opline, b, op_array, ssa, ssa_op, call_level, NULL, 1)) { + if (!zend_jit_init_fcall(&dasm_state, opline, b, op_array, ssa, ssa_op, call_level, NULL, 0)) { goto jit_failure; } goto done; @@ -3895,7 +3895,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } if (!zend_jit_init_method_call(&dasm_state, opline, b, op_array, ssa, ssa_op, call_level, op1_info, op1_addr, ce, ce_is_instanceof, 0, NULL, - NULL, 1, 0)) { + NULL, 0, 0)) { goto jit_failure; } goto done; diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index 770c05f232f..6ac7fc6ebb4 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -8152,15 +8152,19 @@ static int zend_jit_stack_check(dasm_State **Dst, const zend_op *opline, uint32_ return 1; } -static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool use_this, bool stack_check) +static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool use_this, int checked_stack) { uint32_t used_stack; + bool stack_check = 1; // REG0 -> zend_function // FCARG1 -> used_stack if (func) { used_stack = zend_vm_calc_used_stack(opline->extended_value, func); + if ((int)used_stack <= checked_stack) { + stack_check = 0; + } } else { used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value) * sizeof(zval); @@ -8406,7 +8410,7 @@ static int zend_jit_init_fcall_guard(dasm_State **Dst, uint32_t level, const zen return 1; } -static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, bool stack_check) +static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, int checked_stack) { zend_func_info *info = ZEND_FUNC_INFO(op_array); zend_call_info *call_info = NULL; @@ -8514,7 +8518,7 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t |3: } - if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, stack_check)) { + if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, checked_stack)) { return 0; } @@ -8544,7 +8548,7 @@ static int zend_jit_init_method_call(dasm_State **Dst, bool use_this, zend_class_entry *trace_ce, zend_jit_trace_rec *trace, - bool stack_check, + int checked_stack, bool polymorphic_side_trace) { zend_func_info *info = ZEND_FUNC_INFO(op_array); @@ -8728,7 +8732,7 @@ static int zend_jit_init_method_call(dasm_State **Dst, } if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) { - if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, use_this, stack_check)) { + if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, use_this, checked_stack)) { return 0; } } @@ -8758,7 +8762,7 @@ static int zend_jit_init_closure_call(dasm_State **Dst, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, - bool stack_check) + int checked_stack) { zend_function *func = NULL; zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var); @@ -8813,7 +8817,7 @@ static int zend_jit_init_closure_call(dasm_State **Dst, } } - if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, stack_check)) { + if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, checked_stack)) { return 0; } diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 9e9d8c08cca..2e041790a67 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -3756,7 +3756,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par zend_uchar res_type = IS_UNKNOWN; const zend_op *opline, *orig_opline; const zend_ssa_op *ssa_op, *orig_ssa_op; - int used_stack; + int checked_stack; + int peek_checked_stack; uint32_t frame_flags = 0; JIT_G(current_trace) = trace_buffer; @@ -3770,7 +3771,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } ssa_opcodes = ((zend_tssa*)ssa)->tssa_opcodes; - used_stack = ((zend_tssa*)ssa)->used_stack; /* Register allocation */ if ((JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) @@ -3784,6 +3784,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par frame = JIT_G(current_frame); top = zend_jit_trace_call_frame(frame, op_array); TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1); + frame->used_stack = checked_stack = peek_checked_stack = 0; stack = frame->stack; for (i = 0; i < op_array->last_var + op_array->T; i++) { SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1); @@ -3826,8 +3827,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par int last_var; int parent_vars_count = 0; zend_jit_trace_stack *parent_stack = NULL; + int used_stack = ((zend_tssa*)ssa)->used_stack; if (used_stack > 0) { + peek_checked_stack = used_stack; if (!zend_jit_stack_check(&dasm_state, opline, used_stack)) { goto jit_failure; } @@ -4703,7 +4706,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: frame_flags = TRACE_FRAME_MASK_NESTED; - if (!zend_jit_init_fcall(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, used_stack < 0)) { + if (!zend_jit_init_fcall(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) { goto jit_failure; } goto done; @@ -5740,7 +5743,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, op1_info, op1_addr, ce, ce_is_instanceof, delayed_fetch_this, op1_ce, - p + 1, used_stack < 0, polymorphic_side_trace)) { + p + 1, peek_checked_stack - checked_stack, polymorphic_side_trace)) { goto jit_failure; } goto done; @@ -5751,7 +5754,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par op2_info = OP2_INFO(); CHECK_OP2_TRACE_TYPE(); frame_flags = TRACE_FRAME_MASK_NESTED; - if (!zend_jit_init_closure_call(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, used_stack < 0)) { + if (!zend_jit_init_closure_call(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) { goto jit_failure; } goto done; @@ -6183,12 +6186,14 @@ done: op_array_ssa = &jit_extension->func_info.ssa; top = frame; if (frame->prev) { + checked_stack -= frame->used_stack; frame = frame->prev; stack = frame->stack; ZEND_ASSERT(&frame->func->op_array == op_array); } else { frame = zend_jit_trace_ret_frame(frame, op_array); TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1); + frame->used_stack = checked_stack = peek_checked_stack = 0; stack = frame->stack; if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) { uint32_t j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info); @@ -6337,10 +6342,22 @@ done: } if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) { frame->call_level++; + call->used_stack = 0; + } else { + if (p->func) { + call->used_stack = zend_vm_calc_used_stack(init_opline->extended_value, (zend_function*)p->func); + } else { + call->used_stack = (ZEND_CALL_FRAME_SLOT + init_opline->extended_value) * sizeof(zval); + } + checked_stack += call->used_stack; + if (checked_stack > peek_checked_stack) { + peek_checked_stack = checked_stack; + } } } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) { call = frame->call; if (call) { + checked_stack -= call->used_stack; top = call; frame->call = call->prev; } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 67177e7378e..b3ed25161f4 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -8701,12 +8701,16 @@ static int zend_jit_stack_check(dasm_State **Dst, const zend_op *opline, uint32_ return 1; } -static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool use_this, bool stack_check) +static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool use_this, int checked_stack) { uint32_t used_stack; + bool stack_check = 1; if (func) { used_stack = zend_vm_calc_used_stack(opline->extended_value, func); + if ((int)used_stack <= checked_stack) { + stack_check = 0; + } } else { used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value) * sizeof(zval); @@ -8959,7 +8963,7 @@ static int zend_jit_init_fcall_guard(dasm_State **Dst, uint32_t level, const zen return 1; } -static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, bool stack_check) +static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, int checked_stack) { zend_func_info *info = ZEND_FUNC_INFO(op_array); zend_call_info *call_info = NULL; @@ -9095,7 +9099,7 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t |3: } - if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, stack_check)) { + if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, checked_stack)) { return 0; } @@ -9125,7 +9129,7 @@ static int zend_jit_init_method_call(dasm_State **Dst, bool use_this, zend_class_entry *trace_ce, zend_jit_trace_rec *trace, - bool stack_check, + int checked_stack, bool polymorphic_side_trace) { zend_func_info *info = ZEND_FUNC_INFO(op_array); @@ -9340,7 +9344,7 @@ static int zend_jit_init_method_call(dasm_State **Dst, } if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) { - if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, use_this, stack_check)) { + if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, use_this, checked_stack)) { return 0; } } @@ -9370,7 +9374,7 @@ static int zend_jit_init_closure_call(dasm_State **Dst, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, - bool stack_check) + int checked_stack) { zend_function *func = NULL; zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var); @@ -9439,7 +9443,7 @@ static int zend_jit_init_closure_call(dasm_State **Dst, } } - if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, stack_check)) { + if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, checked_stack)) { return 0; }