Improved tracing JIT for nested calls

This commit is contained in:
Dmitry Stogov 2020-04-29 18:24:18 +03:00
parent 0e0c608ce0
commit 65934d31d1
4 changed files with 30 additions and 16 deletions

View File

@ -363,6 +363,7 @@ struct _zend_jit_trace_stack_frame {
zend_jit_trace_stack_frame *call;
zend_jit_trace_stack_frame *prev;
const zend_function *func;
uint32_t call_level;
uint32_t _info;
zend_jit_trace_stack stack[1];
};
@ -384,6 +385,7 @@ struct _zend_jit_trace_stack_frame {
_frame->call = NULL; \
_frame->prev = NULL; \
_frame->func = (const zend_function*)_func; \
_frame->call_level = 0; \
_frame->_info = (((uint32_t)(num_args)) << TRACE_FRAME_SHIFT_NUM_ARGS) & TRACE_FRAME_MASK_NUM_ARGS; \
if (nested) { \
_frame->_info |= TRACE_FRAME_MASK_NESTED; \

View File

@ -1614,8 +1614,12 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
v++;
}
if (return_value_info.type != 0) {
if ((p+1)->op == ZEND_JIT_TRACE_VM) {
const zend_op *opline = (p+1)->opline - 1;
zend_jit_trace_rec *q = p + 1;
while (q->op == ZEND_JIT_TRACE_INIT_CALL) {
q++;
}
if (q->op == ZEND_JIT_TRACE_VM) {
const zend_op *opline = q->opline - 1;
if (opline->result_type != IS_UNUSED) {
ssa_var_info[
p->first_ssa_var +
@ -2429,7 +2433,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
const zend_op_array *op_array;
zend_ssa *ssa, *op_array_ssa;
zend_jit_trace_rec *p;
int call_level = -1; // TODO: proper support for inlined functions ???
zend_jit_op_array_trace_extension *jit_extension;
int num_op_arrays = 0;
zend_jit_trace_info *t;
@ -2671,8 +2674,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
p++;
}
#if 0
// TODO: call level calculation doesn't work for traces ???
switch (opline->opcode) {
case ZEND_INIT_FCALL:
case ZEND_INIT_FCALL_BY_NAME:
@ -2682,9 +2683,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_INIT_USER_CALL:
case ZEND_NEW:
call_level++;
frame->call_level++;
}
#endif
if (zend_jit_level >= ZEND_JIT_LEVEL_INLINE) {
switch (opline->opcode) {
@ -3043,7 +3043,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
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, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, op_array_ssa, call_level, p + 1)) {
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, op_array_ssa, frame->call_level, p + 1)) {
goto jit_failure;
}
goto done;
@ -3128,7 +3128,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
case ZEND_DO_ICALL:
case ZEND_DO_FCALL_BY_NAME:
case ZEND_DO_FCALL:
if (!zend_jit_do_fcall(&dasm_state, opline, op_array, op_array_ssa, call_level, -1, p + 1)) {
if (!zend_jit_do_fcall(&dasm_state, opline, op_array, op_array_ssa, frame->call_level, -1, p + 1)) {
goto jit_failure;
}
goto done;
@ -3608,16 +3608,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
}
done:
#if 0
// TODO: call level calculation doesn't work for traces ???
switch (opline->opcode) {
case ZEND_DO_FCALL:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
call_level--;
frame->call_level--;
}
#endif
if (ra) {
zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
@ -3946,6 +3943,7 @@ done:
if (!skip_guard && !zend_jit_init_fcall_guard(&dasm_state, NULL, p->func)) {
goto jit_failure;
}
frame->call_level++;
}
} else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
call = frame->call;

View File

@ -696,6 +696,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
if (rc == 1) {
#endif
/* Enter into function */
prev_call = NULL;
if (level > ZEND_JIT_TRACE_MAX_CALL_DEPTH) {
stop = ZEND_JIT_TRACE_STOP_TOO_DEEP;
break;
@ -726,6 +727,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
level++;
} else {
/* Return from function */
prev_call = EX(call);
if (level == 0) {
if (is_toplevel) {
stop = ZEND_JIT_TRACE_STOP_TOPLEVEL;
@ -757,6 +759,10 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
unrolled_calls[ret_level] = &EX(func)->op_array;
ret_level++;
is_toplevel = EX(func)->op_array.function_name == NULL;
if (prev_call) {
idx = zend_jit_trace_record_fake_init_call(prev_call, trace_buffer, idx);
}
#endif
} else if (start & ZEND_JIT_TRACE_START_LOOP
&& !zend_jit_trace_bad_loop_exit(orig_opline)) {
@ -785,8 +791,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
offset = jit_extension->offset;
}
if (EX(call) != prev_call) {
if (trace_buffer[idx-1].op != ZEND_JIT_TRACE_BACK
&& EX(call)
if (EX(call)
&& EX(call)->prev_execute_data == prev_call) {
if (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
/* TODO: Can we continue recording ??? */
@ -868,6 +873,13 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
}
}
if (stop == ZEND_JIT_TRACE_STOP_LINK) {
/* Shrink fake INIT_CALLs */
while (trace_buffer[idx-1].op == ZEND_JIT_TRACE_INIT_CALL && trace_buffer[idx-1].fake) {
idx--;
}
}
TRACE_END(ZEND_JIT_TRACE_END, stop, opline);
#ifdef HAVE_GCC_GLOBAL_REGS

View File

@ -9471,7 +9471,9 @@ static int zend_jit_leave_func(dasm_State **Dst, const zend_op *opline, const ze
const void *exit_addr;
zend_jit_trace_stack_frame *current_frame;
trace++;
do {
trace++;
} while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
next_opline = trace->opline;
current_frame = JIT_G(current_frame);