@@ -338,6 +338,15 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
338
338
return zend_jit_trace_type_to_info_ex (type , -1 );
339
339
}
340
340
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
+
341
350
#define STACK_VAR_TYPE (_var ) \
342
351
STACK_TYPE(stack, EX_VAR_TO_NUM(_var))
343
352
@@ -348,7 +357,9 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
348
357
#define ADD_OP_GUARD (_var , _op_type ) do { \
349
358
if (_var >= 0 && _op_type != IS_UNKNOWN) { \
350
359
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)) { \
352
363
info->type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex(_op_type, info->type); \
353
364
} \
354
365
} \
@@ -361,9 +372,13 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
361
372
if (!zend_jit_type_guard(&dasm_state, opline, _var, op_type)) { \
362
373
goto jit_failure; \
363
374
} \
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
+ } \
365
381
ssa->var_info[_ssa_var].type &= op_info; \
366
- SET_STACK_VAR_TYPE(_var, op_type); \
367
382
} \
368
383
} \
369
384
} while (0)
@@ -927,6 +942,30 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
927
942
ssa = zend_jit_trace_build_ssa (op_array , script );
928
943
for (;;p ++ ) {
929
944
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
+ }
930
969
ssa_ops_count += zend_jit_trace_op_len (p -> opline );
931
970
} else if (p -> op == ZEND_JIT_TRACE_INIT_CALL ) {
932
971
call_level ++ ;
@@ -935,6 +974,14 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
935
974
stack_size = stack_top ;
936
975
}
937
976
} 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
+ }
938
985
frame_size = zend_jit_trace_frame_size (p -> op_array );
939
986
if (call_level == 0 ) {
940
987
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
1739
1786
/* Propagate guards through Phi sources */
1740
1787
zend_ssa_phi * phi = tssa -> blocks [1 ].phis ;
1741
1788
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
+
1742
1794
while (phi ) {
1743
1795
uint32_t t = ssa_var_info [phi -> ssa_var ].type ;
1744
1796
uint32_t t0 = ssa_var_info [phi -> sources [0 ]].type ;
1745
1797
uint32_t t1 = ssa_var_info [phi -> sources [1 ]].type ;
1746
1798
1747
1799
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 ))) {
1749
1803
if (!((t0 | t1 ) & MAY_BE_GUARD )) {
1750
1804
ssa_var_info [phi -> ssa_var ].type = t & ~MAY_BE_GUARD ;
1751
1805
}
@@ -1905,7 +1959,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
1905
1959
vars_op_array [i ] = op_array ;
1906
1960
/* We don't start intervals for variables used in Phi */
1907
1961
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 )) {
1909
1964
start [i ] = 0 ;
1910
1965
if (i < parent_vars_count
1911
1966
&& STACK_REG (parent_stack , i ) != ZREG_NONE
@@ -1935,7 +1990,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
1935
1990
SET_STACK_VAR (stack , phi -> var , phi -> ssa_var );
1936
1991
vars_op_array [phi -> ssa_var ] = op_array ;
1937
1992
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 ])) {
1939
1995
start [phi -> ssa_var ] = 0 ;
1940
1996
count ++ ;
1941
1997
}
@@ -2009,7 +2065,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
2009
2065
if (ssa_op -> result_def >= 0
2010
2066
&& (ssa -> vars [ssa_op -> result_def ].use_chain >= 0
2011
2067
|| 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 ))) {
2013
2070
if (!(ssa -> var_info [ssa_op -> result_def ].type & MAY_BE_GUARD )
2014
2071
|| opline -> opcode == ZEND_PRE_INC
2015
2072
|| opline -> opcode == ZEND_PRE_DEC
@@ -2026,15 +2083,17 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
2026
2083
if (ssa_op -> op1_def >= 0
2027
2084
&& (ssa -> vars [ssa_op -> op1_def ].use_chain >= 0
2028
2085
|| 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 ))) {
2030
2088
start [ssa_op -> op1_def ] = idx ;
2031
2089
vars_op_array [ssa_op -> op1_def ] = op_array ;
2032
2090
count ++ ;
2033
2091
}
2034
2092
if (ssa_op -> op2_def >= 0
2035
2093
&& (ssa -> vars [ssa_op -> op2_def ].use_chain >= 0
2036
2094
|| 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 ))) {
2038
2097
start [ssa_op -> op2_def ] = idx ;
2039
2098
vars_op_array [ssa_op -> op2_def ] = op_array ;
2040
2099
count ++ ;
@@ -2071,7 +2130,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
2071
2130
if (support_opline
2072
2131
&& (ssa -> vars [ssa_op -> op1_def ].use_chain >= 0
2073
2132
|| 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 ))) {
2075
2135
start [ssa_op -> op1_def ] = idx ;
2076
2136
vars_op_array [ssa_op -> op1_def ] = op_array ;
2077
2137
count ++ ;
@@ -2129,7 +2189,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
2129
2189
SET_STACK_VAR (stack , i , j );
2130
2190
vars_op_array [j ] = op_array ;
2131
2191
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 )) {
2133
2194
start [j ] = idx ;
2134
2195
flags [j ] = ZREG_LOAD ;
2135
2196
count ++ ;
@@ -2158,7 +2219,8 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
2158
2219
SET_STACK_VAR (stack , i , j );
2159
2220
vars_op_array [j ] = op_array ;
2160
2221
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 )) {
2162
2224
start [j ] = idx ;
2163
2225
flags [j ] = ZREG_LOAD ;
2164
2226
count ++ ;
@@ -2620,6 +2682,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
2620
2682
2621
2683
if (!(info & MAY_BE_GUARD ) && has_concrete_type (info )) {
2622
2684
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 );
2623
2687
} else if (i < parent_vars_count
2624
2688
&& STACK_TYPE (parent_stack , i ) != IS_UNKNOWN ) {
2625
2689
/* This must be already handled by trace type inference */
0 commit comments