Skip to content

Commit f733047

Browse files
committed
Tracing JIT support for indirect CV modification (may be incomplete)
1 parent 9905322 commit f733047

File tree

1 file changed

+76
-12
lines changed

1 file changed

+76
-12
lines changed

ext/opcache/jit/zend_jit_trace.c

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,15 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
338338
return zend_jit_trace_type_to_info_ex(type, -1);
339339
}
340340

341+
static zend_always_inline int zend_jit_var_may_be_modified_indirectly(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t var)
342+
{
343+
if ((!op_array->function_name || (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS))
344+
&& var < op_array->last_var) {
345+
return 1;
346+
}
347+
return 0;
348+
}
349+
341350
#define STACK_VAR_TYPE(_var) \
342351
STACK_TYPE(stack, EX_VAR_TO_NUM(_var))
343352

@@ -348,7 +357,9 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
348357
#define ADD_OP_GUARD(_var, _op_type) do { \
349358
if (_var >= 0 && _op_type != IS_UNKNOWN) { \
350359
zend_ssa_var_info *info = &ssa_var_info[_var]; \
351-
if ((info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << _op_type)) { \
360+
if (zend_jit_var_may_be_modified_indirectly(op_array, ssa, ssa_vars[_var].var)) { \
361+
info->type = MAY_BE_GUARD | zend_jit_trace_type_to_info(_op_type); \
362+
} else if ((info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << _op_type)) { \
352363
info->type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex(_op_type, info->type); \
353364
} \
354365
} \
@@ -361,9 +372,13 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
361372
if (!zend_jit_type_guard(&dasm_state, opline, _var, op_type)) { \
362373
goto jit_failure; \
363374
} \
364-
op_info &= ~MAY_BE_GUARD; \
375+
if (zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, _var)) { \
376+
SET_STACK_VAR_TYPE(_var, IS_UNKNOWN); \
377+
} else { \
378+
SET_STACK_VAR_TYPE(_var, op_type); \
379+
op_info &= ~MAY_BE_GUARD; \
380+
} \
365381
ssa->var_info[_ssa_var].type &= op_info; \
366-
SET_STACK_VAR_TYPE(_var, op_type); \
367382
} \
368383
} \
369384
} while (0)
@@ -927,6 +942,30 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
927942
ssa = zend_jit_trace_build_ssa(op_array, script);
928943
for (;;p++) {
929944
if (p->op == ZEND_JIT_TRACE_VM) {
945+
if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) {
946+
const zend_op *opline = p->opline;
947+
948+
switch (opline->opcode) {
949+
case ZEND_INCLUDE_OR_EVAL:
950+
ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
951+
break;
952+
case ZEND_FETCH_R:
953+
case ZEND_FETCH_W:
954+
case ZEND_FETCH_RW:
955+
case ZEND_FETCH_FUNC_ARG:
956+
case ZEND_FETCH_IS:
957+
case ZEND_FETCH_UNSET:
958+
case ZEND_UNSET_VAR:
959+
case ZEND_ISSET_ISEMPTY_VAR:
960+
if (opline->extended_value & ZEND_FETCH_LOCAL) {
961+
ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
962+
} else if ((opline->extended_value & (ZEND_FETCH_GLOBAL | ZEND_FETCH_GLOBAL_LOCK)) &&
963+
!op_array->function_name) {
964+
ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
965+
}
966+
break;
967+
}
968+
}
930969
ssa_ops_count += zend_jit_trace_op_len(p->opline);
931970
} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
932971
call_level++;
@@ -935,6 +974,14 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
935974
stack_size = stack_top;
936975
}
937976
} else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
977+
if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) {
978+
if (p->func != (zend_function*)&zend_pass_function
979+
&& (zend_string_equals_literal(p->func->common.function_name, "extract")
980+
|| zend_string_equals_literal(p->func->common.function_name, "compact")
981+
|| zend_string_equals_literal(p->func->common.function_name, "get_defined_vars"))) {
982+
ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
983+
}
984+
}
938985
frame_size = zend_jit_trace_frame_size(p->op_array);
939986
if (call_level == 0) {
940987
if (stack_top + frame_size > stack_size) {
@@ -1739,13 +1786,20 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
17391786
/* Propagate guards through Phi sources */
17401787
zend_ssa_phi *phi = tssa->blocks[1].phis;
17411788

1789+
op_array = trace_buffer->op_array;
1790+
jit_extension =
1791+
(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1792+
ssa = &jit_extension->func_info.ssa;
1793+
17421794
while (phi) {
17431795
uint32_t t = ssa_var_info[phi->ssa_var].type;
17441796
uint32_t t0 = ssa_var_info[phi->sources[0]].type;
17451797
uint32_t t1 = ssa_var_info[phi->sources[1]].type;
17461798

17471799
if (t & MAY_BE_GUARD) {
1748-
if (((t0 | t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
1800+
if (zend_jit_var_may_be_modified_indirectly(op_array, ssa, phi->sources[0])) {
1801+
/* pass */
1802+
} else if (((t0 | t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
17491803
if (!((t0 | t1) & MAY_BE_GUARD)) {
17501804
ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
17511805
}
@@ -1905,7 +1959,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
19051959
vars_op_array[i] = op_array;
19061960
/* We don't start intervals for variables used in Phi */
19071961
if ((ssa->vars[i].use_chain >= 0 /*|| ssa->vars[i].phi_use_chain*/)
1908-
&& zend_jit_var_supports_reg(ssa, i)) {
1962+
&& zend_jit_var_supports_reg(ssa, i)
1963+
&& !zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, i)) {
19091964
start[i] = 0;
19101965
if (i < parent_vars_count
19111966
&& STACK_REG(parent_stack, i) != ZREG_NONE
@@ -1935,7 +1990,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
19351990
SET_STACK_VAR(stack, phi->var, phi->ssa_var);
19361991
vars_op_array[phi->ssa_var] = op_array;
19371992
if (ssa->vars[phi->ssa_var].use_chain >= 0
1938-
&& zend_jit_var_supports_reg(ssa, phi->ssa_var)) {
1993+
&& zend_jit_var_supports_reg(ssa, phi->ssa_var)
1994+
&& !zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, phi->sources[0])) {
19391995
start[phi->ssa_var] = 0;
19401996
count++;
19411997
}
@@ -2009,7 +2065,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
20092065
if (ssa_op->result_def >= 0
20102066
&& (ssa->vars[ssa_op->result_def].use_chain >= 0
20112067
|| ssa->vars[ssa_op->result_def].phi_use_chain)
2012-
&& zend_jit_var_supports_reg(ssa, ssa_op->result_def)) {
2068+
&& zend_jit_var_supports_reg(ssa, ssa_op->result_def)
2069+
&& !zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, EX_VAR_TO_NUM(opline->result.var))) {
20132070
if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
20142071
|| opline->opcode == ZEND_PRE_INC
20152072
|| opline->opcode == ZEND_PRE_DEC
@@ -2026,15 +2083,17 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
20262083
if (ssa_op->op1_def >= 0
20272084
&& (ssa->vars[ssa_op->op1_def].use_chain >= 0
20282085
|| ssa->vars[ssa_op->op1_def].phi_use_chain)
2029-
&& zend_jit_var_supports_reg(ssa, ssa_op->op1_def)) {
2086+
&& zend_jit_var_supports_reg(ssa, ssa_op->op1_def)
2087+
&& !zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, EX_VAR_TO_NUM(opline->op1.var))) {
20302088
start[ssa_op->op1_def] = idx;
20312089
vars_op_array[ssa_op->op1_def] = op_array;
20322090
count++;
20332091
}
20342092
if (ssa_op->op2_def >= 0
20352093
&& (ssa->vars[ssa_op->op2_def].use_chain >= 0
20362094
|| ssa->vars[ssa_op->op2_def].phi_use_chain)
2037-
&& zend_jit_var_supports_reg(ssa, ssa_op->op2_def)) {
2095+
&& zend_jit_var_supports_reg(ssa, ssa_op->op2_def)
2096+
&& !zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, EX_VAR_TO_NUM(opline->op2.var))) {
20382097
start[ssa_op->op2_def] = idx;
20392098
vars_op_array[ssa_op->op2_def] = op_array;
20402099
count++;
@@ -2071,7 +2130,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
20712130
if (support_opline
20722131
&& (ssa->vars[ssa_op->op1_def].use_chain >= 0
20732132
|| ssa->vars[ssa_op->op1_def].phi_use_chain)
2074-
&& zend_jit_var_supports_reg(ssa, ssa_op->op1_def)) {
2133+
&& zend_jit_var_supports_reg(ssa, ssa_op->op1_def)
2134+
&& !zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, EX_VAR_TO_NUM(opline->op1.var))) {
20752135
start[ssa_op->op1_def] = idx;
20762136
vars_op_array[ssa_op->op1_def] = op_array;
20772137
count++;
@@ -2129,7 +2189,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
21292189
SET_STACK_VAR(stack, i, j);
21302190
vars_op_array[j] = op_array;
21312191
if (ssa->vars[j].use_chain >= 0
2132-
&& zend_jit_var_supports_reg(ssa, j)) {
2192+
&& zend_jit_var_supports_reg(ssa, j)
2193+
&& !zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, i)) {
21332194
start[j] = idx;
21342195
flags[j] = ZREG_LOAD;
21352196
count++;
@@ -2158,7 +2219,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
21582219
SET_STACK_VAR(stack, i, j);
21592220
vars_op_array[j] = op_array;
21602221
if (ssa->vars[j].use_chain >= 0
2161-
&& zend_jit_var_supports_reg(ssa, j)) {
2222+
&& zend_jit_var_supports_reg(ssa, j)
2223+
&& !zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, i)) {
21622224
start[j] = idx;
21632225
flags[j] = ZREG_LOAD;
21642226
count++;
@@ -2620,6 +2682,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
26202682

26212683
if (!(info & MAY_BE_GUARD) && has_concrete_type(info)) {
26222684
SET_STACK_TYPE(stack, i, concrete_type(info));
2685+
} else if (zend_jit_var_may_be_modified_indirectly(op_array, op_array_ssa, i)) {
2686+
SET_STACK_TYPE(stack, i, IS_UNKNOWN);
26232687
} else if (i < parent_vars_count
26242688
&& STACK_TYPE(parent_stack, i) != IS_UNKNOWN) {
26252689
/* This must be already handled by trace type inference */

0 commit comments

Comments
 (0)