zend_jit_trace_stack_frame *call;
zend_jit_trace_stack_frame *prev;
const zend_function *func;
- union {
- struct {
- int8_t return_value_used;
- int8_t nested;
- int8_t num_args;
- int8_t last_send_by_ref;
- };
- int return_ssa_var;
- };
+ uint32_t _info;
zend_jit_trace_stack stack[1];
};
+#define TRACE_FRAME_SHIFT_NUM_ARGS 16
+#define TRACE_FRAME_MAX_NUM_ARGS 32767
+
+#define TRACE_FRAME_MASK_NUM_ARGS 0xffff0000
+#define TRACE_FRAME_MASK_NESTED 0x00000001
+#define TRACE_FRAME_MASK_LAST_SEND_BY_REF 0x00000002
+#define TRACE_FRAME_MASK_LAST_SEND_BY_VAL 0x00000004
+#define TRACE_FRAME_MASK_RETURN_VALUE_USED 0x00000008
+#define TRACE_FRAME_MASK_RETURN_VALUE_UNUSED 0x00000010
+
+
+#define TRACE_FRAME_INIT(frame, _func, nested, num_args) do { \
+ zend_jit_trace_stack_frame *_frame = (frame); \
+ _frame->call = NULL; \
+ _frame->prev = NULL; \
+ _frame->func = (const zend_function*)_func; \
+ _frame->_info = (uint32_t)((((int)(num_args)) << TRACE_FRAME_SHIFT_NUM_ARGS) & TRACE_FRAME_MASK_NUM_ARGS); \
+ if (nested) { \
+ _frame->_info |= TRACE_FRAME_MASK_NESTED; \
+ }; \
+ } while (0)
+
+#define TRACE_FRAME_RETURN_SSA_VAR(frame) \
+ ((int)(frame)->_info)
+#define TRACE_FRAME_NUM_ARGS(frame) \
+ ((int)((frame)->_info) >> TRACE_FRAME_SHIFT_NUM_ARGS)
+#define TRACE_FRAME_IS_NESTED(frame) \
+ ((frame)->_info & TRACE_FRAME_MASK_NESTED)
+#define TRACE_FRAME_IS_LAST_SEND_BY_REF(frame) \
+ ((frame)->_info & TRACE_FRAME_MASK_LAST_SEND_BY_REF)
+#define TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame) \
+ ((frame)->_info & TRACE_FRAME_MASK_LAST_SEND_BY_VAL)
+#define TRACE_FRAME_IS_RETURN_VALUE_USED(frame) \
+ ((frame)->_info & TRACE_FRAME_MASK_RETURN_VALUE_USED)
+#define TRACE_FRAME_IS_RETURN_VALUE_UNUSED(frame) \
+ ((frame)->_info & TRACE_FRAME_MASK_RETURN_VALUE_UNUSED)
+
+#define TRACE_FRAME_SET_RETURN_SSA_VAR(frame, var) do { \
+ (frame)->_info = var; \
+ } while (0)
+#define TRACE_FRAME_SET_LAST_SEND_BY_REF(frame) do { \
+ (frame)->_info |= TRACE_FRAME_MASK_LAST_SEND_BY_REF; \
+ (frame)->_info &= ~TRACE_FRAME_MASK_LAST_SEND_BY_VAL; \
+ } while (0)
+#define TRACE_FRAME_SET_LAST_SEND_BY_VAL(frame) do { \
+ (frame)->_info |= TRACE_FRAME_MASK_LAST_SEND_BY_VAL; \
+ (frame)->_info &= ~TRACE_FRAME_MASK_LAST_SEND_BY_REF; \
+ } while (0)
+#define TRACE_FRAME_SET_RETURN_VALUE_USED(frame) do { \
+ (frame)->_info |= TRACE_FRAME_MASK_RETURN_VALUE_USED; \
+ (frame)->_info &= ~TRACE_FRAME_MASK_RETURN_VALUE_UNUSED; \
+ } while (0)
+#define TRACE_FRAME_SET_RETURN_VALUE_UNUSED(frame) do { \
+ (frame)->_info |= TRACE_FRAME_MASK_RETURN_VALUE_UNUSED; \
+ (frame)->_info &= ~TRACE_FRAME_MASK_RETURN_VALUE_USED; \
+ } while (0)
+
typedef struct _zend_jit_globals {
zend_jit_trace_stack_frame *current_frame;
|| p->opline->opcode == ZEND_NEW
|| p->opline->opcode == ZEND_INIT_METHOD_CALL
|| p->opline->opcode == ZEND_INIT_STATIC_METHOD_CALL) {
- if (p->opline->extended_value <= 127) {
+ if (p->opline->extended_value <= TRACE_FRAME_MAX_NUM_ARGS) {
return p->opline->extended_value;
} else {
return -1;
frame = JIT_G(current_frame);
top = zend_jit_trace_call_frame(frame, op_array);
- frame->call = NULL;
- frame->prev = NULL;
- frame->func = (const zend_function*)op_array;
- frame->return_ssa_var = -1;
+ TRACE_FRAME_INIT(frame, op_array, 0, 0);
+ TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
for (i = 0; i < op_array->last_var + op_array->T; i++) {
frame->stack[i] = -1;
}
if (!call) {
/* Trace missed INIT_FCALL opcode */
call = top;
- call->call = NULL;
- call->prev = NULL;
- call->func = (const zend_function*)op_array;
+ TRACE_FRAME_INIT(call, op_array, 0, 0);
top = zend_jit_trace_call_frame(top, op_array);
for (i = 0; i < op_array->last_var + op_array->T; i++) {
call->stack[i] = -1;
}
frame->call = call->prev;
call->prev = frame;
- call->return_ssa_var = find_return_ssa_var(p - 1, ssa_ops + (idx - 1));
+ TRACE_FRAME_SET_RETURN_SSA_VAR(call, find_return_ssa_var(p - 1, ssa_ops + (idx - 1)));
frame = call;
level++;
if ((p+1)->op == ZEND_JIT_TRACE_VM) {
const zend_op *opline = (p+1)->opline - 1;
if (opline->result_type != IS_UNUSED) {
- if (frame->return_ssa_var >= 0) {
- ssa_var_info[frame->return_ssa_var] = return_value_info;
+ if (TRACE_FRAME_RETURN_SSA_VAR(frame) >= 0) {
+ ssa_var_info[TRACE_FRAME_RETURN_SSA_VAR(frame)] = return_value_info;
}
}
}
ZEND_ASSERT(&frame->func->op_array == op_array);
} else {
frame = zend_jit_trace_ret_frame(frame, op_array);
- frame->call = NULL;
- frame->prev = NULL;
- frame->func = (const zend_function*)op_array;
- frame->return_ssa_var = -1;
+ TRACE_FRAME_INIT(frame, op_array, 0, 0);
+ TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
for (i = 0; i < op_array->last_var + op_array->T; i++) {
frame->stack[i] = -1;
}
} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
call = top;
- call->call = NULL;
+ TRACE_FRAME_INIT(call, p->func, 0, 0);
call->prev = frame->call;
- call->func = p->func;
frame->call = call;
top = zend_jit_trace_call_frame(top, p->op_array);
if (p->func->type == ZEND_USER_FUNCTION) {
op_array = p->op_array;
frame = JIT_G(current_frame);
top = zend_jit_trace_call_frame(frame, op_array);
- frame->call = NULL;
- frame->prev = NULL;
- frame->func = (const zend_function*)op_array;
- frame->return_value_used = -1;
- frame->nested = 0;
- frame->num_args = -1;
- frame->last_send_by_ref = -1;
+ TRACE_FRAME_INIT(frame, op_array, 0, -1);
stack = frame->stack;
if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
if (!call) {
/* Trace missed INIT_FCALL opcode */
call = top;
- call->call = NULL;
- call->prev = NULL;
- call->func = (const zend_function*)op_array;
- call->nested = 0;
- call->num_args = -1; // TODO: should be possible to get the real number ???
- call->last_send_by_ref = -1;
+ 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;
while (i < p->op_array->num_args) {
}
frame->call = call->prev;
call->prev = frame;
- call->return_value_used = p->return_value_used;
+ if (p->return_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;
zend_jit_set_opline(&dasm_state, (p+1)->opline);
ZEND_ASSERT(&frame->func->op_array == op_array);
} else {
frame = zend_jit_trace_ret_frame(frame, op_array);
- frame->call = NULL;
- frame->prev = NULL;
- frame->func = (const zend_function*)op_array;
- frame->return_value_used = -1;
- frame->nested = 0;
- frame->num_args = -1;
- frame->last_send_by_ref = -1;
+ TRACE_FRAME_INIT(frame, op_array, 0, -1);
stack = frame->stack;
for (i = 0; i < op_array->last_var + op_array->T; i++) {
/* Initialize abstract stack using SSA */
break;
} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
call = top;
- call->call = NULL;
+ TRACE_FRAME_INIT(call, p->func, 1, find_call_num_args(p-1));
call->prev = frame->call;
- call->func = p->func;
- call->nested = 1;
- call->num_args = find_call_num_args(p-1);
- call->last_send_by_ref = p->fake ? -1 : 0;
+ if (!p->fake) {
+ TRACE_FRAME_SET_LAST_SEND_BY_VAL(call);
+ }
frame->call = call;
top = zend_jit_trace_call_frame(top, p->op_array);
if (p->func->type == ZEND_USER_FUNCTION) {
func = trace->func;
if (JIT_G(current_frame) &&
JIT_G(current_frame)->call &&
- JIT_G(current_frame)->call->num_args >= 0) {
- call_num_args = JIT_G(current_frame)->call->num_args;
+ TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
+ call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
} else {
unknown_num_args = 1;
}
func = trace->func;
if (JIT_G(current_frame) &&
JIT_G(current_frame)->call &&
- JIT_G(current_frame)->call->num_args >= 0) {
- call_num_args = JIT_G(current_frame)->call->num_args;
+ TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
+ call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
} else {
unknown_num_args = 1;
}
if (zend_jit_trigger != ZEND_JIT_ON_HOT_TRACE ||
!JIT_G(current_frame) ||
!JIT_G(current_frame)->call ||
- !JIT_G(current_frame)->call->nested) {
+ !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call)) {
| // zend_vm_stack_free_call_frame(call);
| test byte [RX + offsetof(zend_execute_data, This.u1.type_info) + 2], (ZEND_CALL_ALLOCATED >> 16)
&& JIT_G(current_frame)->call
&& JIT_G(current_frame)->call->func) {
if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
- if (JIT_G(current_frame)->call->last_send_by_ref != 1) {
- JIT_G(current_frame)->call->last_send_by_ref = 1;
+ if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
+ TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
| // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
|| if (reuse_ip) {
| or dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF
|| }
}
} else {
- if (JIT_G(current_frame)->call->last_send_by_ref != 0) {
- JIT_G(current_frame)->call->last_send_by_ref = 0;
+ if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
+ TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
| // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
|| if (reuse_ip) {
| and dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF
if (zend_jit_trigger != ZEND_JIT_ON_HOT_TRACE ||
!JIT_G(current_frame) ||
- !JIT_G(current_frame)->nested) {
+ !TRACE_FRAME_IS_NESTED(JIT_G(current_frame))) {
// TODO: try to avoid this check ???
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
| cmp IP, zend_jit_halt_op
ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
if (zend_jit_trigger == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) {
- return_value_used = JIT_G(current_frame)->return_value_used;
+ if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
+ return_value_used = 1;
+ } else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
+ return_value_used = 0;
+ } else {
+ return_value_used = -1;
+ }
} else {
return_value_used = -1;
}