93
93
94
94
#define ADD_SCC_VAR (_var ) \
95
95
do { \
96
- if (ssa->vars[_var].scc == scc) { \
96
+ if (ssa->vars[_var].scc == scc && \
97
+ !(ssa->var_info[_var].type & MAY_BE_REF)) { \
97
98
zend_bitset_incl(worklist, _var); \
98
99
} \
99
100
} while (0)
100
101
101
102
#define ADD_SCC_VAR_1 (_var ) \
102
103
do { \
103
104
if (ssa->vars[_var].scc == scc && \
105
+ !(ssa->var_info[_var].type & MAY_BE_REF) && \
104
106
!zend_bitset_in(visited, _var)) { \
105
107
zend_bitset_incl(worklist, _var); \
106
108
} \
@@ -1657,7 +1659,8 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss
1657
1659
for (n = 0 ; n < RANGE_WARMUP_PASSES ; n ++ ) {
1658
1660
j = scc_var [scc ];
1659
1661
while (j >= 0 ) {
1660
- if (ssa -> vars [j ].scc_entry ) {
1662
+ if (ssa -> vars [j ].scc_entry
1663
+ && !(ssa -> var_info [j ].type & MAY_BE_REF )) {
1661
1664
zend_bitset_incl (worklist , j );
1662
1665
}
1663
1666
j = next_scc_var [j ];
@@ -1758,7 +1761,9 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
1758
1761
j = scc_var [scc ];
1759
1762
if (next_scc_var [j ] < 0 ) {
1760
1763
/* SCC with a single element */
1761
- if (zend_inference_calc_range (op_array , ssa , j , 0 , 1 , & tmp )) {
1764
+ if (ssa -> var_info [j ].type & MAY_BE_REF ) {
1765
+ /* pass */
1766
+ } else if (zend_inference_calc_range (op_array , ssa , j , 0 , 1 , & tmp )) {
1762
1767
zend_inference_init_range (op_array , ssa , j , tmp .underflow , tmp .min , tmp .max , tmp .overflow );
1763
1768
} else {
1764
1769
zend_inference_init_range (op_array , ssa , j , 1 , ZEND_LONG_MIN , ZEND_LONG_MAX , 1 );
@@ -1767,7 +1772,8 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
1767
1772
/* Find SCC entry points */
1768
1773
memset (worklist , 0 , sizeof (zend_ulong ) * worklist_len );
1769
1774
do {
1770
- if (ssa -> vars [j ].scc_entry ) {
1775
+ if (ssa -> vars [j ].scc_entry
1776
+ && !(ssa -> var_info [j ].type & MAY_BE_REF )) {
1771
1777
zend_bitset_incl (worklist , j );
1772
1778
}
1773
1779
j = next_scc_var [j ];
@@ -1777,7 +1783,9 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
1777
1783
zend_infer_ranges_warmup (op_array , ssa , scc_var , next_scc_var , scc );
1778
1784
j = scc_var [scc ];
1779
1785
do {
1780
- zend_bitset_incl (worklist , j );
1786
+ if (!(ssa -> var_info [j ].type & MAY_BE_REF )) {
1787
+ zend_bitset_incl (worklist , j );
1788
+ }
1781
1789
j = next_scc_var [j ];
1782
1790
} while (j >= 0 );
1783
1791
#endif
@@ -1791,7 +1799,8 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
1791
1799
1792
1800
/* initialize missing ranges */
1793
1801
for (j = scc_var [scc ]; j >= 0 ; j = next_scc_var [j ]) {
1794
- if (!ssa -> var_info [j ].has_range ) {
1802
+ if (!ssa -> var_info [j ].has_range
1803
+ && !(ssa -> var_info [j ].type & MAY_BE_REF )) {
1795
1804
zend_inference_init_range (op_array , ssa , j , 1 , ZEND_LONG_MIN , ZEND_LONG_MAX , 1 );
1796
1805
FOR_EACH_VAR_USAGE (j , ADD_SCC_VAR );
1797
1806
}
@@ -1807,7 +1816,8 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
1807
1816
/* Add all SCC entry variables into worklist for narrowing */
1808
1817
for (j = scc_var [scc ]; j >= 0 ; j = next_scc_var [j ]) {
1809
1818
if (ssa -> vars [j ].definition_phi
1810
- && ssa -> vars [j ].definition_phi -> pi < 0 ) {
1819
+ && ssa -> vars [j ].definition_phi -> pi < 0
1820
+ && !(ssa -> var_info [j ].type & MAY_BE_REF )) {
1811
1821
/* narrowing Phi functions first */
1812
1822
zend_ssa_range_narrowing (op_array , ssa , j , scc );
1813
1823
}
@@ -4273,6 +4283,134 @@ static int zend_infer_types(const zend_op_array *op_array, const zend_script *sc
4273
4283
return SUCCESS ;
4274
4284
}
4275
4285
4286
+ static int zend_mark_cv_references (const zend_op_array * op_array , const zend_script * script , zend_ssa * ssa )
4287
+ {
4288
+ int var , def ;
4289
+ const zend_op * opline ;
4290
+ zend_arg_info * arg_info ;
4291
+ uint32_t worklist_len = zend_bitset_len (ssa -> vars_count );
4292
+ zend_bitset worklist ;
4293
+ ALLOCA_FLAG (use_heap );
4294
+
4295
+ worklist = do_alloca (sizeof (zend_ulong ) * worklist_len , use_heap );
4296
+ memset (worklist , 0 , sizeof (zend_ulong ) * worklist_len );
4297
+
4298
+ /* Collect SSA variables which definitions creates PHP reference */
4299
+ for (var = 0 ; var < ssa -> vars_count ; var ++ ) {
4300
+ def = ssa -> vars [var ].definition ;
4301
+ if (def >= 0 && ssa -> vars [var ].var < op_array -> last_var ) {
4302
+ opline = op_array -> opcodes + def ;
4303
+ if (ssa -> ops [def ].result_def == var ) {
4304
+ switch (opline -> opcode ) {
4305
+ case ZEND_RECV :
4306
+ case ZEND_RECV_INIT :
4307
+ arg_info = & op_array -> arg_info [opline -> op1 .num - 1 ];
4308
+ if (!ZEND_ARG_SEND_MODE (arg_info )) {
4309
+ continue ;
4310
+ }
4311
+ break ;
4312
+ default :
4313
+ continue ;
4314
+ }
4315
+ } else if (ssa -> ops [def ].op1_def == var ) {
4316
+ switch (opline -> opcode ) {
4317
+ case ZEND_ASSIGN_REF :
4318
+ case ZEND_MAKE_REF :
4319
+ case ZEND_FE_RESET_RW :
4320
+ case ZEND_BIND_GLOBAL :
4321
+ case ZEND_SEND_REF :
4322
+ case ZEND_SEND_VAR_EX :
4323
+ case ZEND_SEND_FUNC_ARG :
4324
+ break ;
4325
+ case ZEND_ADD_ARRAY_ELEMENT :
4326
+ if (!(opline -> extended_value & ZEND_ARRAY_ELEMENT_REF )) {
4327
+ continue ;
4328
+ }
4329
+ break ;
4330
+ case ZEND_BIND_LEXICAL :
4331
+ case ZEND_BIND_STATIC :
4332
+ if (!(opline -> extended_value & ZEND_BIND_REF )) {
4333
+ continue ;
4334
+ }
4335
+ break ;
4336
+ case ZEND_YIELD :
4337
+ if (!(op_array -> fn_flags & ZEND_ACC_RETURN_REFERENCE )) {
4338
+ continue ;
4339
+ }
4340
+ break ;
4341
+ case ZEND_OP_DATA :
4342
+ switch ((opline - 1 )-> opcode ) {
4343
+ case ZEND_ASSIGN_OBJ_REF :
4344
+ case ZEND_ASSIGN_STATIC_PROP_REF :
4345
+ break ;
4346
+ default :
4347
+ continue ;
4348
+ }
4349
+ break ;
4350
+ default :
4351
+ continue ;
4352
+ }
4353
+ } else if (ssa -> ops [def ].op2_def == var ) {
4354
+ if (opline -> opcode != ZEND_ASSIGN_REF ) {
4355
+ continue ;
4356
+ }
4357
+ } else {
4358
+ ZEND_UNREACHABLE ();
4359
+ }
4360
+ zend_bitset_incl (worklist , var );
4361
+ } else if (ssa -> var_info [var ].type & MAY_BE_REF ) {
4362
+ zend_bitset_incl (worklist , var );
4363
+ } else if (ssa -> vars [var ].alias == SYMTABLE_ALIAS ) {
4364
+ zend_bitset_incl (worklist , var );
4365
+ }
4366
+ }
4367
+
4368
+ /* Set and propagate MAY_BE_REF */
4369
+ WHILE_WORKLIST (worklist , worklist_len , var ) {
4370
+
4371
+ ssa -> var_info [var ].type |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF ;
4372
+
4373
+ if (ssa -> vars [var ].phi_use_chain ) {
4374
+ zend_ssa_phi * p = ssa -> vars [var ].phi_use_chain ;
4375
+ do {
4376
+ if (!(ssa -> var_info [p -> ssa_var ].type & MAY_BE_REF )) {
4377
+ zend_bitset_incl (worklist , p -> ssa_var );
4378
+ }
4379
+ p = zend_ssa_next_use_phi (ssa , var , p );
4380
+ } while (p );
4381
+ }
4382
+
4383
+ if (ssa -> vars [var ].use_chain >= 0 ) {
4384
+ int use = ssa -> vars [var ].use_chain ;
4385
+ zend_ssa_op * op ;
4386
+
4387
+ do {
4388
+ op = ssa -> ops + use ;
4389
+ if (op -> op1_use == var && op -> op1_def >= 0 ) {
4390
+ if (!(ssa -> var_info [op -> op1_def ].type & MAY_BE_REF )) {
4391
+ zend_bitset_incl (worklist , op -> op1_def );
4392
+ }
4393
+ }
4394
+ if (op -> op2_use == var && op -> op2_def >= 0 ) {
4395
+ if (!(ssa -> var_info [op -> op2_def ].type & MAY_BE_REF )) {
4396
+ zend_bitset_incl (worklist , op -> op2_def );
4397
+ }
4398
+ }
4399
+ if (op -> result_use == var && op -> result_def >= 0 ) {
4400
+ if (!(ssa -> var_info [op -> result_def ].type & MAY_BE_REF )) {
4401
+ zend_bitset_incl (worklist , op -> result_def );
4402
+ }
4403
+ }
4404
+
4405
+ use = zend_ssa_next_use (ssa -> ops , var , use );
4406
+ } while (use >= 0 );
4407
+ }
4408
+ } WHILE_WORKLIST_END ();
4409
+
4410
+ free_alloca (worklist , use_heap );
4411
+ return SUCCESS ;
4412
+ }
4413
+
4276
4414
ZEND_API int zend_ssa_inference (zend_arena * * arena , const zend_op_array * op_array , const zend_script * script , zend_ssa * ssa , zend_long optimization_level ) /* {{{ */
4277
4415
{
4278
4416
zend_ssa_var_info * ssa_var_info ;
@@ -4302,6 +4440,10 @@ ZEND_API int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_arra
4302
4440
ssa_var_info [i ].has_range = 0 ;
4303
4441
}
4304
4442
4443
+ if (zend_mark_cv_references (op_array , script , ssa ) != SUCCESS ) {
4444
+ return FAILURE ;
4445
+ }
4446
+
4305
4447
if (zend_infer_ranges (op_array , ssa ) != SUCCESS ) {
4306
4448
return FAILURE ;
4307
4449
}
0 commit comments