Skip to content

Commit 864b1cc

Browse files
committed
Free room for information about register allocation at astact stack and at trace_exit_info. Implement simple deoptimizer.
1 parent 4006c00 commit 864b1cc

File tree

2 files changed

+81
-38
lines changed

2 files changed

+81
-38
lines changed

ext/opcache/jit/zend_jit_internal.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,35 @@ typedef struct _zend_jit_trace_exit_info {
307307
uint32_t stack_offset;
308308
} zend_jit_trace_exit_info;
309309

310-
typedef int32_t zend_jit_trace_stack;
310+
typedef union _zend_jit_trace_stack {
311+
int32_t __ssa_var;
312+
uint32_t __info;
313+
struct {
314+
uint8_t __type;
315+
int8_t __reg;
316+
uint16_t __flags;
317+
};
318+
} zend_jit_trace_stack;
319+
320+
#define STACK_VAR(_stack, _slot) \
321+
(_stack)[_slot].__ssa_var
322+
#define STACK_INFO(_stack, _slot) \
323+
(_stack)[_slot].__info
324+
#define STACK_TYPE(_stack, _slot) \
325+
(_stack)[_slot].__type
326+
#define STACK_REG(_stack, _slot) \
327+
(_stack)[_slot].__reg
328+
#define SET_STACK_VAR(_stack, _slot, _ssa_var) do { \
329+
(_stack)[_slot].__ssa_var = _ssa_var; \
330+
} while (0)
331+
#define SET_STACK_INFO(_stack, _slot, _info) do { \
332+
(_stack)[_slot].__info = _info; \
333+
} while (0)
334+
#define SET_STACK_TYPE(_stack, _slot, _type) do { \
335+
(_stack)[_slot].__type = _type; \
336+
(_stack)[_slot].__reg = ZREG_NONE; \
337+
(_stack)[_slot].__flags = 0; \
338+
} while (0)
311339

312340
typedef struct _zend_jit_trace_info {
313341
uint32_t id; /* trace id */

ext/opcache/jit/zend_jit_trace.c

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ static uint32_t zend_jit_trace_get_exit_point(const zend_op *from_opline, const
134134
if (stack_size) {
135135
stack = JIT_G(current_frame)->stack;
136136
do {
137-
if (stack[stack_size-1] != IS_UNKNOWN) {
137+
if (STACK_TYPE(stack, stack_size-1) != IS_UNKNOWN) {
138138
break;
139139
}
140140
stack_size--;
@@ -320,10 +320,10 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
320320
}
321321

322322
#define STACK_VAR_TYPE(_var) \
323-
((zend_uchar)stack[EX_VAR_TO_NUM(_var)])
323+
STACK_TYPE(stack, EX_VAR_TO_NUM(_var))
324324

325325
#define SET_STACK_VAR_TYPE(_var, _type) do { \
326-
stack[EX_VAR_TO_NUM(_var)] = _type; \
326+
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), _type); \
327327
} while (0)
328328

329329
#define CHECK_OP_TRACE_TYPE(_var, _ssa_var, op_info, op_type) do { \
@@ -575,13 +575,13 @@ static int zend_jit_trace_add_phis(zend_jit_trace_rec *trace_buffer, uint32_t ss
575575
ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
576576
sizeof(void*) * 2);
577577
phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
578-
phi->sources[0] = stack[k];
578+
phi->sources[0] = STACK_VAR(stack, k);
579579
phi->sources[1] = -1;
580580
phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
581581
phi->pi = -1;
582582
phi->var = k;
583583
phi->ssa_var = ssa_vars_count;
584-
stack[k] = ssa_vars_count;
584+
SET_STACK_VAR(stack, k, ssa_vars_count);
585585
ssa_vars_count++;
586586
phi->block = 1;
587587
if (prev) {
@@ -957,7 +957,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
957957
}
958958
stack = frame->stack;
959959
for (i = 0; i < ssa_vars_count; i++) {
960-
stack[i] = i;
960+
SET_STACK_VAR(stack, i, i);
961961
}
962962

963963
if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
@@ -973,14 +973,14 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
973973
if (p->op == ZEND_JIT_TRACE_VM) {
974974
opline = p->opline;
975975
ssa_opcodes[idx] = opline;
976-
ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, stack);
976+
ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (int*)stack);
977977
idx++;
978978
len = zend_jit_trace_op_len(p->opline);
979979
while (len > 1) {
980980
opline++;
981981
ssa_opcodes[idx] = opline;
982982
if (opline->opcode != ZEND_OP_DATA) {
983-
ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, stack);
983+
ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (int*)stack);
984984
}
985985
idx++;
986986
len--;
@@ -993,7 +993,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
993993
ZEND_ASSERT(ssa_vars_count < 0xff);
994994
p->first_ssa_var = ssa_vars_count;
995995
for (i = 0; i < op_array->last_var; i++) {
996-
stack[i] = ssa_vars_count++;
996+
SET_STACK_VAR(stack, i, ssa_vars_count++);
997997
}
998998
} else if (p->op == ZEND_JIT_TRACE_BACK) {
999999
op_array = p->op_array;
@@ -1003,7 +1003,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
10031003
ZEND_ASSERT(ssa_vars_count <= 0xff);
10041004
p->first_ssa_var = ssa_vars_count;
10051005
for (i = 0; i < op_array->last_var + op_array->T; i++) {
1006-
stack[i] = ssa_vars_count++;
1006+
SET_STACK_VAR(stack, i, ssa_vars_count++);
10071007
}
10081008
} else {
10091009
level--;
@@ -1042,7 +1042,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
10421042
zend_ssa_phi *phi = tssa->blocks[1].phis;
10431043

10441044
while (phi) {
1045-
phi->sources[1] = stack[phi->var];
1045+
phi->sources[1] = STACK_VAR(stack, phi->var);
10461046
ssa_vars[phi->ssa_var].var = phi->var;
10471047
ssa_vars[phi->ssa_var].definition_phi = phi;
10481048
ssa_vars[phi->sources[0]].phi_use_chain = phi;
@@ -1143,7 +1143,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
11431143
}
11441144
if (i < parent_vars_count) {
11451145
/* Initialize TSSA variable from parent trace */
1146-
zend_uchar op_type = parent_stack[i];
1146+
zend_uchar op_type = STACK_TYPE(parent_stack, i);
11471147

11481148
if (op_type != IS_UNKNOWN) {
11491149
ssa_var_info[i].type &= zend_jit_trace_type_to_info(op_type);
@@ -1171,7 +1171,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
11711171
TRACE_FRAME_INIT(frame, op_array, 0, 0);
11721172
TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
11731173
for (i = 0; i < op_array->last_var + op_array->T; i++) {
1174-
frame->stack[i] = -1;
1174+
SET_STACK_TYPE(frame->stack, i, IS_UNKNOWN);
11751175
}
11761176
memset(&return_value_info, 0, sizeof(return_value_info));
11771177

@@ -1334,7 +1334,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
13341334
if (ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
13351335
info |= MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY;
13361336
}
1337-
frame->call->stack[opline->op2.num - 1] = info;
1337+
SET_STACK_INFO(frame->call->stack, opline->op2.num - 1, info);
13381338
}
13391339
break;
13401340
case ZEND_RETURN:
@@ -1476,7 +1476,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
14761476
TRACE_FRAME_INIT(call, op_array, 0, 0);
14771477
top = zend_jit_trace_call_frame(top, op_array);
14781478
for (i = 0; i < op_array->last_var + op_array->T; i++) {
1479-
call->stack[i] = -1;
1479+
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN);
14801480
}
14811481
} else {
14821482
ZEND_ASSERT(&call->func->op_array == op_array);
@@ -1515,7 +1515,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
15151515
if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
15161516
&& i < op_array->num_args) {
15171517
/* Propagate argument type */
1518-
ssa_var_info[v].type &= frame->stack[i];
1518+
ssa_var_info[v].type &= STACK_INFO(frame->stack, i);
15191519
}
15201520
i++;
15211521
v++;
@@ -1582,7 +1582,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
15821582
TRACE_FRAME_INIT(frame, op_array, 0, 0);
15831583
TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
15841584
for (i = 0; i < op_array->last_var + op_array->T; i++) {
1585-
frame->stack[i] = -1;
1585+
SET_STACK_TYPE(frame->stack, i, IS_UNKNOWN);
15861586
}
15871587
}
15881588

@@ -1594,7 +1594,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
15941594
top = zend_jit_trace_call_frame(top, p->op_array);
15951595
if (p->func->type == ZEND_USER_FUNCTION) {
15961596
for (i = 0; i < p->op_array->last_var + p->op_array->T; i++) {
1597-
call->stack[i] = -1;
1597+
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN);
15981598
}
15991599
}
16001600
} else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
@@ -1724,11 +1724,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
17241724
while (i < op_array->last_var) {
17251725
if (!(ssa->var_info[i].type & MAY_BE_GUARD)
17261726
&& has_concrete_type(ssa->var_info[i].type)) {
1727-
stack[i] = concrete_type(ssa->var_info[i].type);
1727+
SET_STACK_TYPE(stack, i, concrete_type(ssa->var_info[i].type));
17281728
} else if (i < op_array->num_args) {
1729-
stack[i] = IS_UNKNOWN;
1729+
SET_STACK_TYPE(stack, i, IS_UNKNOWN);
17301730
} else {
1731-
stack[i] = IS_UNDEF;
1731+
SET_STACK_TYPE(stack, i, IS_UNDEF);
17321732
}
17331733
i++;
17341734
}
@@ -1749,12 +1749,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
17491749
while (i < op_array->last_var + op_array->T) {
17501750
if (!(ssa->var_info[i].type & MAY_BE_GUARD)
17511751
&& has_concrete_type(ssa->var_info[i].type)) {
1752-
stack[i] = concrete_type(ssa->var_info[i].type);
1752+
SET_STACK_TYPE(stack, i, concrete_type(ssa->var_info[i].type));
17531753
} else if (i < parent_vars_count
1754-
&& (zend_uchar)parent_stack[i] != IS_UNKNOWN) {
1755-
stack[i] = parent_stack[i];
1754+
&& STACK_TYPE(parent_stack, i) != IS_UNKNOWN) {
1755+
SET_STACK_TYPE(stack, i, STACK_TYPE(parent_stack, i));
17561756
} else {
1757-
stack[i] = IS_UNKNOWN;
1757+
SET_STACK_TYPE(stack, i, IS_UNKNOWN);
17581758
}
17591759
i++;
17601760
}
@@ -1814,7 +1814,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
18141814
goto jit_failure;
18151815
}
18161816
ssa->var_info[i].type = info & ~MAY_BE_GUARD;
1817-
stack[i] = concrete_type(info);
1817+
SET_STACK_TYPE(stack, i, concrete_type(info));
18181818
}
18191819
}
18201820
}
@@ -2449,7 +2449,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
24492449
for (j = 0 ; j < op_array->last_var; j++) {
24502450
// TODO: get info from trace ???
24512451
uint32_t info = zend_ssa_cv_info(opline, op_array, op_array_ssa, j);
2452-
zend_uchar type = stack[j];
2452+
zend_uchar type = STACK_TYPE(stack, j);
24532453

24542454
info = zend_jit_trace_type_to_info_ex(type, info);
24552455
if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
@@ -2949,18 +2949,18 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
29492949
/* Initialize abstract stack using SSA */
29502950
if (!(ssa->var_info[p->first_ssa_var + i].type & MAY_BE_GUARD)
29512951
&& has_concrete_type(ssa->var_info[p->first_ssa_var + i].type)) {
2952-
call->stack[i] = concrete_type(ssa->var_info[p->first_ssa_var + i].type);
2952+
SET_STACK_TYPE(call->stack, i, concrete_type(ssa->var_info[p->first_ssa_var + i].type));
29532953
} else {
2954-
call->stack[i] = IS_UNKNOWN;
2954+
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN);
29552955
}
29562956
i++;
29572957
}
29582958
while (i < p->op_array->last_var) {
2959-
call->stack[i] = IS_UNDEF;
2959+
SET_STACK_TYPE(call->stack, i, IS_UNDEF);
29602960
i++;
29612961
}
29622962
while (i < p->op_array->last_var + p->op_array->T) {
2963-
call->stack[i] = IS_UNKNOWN;
2963+
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN);
29642964
i++;
29652965
}
29662966
} else {
@@ -2994,9 +2994,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
29942994
/* Initialize abstract stack using SSA */
29952995
if (!(ssa->var_info[p->first_ssa_var + i].type & MAY_BE_GUARD)
29962996
&& has_concrete_type(ssa->var_info[p->first_ssa_var + i].type)) {
2997-
stack[i] = concrete_type(ssa->var_info[p->first_ssa_var + i].type);
2997+
SET_STACK_TYPE(stack, i, concrete_type(ssa->var_info[p->first_ssa_var + i].type));
29982998
} else {
2999-
stack[i] = IS_UNKNOWN;
2999+
SET_STACK_TYPE(stack, i, IS_UNKNOWN);
30003000
}
30013001
}
30023002
}
@@ -3024,15 +3024,15 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
30243024
i = 0;
30253025
while (i < p->op_array->num_args) {
30263026
/* Types of arguments are going to be stored in abstract stack when proseccin SEV onstruction */
3027-
call->stack[i] = IS_UNKNOWN;
3027+
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN);
30283028
i++;
30293029
}
30303030
while (i < p->op_array->last_var) {
3031-
call->stack[i] = IS_UNDEF;
3031+
SET_STACK_TYPE(call->stack, i, IS_UNDEF);
30323032
i++;
30333033
}
30343034
while (i < p->op_array->last_var + p->op_array->T) {
3035-
call->stack[i] = IS_UNKNOWN;
3035+
SET_STACK_TYPE(call->stack, i, IS_UNKNOWN);
30363036
i++;
30373037
}
30383038
}
@@ -3886,7 +3886,22 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf
38863886
const zend_op *opline;
38873887
zend_jit_trace_info *t = &zend_jit_traces[trace_num];
38883888

3889-
// TODO: Deoptimizatoion of VM stack state ???
3889+
/* Deoptimizatoion of VM stack state */
3890+
uint32_t i;
3891+
uint32_t stack_size = t->exit_info[exit_num].stack_size;
3892+
zend_jit_trace_stack *stack = t->stack_map + t->exit_info[exit_num].stack_offset;
3893+
3894+
for (i = 0; i < stack_size; i++) {
3895+
if (STACK_REG(stack, i) != ZREG_NONE) {
3896+
if (STACK_TYPE(stack, i) == IS_LONG) {
3897+
ZVAL_LONG(EX_VAR_NUM(i), regs->r[STACK_REG(stack, i)]);
3898+
} else if (STACK_TYPE(stack, i) == IS_DOUBLE) {
3899+
ZVAL_DOUBLE(EX_VAR_NUM(i), regs->xmm[STACK_REG(stack, i) - ZREG_XMM0]);
3900+
} else {
3901+
ZEND_ASSERT(0);
3902+
}
3903+
}
3904+
}
38903905

38913906
/* Lock-free check if the side trace was already JIT-ed or blacklist-ed in another process */
38923907
// TODO: We may remoive this, becaus of the same check in zend_jit_trace_hot_side() ???

0 commit comments

Comments
 (0)