#define ZEND_JIT_TRACE_MAX_SSA_VAR 0x7ffffe
#define ZEND_JIT_TRACE_SSA_VAR_SHIFT 9
+#define ZEND_JIT_TRACE_FAKE_LEVEL_MASK 0xffff0000
+#define ZEND_JIT_TRACE_FAKE_LEVEL_SHIFT 16
+
+#define ZEND_JIT_TRACE_FAKE_LEVEL(info) \
+ (((info) & ZEND_JIT_TRACE_FAKE_LEVEL_MASK) >> ZEND_JIT_TRACE_FAKE_LEVEL_SHIFT)
+
+#define ZEND_JIT_TRACE_FAKE_INFO(level) \
+ (((level) << ZEND_JIT_TRACE_FAKE_LEVEL_SHIFT) | ZEND_JIT_TRACE_FAKE_INIT_CALL)
+
#define ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(_info, var) do { \
_info |= (var << ZEND_JIT_TRACE_SSA_VAR_SHIFT); \
} while (0)
goto jit_failure;
}
if ((p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func) {
- if (!zend_jit_init_fcall_guard(&dasm_state, (p+1)->func, opline+1)) {
+ if (!zend_jit_init_fcall_guard(&dasm_state, 0, (p+1)->func, opline+1)) {
goto jit_failure;
}
}
if ((opline->op1_type != IS_CONST
|| opline->op2_type != IS_CONST)
&& (p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func) {
- if (!zend_jit_init_fcall_guard(&dasm_state, (p+1)->func, opline+1)) {
+ if (!zend_jit_init_fcall_guard(&dasm_state, 0, (p+1)->func, opline+1)) {
goto jit_failure;
}
}
}
if (opline->op2_type != IS_CONST
&& (p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func) {
- if (!zend_jit_init_fcall_guard(&dasm_state, (p+1)->func, opline+1)) {
+ if (!zend_jit_init_fcall_guard(&dasm_state, 0, (p+1)->func, opline+1)) {
goto jit_failure;
}
}
if (opline->op1_type != IS_CONST
&& (p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func) {
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_OBJECT);
- if (!zend_jit_init_fcall_guard(&dasm_state, (p+1)->func, opline+1)) {
+ if (!zend_jit_init_fcall_guard(&dasm_state, 0, (p+1)->func, opline+1)) {
goto jit_failure;
}
}
opline = q->opline;
ZEND_ASSERT(opline != NULL);
}
- if (!zend_jit_init_fcall_guard(&dasm_state, p->func, opline)) {
+ if (!zend_jit_init_fcall_guard(&dasm_state,
+ ZEND_JIT_TRACE_FAKE_LEVEL(p->info), p->func, opline)) {
goto jit_failure;
}
}
return 0;
}
-static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, zend_bool is_megamorphic, uint32_t *megamorphic, uint32_t level, uint32_t *call_level)
+static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, zend_bool is_megamorphic, uint32_t *megamorphic, uint32_t level, uint32_t init_level, uint32_t *call_level)
{
zend_jit_trace_stop stop ZEND_ATTRIBUTE_UNUSED = ZEND_JIT_TRACE_STOP_ERROR;
zend_jit_op_array_trace_extension *jit_extension;
if (call->prev_execute_data) {
- idx = zend_jit_trace_record_fake_init_call_ex(call->prev_execute_data, trace_buffer, idx, is_megamorphic, megamorphic, level, call_level);
+ idx = zend_jit_trace_record_fake_init_call_ex(call->prev_execute_data, trace_buffer, idx, is_megamorphic, megamorphic, level, init_level + 1, call_level);
if (idx < 0) {
return idx;
}
*megamorphic &= ~(1 << (level + *call_level));
}
(*call_level)++;
- TRACE_RECORD(ZEND_JIT_TRACE_INIT_CALL, ZEND_JIT_TRACE_FAKE_INIT_CALL, func);
+ TRACE_RECORD(ZEND_JIT_TRACE_INIT_CALL, ZEND_JIT_TRACE_FAKE_INFO(init_level), func);
} while (0);
return idx;
}
{
uint32_t call_level = 0;
- return zend_jit_trace_record_fake_init_call_ex(call, trace_buffer, idx, is_megamorphic, megamorphic, level, &call_level);
+ return zend_jit_trace_record_fake_init_call_ex(call, trace_buffer, idx, is_megamorphic, megamorphic, level, 0, &call_level);
}
static int zend_jit_trace_call_level(const zend_execute_data *call)
}
}
-static int zend_jit_init_fcall_guard(dasm_State **Dst, const zend_function *func, const zend_op *to_opline)
+static int zend_jit_init_fcall_guard(dasm_State **Dst, uint32_t level, const zend_function *func, const zend_op *to_opline)
{
int32_t exit_point;
const void *exit_addr;
return 0;
}
+ | // call = EX(call);
+ | mov r1, EX->call
+ while (level > 0) {
+ | mov r1, EX:r1->prev_execute_data
+ level--;
+ }
+
if (func->type == ZEND_USER_FUNCTION &&
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
!func->common.function_name)) {
const zend_op *opcodes = func->op_array.opcodes;
- | // call = EX(call);
- | mov r1, EX->call
| mov r1, aword EX:r1->func
| .if X64
|| if (!IS_SIGNED_32BIT(opcodes)) {
| .endif
| jne &exit_addr
} else {
- | // call = EX(call);
- | mov r1, EX->call
| .if X64
|| if (!IS_SIGNED_32BIT(func)) {
| mov64 r0, ((ptrdiff_t)func)