ZEND_JIT_TRACE_DO_ICALL,
ZEND_JIT_TRACE_ENTER,
ZEND_JIT_TRACE_BACK,
- ZEND_JIT_TRACE_START,
ZEND_JIT_TRACE_END,
+ ZEND_JIT_TRACE_START,
} zend_jit_trace_op;
#define IS_UNKNOWN 255 /* may be used for zend_jit_trace_rec.op?_type */
#define IS_TRACE_REFERENCE (1<<5)
#define IS_TRACE_INDIRECT (1<<6)
+#define ZEND_JIT_TRACE_FAKE_INIT_CALL 0x00000100
+#define ZEND_JIT_TRACE_RETRUN_VALUE_USED 0x00000100
+
+#define ZEND_JIT_TRACE_MAX_SSA_VAR 0x7ffffe
+#define ZEND_JIT_TRACE_SSA_VAR_SHIFT 9
+
+#define ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(_info, var) do { \
+ _info |= (var << ZEND_JIT_TRACE_SSA_VAR_SHIFT); \
+ } while (0)
+#define ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(_info) \
+ (_info >> ZEND_JIT_TRACE_SSA_VAR_SHIFT)
+
typedef struct _zend_jit_trace_rec {
- uint8_t op; /* zend_jit_trace_op */
union {
- struct {
- uint8_t op1_type;/* recorded zval op1_type for ZEND_JIT_TRACE_VM */
- uint8_t op2_type;/* recorded zval op2_type for ZEND_JIT_TRACE_VM */
- uint8_t op3_type;/* recorded zval for op_data.op1_type for ZEND_JIT_TRACE_VM */
- };
- struct {
+ struct { ZEND_ENDIAN_LOHI(
+ uint8_t op, /* zend_jit_trace_op */
union {
- int8_t return_value_used; /* for ZEND_JIT_TRACE_ENTER */
- uint8_t fake; /* for ZEND_JIT_TRACE_INIT_CALL */
- };
- uint8_t first_ssa_var; /* may be used for ZEND_JIT_TRACE_ENTER and ZEND_JIT_TRACE_BACK */
- };
- struct {
- uint8_t start; /* ZEND_JIT_TRACE_START_MASK for ZEND_JIT_TRACE_START/END */
- uint8_t stop; /* zend_jit_trace_stop for ZEND_JIT_TRACE_START/END */
- uint8_t level; /* recursive return level for ZEND_JIT_TRACE_START */
+ struct {
+ uint8_t op1_type;/* recorded zval op1_type for ZEND_JIT_TRACE_VM */
+ uint8_t op2_type;/* recorded zval op2_type for ZEND_JIT_TRACE_VM */
+ uint8_t op3_type;/* recorded zval for op_data.op1_type for ZEND_JIT_TRACE_VM */
+ };
+ struct {
+ uint8_t start; /* ZEND_JIT_TRACE_START_MASK for ZEND_JIT_TRACE_START/END */
+ uint8_t stop; /* zend_jit_trace_stop for ZEND_JIT_TRACE_START/END */
+ uint8_t level; /* recursive return level for ZEND_JIT_TRACE_START */
+ };
+ })
};
+ uint32_t last;
+ uint32_t info; /* "first_ssa_var" for ZEND_JIT_TRACE_ENTER and ZEND_JIT_TRACE_BACK,
+ * "return_value_used" for ZEND_JIT_TRACE_ENTER,
+ * "fake" for ZEND_JIT_TRACE_INIT_CALL */
};
union {
const void *ptr;
};
} zend_jit_trace_rec;
-typedef struct _zend_jit_trace_start_rec {
- uint8_t op; /* zend_jit_trace_op */
- uint8_t start; /* ZEND_JIT_TRACE_START_MASK for ZEND_JIT_TRACE_START/END */
- uint8_t stop; /* zend_jit_trace_stop for ZEND_JIT_TRACE_START/END */
- uint8_t level; /* recursive return level for ZEND_JIT_TRACE_START */
- const zend_op_array *op_array;
- const zend_op *opline;
-} zend_jit_trace_start_rec;
-
#define ZEND_JIT_TRACE_START_REC_SIZE 2
typedef struct _zend_jit_trace_exit_info {
static const zend_op *zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec *p, const zend_op_array *op_array)
{
- if (!p->fake) {
+ if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
p--;
while (1) {
if (p->op == ZEND_JIT_TRACE_VM) {
stack = frame->stack;
op_array = p->op_array;
level++;
- // TODO: remove this restriction ???
- if (ssa_vars_count >= 0xff) {
+ if (ssa_vars_count >= ZEND_JIT_TRACE_MAX_SSA_VAR) {
return NULL;
}
- p->first_ssa_var = ssa_vars_count;
+ ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(p->info, ssa_vars_count);
for (i = 0; i < op_array->last_var; i++) {
SET_STACK_VAR(stack, i, ssa_vars_count++);
}
frame = zend_jit_trace_ret_frame(frame, op_array);
stack = frame->stack;
if (level == 0) {
- // TODO: remove this restriction ???
- if (ssa_vars_count >= 0xff) {
+ if (ssa_vars_count >= ZEND_JIT_TRACE_MAX_SSA_VAR) {
return NULL;
}
- p->first_ssa_var = ssa_vars_count;
+ ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(p->info, ssa_vars_count);
for (i = 0; i < op_array->last_var + op_array->T; i++) {
SET_STACK_VAR(stack, i, ssa_vars_count++);
}
level++;
i = 0;
- v = p->first_ssa_var;
+ v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
while (i < op_array->last_var) {
ssa_vars[v].var = i;
if (i < op_array->num_args) {
ssa = &jit_extension->func_info.ssa;
if (level == 0) {
i = 0;
- v = p->first_ssa_var;
+ v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
while (i < op_array->last_var) {
ssa_vars[v].var = i;
if (!ssa->var_info
const zend_op *opline = q->opline - 1;
if (opline->result_type != IS_UNUSED) {
ssa_var_info[
- p->first_ssa_var +
+ ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info) +
EX_VAR_TO_NUM(opline->result.var)] = return_value_info;
}
}
trace_buffer->op_array->function_name ?
ZSTR_VAL(trace_buffer->op_array->function_name) : "$main",
ZSTR_VAL(trace_buffer->op_array->filename),
- ((zend_jit_trace_start_rec*)trace_buffer)->opline->lineno);
+ trace_buffer[1].opline->lineno);
} else {
fprintf(stderr, "---- TRACE %d TSSA start (%s) %s() %s:%d\n",
ZEND_JIT_TRACE_NUM,
trace_buffer->op_array->function_name ?
ZSTR_VAL(trace_buffer->op_array->function_name) : "$main",
ZSTR_VAL(trace_buffer->op_array->filename),
- ((zend_jit_trace_start_rec*)trace_buffer)->opline->lineno);
+ trace_buffer[1].opline->lineno);
}
zend_jit_dump_trace(trace_buffer, tssa);
if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LINK) {
- uint32_t link_to = zend_jit_find_trace(EG(current_execute_data)->opline->handler);;
+ uint32_t idx = trace_buffer[1].last;
+ uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);
fprintf(stderr, "---- TRACE %d TSSA stop (link to %d)\n",
ZEND_JIT_TRACE_NUM,
link_to);
jit_extension =
(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
op_array_ssa = &jit_extension->func_info.ssa;
- j = p->first_ssa_var;
+ j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
for (i = 0; i < op_array->last_var; i++) {
SET_STACK_VAR(stack, i, j);
vars_op_array[j] = op_array;
stack = frame->stack;
if (level == 0) {
/* New return frames */
- j = p->first_ssa_var;
+ j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
for (i = 0; i < op_array->last_var + op_array->T; i++) {
SET_STACK_VAR(stack, i, j);
vars_op_array[j] = op_array;
TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1);
stack = frame->stack;
- opline = ((zend_jit_trace_start_rec*)p)->opline;
+ opline = p[1].opline;
name = zend_jit_trace_name(op_array, opline->lineno);
p += ZEND_JIT_TRACE_START_REC_SIZE;
op_array_ssa = &jit_extension->func_info.ssa;
call = frame->call;
if (!call) {
+ uint32_t v;
+
assert(0); // This should be handled by "fake" ZEND_JIT_TRACE_INIT_CALL
/* Trace missed INIT_FCALL opcode */
call = top;
TRACE_FRAME_INIT(call, op_array, 0, -1); // TODO: should be possible to get the real number af arguments ???
top = zend_jit_trace_call_frame(top, op_array);
i = 0;
+ v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
while (i < p->op_array->num_args) {
/* Initialize abstract stack using SSA */
- if (!(ssa->var_info[p->first_ssa_var + i].type & MAY_BE_GUARD)
- && has_concrete_type(ssa->var_info[p->first_ssa_var + i].type)) {
- SET_STACK_TYPE(call->stack, i, concrete_type(ssa->var_info[p->first_ssa_var + i].type));
+ if (!(ssa->var_info[v + i].type & MAY_BE_GUARD)
+ && has_concrete_type(ssa->var_info[v + i].type)) {
+ SET_STACK_TYPE(call->stack, i, concrete_type(ssa->var_info[v + i].type));
} else {
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN);
}
}
frame->call = call->prev;
call->prev = frame;
- if (p->return_value_used) {
+ if (p->info & ZEND_JIT_TRACE_RETRUN_VALUE_USED) {
TRACE_FRAME_SET_RETURN_VALUE_USED(call);
} else {
TRACE_FRAME_SET_RETURN_VALUE_UNUSED(call);
JIT_G(current_frame) = frame = call;
stack = frame->stack;
if (ra) {
- for (i = 0; i < op_array->last_var; i++) {
- int j = p->first_ssa_var + i;
+ int j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
+ for (i = 0; i < op_array->last_var; i++,j++) {
if (ra[j] && (ra[j]->flags & ZREG_LOAD) != 0) {
//SET_STACK_REG(stack, i, ra[j]->reg);
if (!zend_jit_load_var(&dasm_state, ssa->var_info[j].type, i, ra[j]->reg)) {
stack = frame->stack;
ZEND_ASSERT(&frame->func->op_array == op_array);
} else {
+ uint32_t j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
+
frame = zend_jit_trace_ret_frame(frame, op_array);
TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1);
stack = frame->stack;
- for (i = 0; i < op_array->last_var + op_array->T; i++) {
+ for (i = 0; i < op_array->last_var + op_array->T; i++, j++) {
/* Initialize abstract stack using SSA */
- if (!(ssa->var_info[p->first_ssa_var + i].type & MAY_BE_GUARD)
- && has_concrete_type(ssa->var_info[p->first_ssa_var + i].type)) {
- SET_STACK_TYPE(stack, i, concrete_type(ssa->var_info[p->first_ssa_var + i].type));
+ if (!(ssa->var_info[j].type & MAY_BE_GUARD)
+ && has_concrete_type(ssa->var_info[j].type)) {
+ SET_STACK_TYPE(stack, i, concrete_type(ssa->var_info[j].type));
} else {
SET_STACK_TYPE(stack, i, IS_UNKNOWN);
}
}
if (ra) {
- for (i = 0; i < op_array->last_var + op_array->T; i++) {
- int j = p->first_ssa_var + i;
-
+ j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
+ for (i = 0; i < op_array->last_var + op_array->T; i++, j++) {
if (ra[j] && (ra[j]->flags & ZREG_LOAD) != 0) {
//SET_STACK_REG(stack, i, ra[j]->reg);
if (!zend_jit_load_var(&dasm_state, ssa->var_info[j].type, i, ra[j]->reg)) {
call = top;
TRACE_FRAME_INIT(call, p->func, TRACE_FRAME_MASK_NESTED, num_args);
call->prev = frame->call;
- if (!p->fake) {
+ if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
TRACE_FRAME_SET_LAST_SEND_BY_VAL(call);
}
frame->call = call;
i++;
}
}
- if (p->fake) {
+ if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) {
int skip_guard = 0;
if (init_opline) {
call_info = call_info->next_callee;
}
}
- if (!skip_guard && !zend_jit_init_fcall_guard(&dasm_state, NULL, p->func, ((zend_jit_trace_start_rec*)trace_buffer)->opline)) {
+ if (!skip_guard && !zend_jit_init_fcall_guard(&dasm_state, NULL, p->func, trace_buffer[1].opline)) {
goto jit_failure;
}
frame->call_level++;
t->child_count = 0;
t->stack_map_size = 0;
t->flags = 0;
- t->opline = ((zend_jit_trace_start_rec*)trace_buffer)->opline;
+ t->opline = trace_buffer[1].opline;
t->exit_info = exit_info;
t->stack_map = NULL;
level++;
if (tssa && tssa->var_info) {
call_level++;
- v = p->first_ssa_var;
+ v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
vars_count = op_array->last_var;
for (i = 0; i < vars_count; i++, v++) {
if (tssa->vars[v].use_chain >= 0 || tssa->vars[v].phi_use_chain) {
ZSTR_VAL(op_array->filename));
if (tssa && tssa->var_info) {
if (call_level == 0) {
- v = p->first_ssa_var;
+ v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
vars_count = op_array->last_var + op_array->T;
for (i = 0; i < vars_count; i++, v++) {
if (tssa->vars[v].use_chain >= 0 || tssa->vars[v].phi_use_chain) {
}
} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
if (p->func != (zend_function*)&zend_pass_function) {
- fprintf(stderr, p->fake ? " %*c>fake_init %s%s%s\n" : " %*c>init %s%s%s\n",
+ fprintf(stderr, (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) ? " %*c>fake_init %s%s%s\n" : " %*c>init %s%s%s\n",
level, ' ',
p->func->common.scope ? ZSTR_VAL(p->func->common.scope->name) : "",
p->func->common.scope ? "::" : "",
if (ZEND_JIT_TRACE_STOP_OK(stop)) {
if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_TRACE_STOP) {
if (stop == ZEND_JIT_TRACE_STOP_LINK) {
- uint32_t link_to = zend_jit_find_trace(EG(current_execute_data)->opline->handler);;
+ uint32_t idx = trace_buffer[1].last;
+ uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);
fprintf(stderr, "---- TRACE %d stop (link to %d)\n",
trace_num,
link_to);
if (ZEND_JIT_TRACE_STOP_OK(stop)) {
if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_TRACE_STOP) {
if (stop == ZEND_JIT_TRACE_STOP_LINK) {
- uint32_t link_to = zend_jit_find_trace(EG(current_execute_data)->opline->handler);;
+ uint32_t idx = trace_buffer[1].last;
+ uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);;
fprintf(stderr, "---- TRACE %d stop (link to %d)\n",
trace_num,
link_to);
ZEND_OPCODE_TAIL_CALL_EX(zend_jit_trace_counter_helper, ZEND_JIT_TRACE_LOOP_COST);
}
-#define TRACE_RECORD(_op, _ptr) \
- trace_buffer[idx].op = _op; \
+#define TRACE_RECORD(_op, _info, _ptr) \
+ trace_buffer[idx].info = _op | (_info); \
trace_buffer[idx].ptr = _ptr; \
idx++; \
if (idx >= ZEND_JIT_TRACE_MAX_LENGTH - 1) { \
break; \
}
-#define TRACE_RECORD_ENTER(_op, _return_value_used, _ptr) \
- trace_buffer[idx].op = _op; \
- trace_buffer[idx].return_value_used = _return_value_used; \
- trace_buffer[idx].ptr = _ptr; \
- idx++; \
- if (idx >= ZEND_JIT_TRACE_MAX_LENGTH - 1) { \
- stop = ZEND_JIT_TRACE_STOP_TOO_LONG; \
- break; \
- }
-
-#define TRACE_RECORD_INIT(_op, _fake, _ptr) \
- trace_buffer[idx].op = _op; \
- trace_buffer[idx].fake = _fake; \
- trace_buffer[idx].ptr = _ptr; \
- idx++; \
- if (idx >= ZEND_JIT_TRACE_MAX_LENGTH - 1) { \
- stop = ZEND_JIT_TRACE_STOP_TOO_LONG; \
- break; \
- }
-
-#define TRACE_RECORD_BACK(_op, _ptr) \
- trace_buffer[idx].op = _op; \
- trace_buffer[idx].ptr = _ptr; \
- idx++; \
- if (idx >= ZEND_JIT_TRACE_MAX_LENGTH - 1) { \
- stop = ZEND_JIT_TRACE_STOP_TOO_LONG; \
- break; \
- }
-
-#define TRACE_RECORD_TYPE(_op, _ptr) \
- trace_buffer[idx].op = _op; \
- trace_buffer[idx].ptr = _ptr; \
- idx++; \
- if (idx >= ZEND_JIT_TRACE_MAX_LENGTH - 1) { \
- stop = ZEND_JIT_TRACE_STOP_TOO_LONG; \
- break; \
- }
-
-#define TRACE_START(_op, _start, _ptr) \
+#define TRACE_START(_op, _start, _ptr1, _ptr2) \
trace_buffer[0].op = _op; \
trace_buffer[0].start = _start; \
trace_buffer[0].level = 0; \
- trace_buffer[0].ptr = _ptr; \
+ trace_buffer[0].ptr = _ptr1; \
+ trace_buffer[1].last = 0; \
+ trace_buffer[1].ptr = _ptr2; \
idx = ZEND_JIT_TRACE_START_REC_SIZE;
#define TRACE_END(_op, _stop, _ptr) \
+ trace_buffer[1].last = idx; \
trace_buffer[idx].op = _op; \
trace_buffer[idx].start = trace_buffer[idx].start; \
trace_buffer[idx].stop = trace_buffer[0].stop = _stop; \
if (call->prev_execute_data) {
idx = zend_jit_trace_record_fake_init_call(call->prev_execute_data, trace_buffer, idx);
}
- TRACE_RECORD_INIT(ZEND_JIT_TRACE_INIT_CALL, 1, call->func);
+ TRACE_RECORD(ZEND_JIT_TRACE_INIT_CALL, ZEND_JIT_TRACE_FAKE_INIT_CALL, call->func);
} while (0);
return idx;
}
(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(&EX(func)->op_array);
offset = jit_extension->offset;
- TRACE_START(ZEND_JIT_TRACE_START, start, &EX(func)->op_array);
- ((zend_jit_trace_start_rec*)trace_buffer)->opline = opline;
+ TRACE_START(ZEND_JIT_TRACE_START, start, &EX(func)->op_array, opline);
is_toplevel = EX(func)->op_array.function_name == NULL;
if (prev_call) {
TRACE_RECORD_VM(ZEND_JIT_TRACE_VM, opline, op1_type, op2_type, op3_type);
if (ce1) {
- TRACE_RECORD_TYPE(ZEND_JIT_TRACE_OP1_TYPE, ce1);
+ TRACE_RECORD(ZEND_JIT_TRACE_OP1_TYPE, 0, ce1);
}
if (ce2) {
- TRACE_RECORD_TYPE(ZEND_JIT_TRACE_OP2_TYPE, ce2);
+ TRACE_RECORD(ZEND_JIT_TRACE_OP2_TYPE, 0, ce2);
}
switch (opline->opcode) {
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
if (EX(call)->func->type == ZEND_INTERNAL_FUNCTION) {
- TRACE_RECORD(ZEND_JIT_TRACE_DO_ICALL, EX(call)->func);
+ TRACE_RECORD(ZEND_JIT_TRACE_DO_ICALL, 0, EX(call)->func);
}
break;
default:
break;
}
- TRACE_RECORD_ENTER(ZEND_JIT_TRACE_ENTER, EX(return_value) != NULL, &EX(func)->op_array);
+ TRACE_RECORD(ZEND_JIT_TRACE_ENTER,
+ EX(return_value) != NULL ? ZEND_JIT_TRACE_RETRUN_VALUE_USED : 0,
+ &EX(func)->op_array);
count = zend_jit_trace_recursive_call_count(&EX(func)->op_array, unrolled_calls, ret_level, level);
stop = ZEND_JIT_TRACE_STOP_TOO_DEEP_RET;
break;
}
- TRACE_RECORD_BACK(ZEND_JIT_TRACE_BACK, &EX(func)->op_array);
+ TRACE_RECORD(ZEND_JIT_TRACE_BACK, 0, &EX(func)->op_array);
count = zend_jit_trace_recursive_ret_count(&EX(func)->op_array, unrolled_calls, ret_level);
if (opline == orig_opline) {
if (count + 1 >= ZEND_JIT_TRACE_MAX_RECURSION) {
}
} else {
level--;
- TRACE_RECORD_BACK(ZEND_JIT_TRACE_BACK, &EX(func)->op_array);
+ TRACE_RECORD(ZEND_JIT_TRACE_BACK, 0, &EX(func)->op_array);
}
}
#ifdef HAVE_GCC_GLOBAL_REGS
stop = ZEND_JIT_TRACE_STOP_TRAMPOLINE;
break;
}
- TRACE_RECORD_INIT(ZEND_JIT_TRACE_INIT_CALL, 0, EX(call)->func);
+ TRACE_RECORD(ZEND_JIT_TRACE_INIT_CALL, 0, EX(call)->func);
}
prev_call = EX(call);
}
break;
}
} else if (trace_flags & ZEND_JIT_TRACE_UNSUPPORTED) {
- TRACE_RECORD(ZEND_JIT_TRACE_VM, opline);
+ TRACE_RECORD(ZEND_JIT_TRACE_VM, 0, opline);
stop = ZEND_JIT_TRACE_STOP_NOT_SUPPORTED;
break;
}
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) {
+ while (trace_buffer[idx-1].op == ZEND_JIT_TRACE_INIT_CALL
+ && (trace_buffer[idx-1].info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
idx--;
}
}