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
}
@@ -1867,6 +1877,10 @@ static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) {
1867
1877
} \
1868
1878
} \
1869
1879
if (ssa_var_info [__var ].type != __type ) { \
1880
+ ZEND_ASSERT (ssa_opcodes != NULL || \
1881
+ __ssa_var -> var >= op_array -> last_var || \
1882
+ (ssa_var_info [__var ].type & MAY_BE_REF ) \
1883
+ == (__type & MAY_BE_REF )); \
1870
1884
if (ssa_var_info [__var ].type & ~__type ) { \
1871
1885
emit_type_narrowing_warning (op_array , ssa , __var ); \
1872
1886
return FAILURE ; \
@@ -3432,7 +3446,7 @@ static zend_always_inline int _zend_update_type_info(
3432
3446
zend_property_info * prop_info = zend_fetch_prop_info (op_array , ssa , opline , ssa_op );
3433
3447
3434
3448
tmp = zend_fetch_prop_type (script , prop_info , & ce );
3435
- if (opline -> result_type != IS_TMP_VAR ) {
3449
+ if (opline -> result_type == IS_VAR ) {
3436
3450
tmp |= MAY_BE_REF | MAY_BE_INDIRECT ;
3437
3451
} else if (!(opline -> op1_type & (IS_VAR |IS_TMP_VAR )) || !(t1 & MAY_BE_RC1 )) {
3438
3452
zend_class_entry * ce = NULL ;
@@ -3468,7 +3482,7 @@ static zend_always_inline int _zend_update_type_info(
3468
3482
case ZEND_FETCH_STATIC_PROP_FUNC_ARG :
3469
3483
tmp = zend_fetch_prop_type (script ,
3470
3484
zend_fetch_static_prop_info (script , op_array , ssa , opline ), & ce );
3471
- if (opline -> result_type != IS_TMP_VAR ) {
3485
+ if (opline -> result_type == IS_VAR ) {
3472
3486
tmp |= MAY_BE_REF | MAY_BE_INDIRECT ;
3473
3487
} else {
3474
3488
tmp &= ~MAY_BE_RC1 ;
@@ -3587,6 +3601,8 @@ static zend_always_inline int _zend_update_type_info(
3587
3601
} else {
3588
3602
tmp |= MAY_BE_RC1 | MAY_BE_RCN ;
3589
3603
}
3604
+ } else if (opline -> result_type == IS_CV ) {
3605
+ tmp |= MAY_BE_RC1 | MAY_BE_RCN ;
3590
3606
} else {
3591
3607
tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN ;
3592
3608
switch (opline -> opcode ) {
@@ -3685,6 +3701,7 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script
3685
3701
int i , j ;
3686
3702
uint32_t tmp , worklist_len = zend_bitset_len (ssa_vars_count );
3687
3703
bool update_worklist = 1 ;
3704
+ const zend_op * * ssa_opcodes = NULL ;
3688
3705
3689
3706
while (!zend_bitset_empty (worklist , worklist_len )) {
3690
3707
j = zend_bitset_first (worklist , worklist_len );
@@ -4242,7 +4259,6 @@ void zend_func_return_info(const zend_op_array *op_array,
4242
4259
4243
4260
static int zend_infer_types (const zend_op_array * op_array , const zend_script * script , zend_ssa * ssa , zend_long optimization_level )
4244
4261
{
4245
- zend_ssa_var_info * ssa_var_info = ssa -> var_info ;
4246
4262
int ssa_vars_count = ssa -> vars_count ;
4247
4263
int j ;
4248
4264
zend_bitset worklist ;
@@ -4254,7 +4270,6 @@ static int zend_infer_types(const zend_op_array *op_array, const zend_script *sc
4254
4270
/* Type Inference */
4255
4271
for (j = op_array -> last_var ; j < ssa_vars_count ; j ++ ) {
4256
4272
zend_bitset_incl (worklist , j );
4257
- ssa_var_info [j ].type = 0 ;
4258
4273
}
4259
4274
4260
4275
if (zend_infer_types_ex (op_array , script , ssa , worklist , optimization_level ) != SUCCESS ) {
@@ -4273,6 +4288,144 @@ static int zend_infer_types(const zend_op_array *op_array, const zend_script *sc
4273
4288
return SUCCESS ;
4274
4289
}
4275
4290
4291
+ static int zend_mark_cv_references (const zend_op_array * op_array , const zend_script * script , zend_ssa * ssa )
4292
+ {
4293
+ int var , def ;
4294
+ const zend_op * opline ;
4295
+ zend_arg_info * arg_info ;
4296
+ uint32_t worklist_len = zend_bitset_len (ssa -> vars_count );
4297
+ zend_bitset worklist ;
4298
+ ALLOCA_FLAG (use_heap );
4299
+
4300
+ worklist = do_alloca (sizeof (zend_ulong ) * worklist_len , use_heap );
4301
+ memset (worklist , 0 , sizeof (zend_ulong ) * worklist_len );
4302
+
4303
+ /* Collect SSA variables which definitions creates PHP reference */
4304
+ for (var = 0 ; var < ssa -> vars_count ; var ++ ) {
4305
+ def = ssa -> vars [var ].definition ;
4306
+ if (def >= 0 && ssa -> vars [var ].var < op_array -> last_var ) {
4307
+ opline = op_array -> opcodes + def ;
4308
+ if (ssa -> ops [def ].result_def == var ) {
4309
+ switch (opline -> opcode ) {
4310
+ case ZEND_RECV :
4311
+ case ZEND_RECV_INIT :
4312
+ arg_info = & op_array -> arg_info [opline -> op1 .num - 1 ];
4313
+ if (!ZEND_ARG_SEND_MODE (arg_info )) {
4314
+ continue ;
4315
+ }
4316
+ break ;
4317
+ default :
4318
+ continue ;
4319
+ }
4320
+ } else if (ssa -> ops [def ].op1_def == var ) {
4321
+ switch (opline -> opcode ) {
4322
+ case ZEND_ASSIGN_REF :
4323
+ case ZEND_MAKE_REF :
4324
+ case ZEND_FE_RESET_RW :
4325
+ case ZEND_BIND_GLOBAL :
4326
+ case ZEND_SEND_REF :
4327
+ case ZEND_SEND_VAR_EX :
4328
+ case ZEND_SEND_FUNC_ARG :
4329
+ break ;
4330
+ case ZEND_INIT_ARRAY :
4331
+ case ZEND_ADD_ARRAY_ELEMENT :
4332
+ if (!(opline -> extended_value & ZEND_ARRAY_ELEMENT_REF )) {
4333
+ continue ;
4334
+ }
4335
+ break ;
4336
+ case ZEND_BIND_STATIC :
4337
+ if (!(opline -> extended_value & ZEND_BIND_REF )) {
4338
+ continue ;
4339
+ }
4340
+ break ;
4341
+ case ZEND_YIELD :
4342
+ if (!(op_array -> fn_flags & ZEND_ACC_RETURN_REFERENCE )) {
4343
+ continue ;
4344
+ }
4345
+ break ;
4346
+ case ZEND_OP_DATA :
4347
+ switch ((opline - 1 )-> opcode ) {
4348
+ case ZEND_ASSIGN_OBJ_REF :
4349
+ case ZEND_ASSIGN_STATIC_PROP_REF :
4350
+ break ;
4351
+ default :
4352
+ continue ;
4353
+ }
4354
+ break ;
4355
+ default :
4356
+ continue ;
4357
+ }
4358
+ } else if (ssa -> ops [def ].op2_def == var ) {
4359
+ switch (opline -> opcode ) {
4360
+ case ZEND_ASSIGN_REF :
4361
+ case ZEND_FE_FETCH_RW :
4362
+ break ;
4363
+ case ZEND_BIND_LEXICAL :
4364
+ if (!(opline -> extended_value & ZEND_BIND_REF )) {
4365
+ continue ;
4366
+ }
4367
+ break ;
4368
+ default :
4369
+ continue ;
4370
+ }
4371
+ } else {
4372
+ ZEND_UNREACHABLE ();
4373
+ }
4374
+ zend_bitset_incl (worklist , var );
4375
+ } else if (ssa -> var_info [var ].type & MAY_BE_REF ) {
4376
+ zend_bitset_incl (worklist , var );
4377
+ } else if (ssa -> vars [var ].alias == SYMTABLE_ALIAS ) {
4378
+ zend_bitset_incl (worklist , var );
4379
+ }
4380
+ }
4381
+
4382
+ /* Set and propagate MAY_BE_REF */
4383
+ WHILE_WORKLIST (worklist , worklist_len , var ) {
4384
+
4385
+ 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 ;
4386
+
4387
+ if (ssa -> vars [var ].phi_use_chain ) {
4388
+ zend_ssa_phi * p = ssa -> vars [var ].phi_use_chain ;
4389
+ do {
4390
+ if (!(ssa -> var_info [p -> ssa_var ].type & MAY_BE_REF )) {
4391
+ zend_bitset_incl (worklist , p -> ssa_var );
4392
+ }
4393
+ p = zend_ssa_next_use_phi (ssa , var , p );
4394
+ } while (p );
4395
+ }
4396
+
4397
+ if (ssa -> vars [var ].use_chain >= 0 ) {
4398
+ int use = ssa -> vars [var ].use_chain ;
4399
+ FOREACH_USE (& ssa -> vars [var ], use ) {
4400
+ zend_ssa_op * op = ssa -> ops + use ;
4401
+ if (op -> op1_use == var && op -> op1_def >= 0 ) {
4402
+ if (!(ssa -> var_info [op -> op1_def ].type & MAY_BE_REF )) {
4403
+ /* Unset breaks references (outside global scope). */
4404
+ if (op_array -> opcodes [use ].opcode == ZEND_UNSET_CV
4405
+ && op_array -> function_name ) {
4406
+ continue ;
4407
+ }
4408
+ zend_bitset_incl (worklist , op -> op1_def );
4409
+ }
4410
+ }
4411
+ if (op -> op2_use == var && op -> op2_def >= 0 ) {
4412
+ if (!(ssa -> var_info [op -> op2_def ].type & MAY_BE_REF )) {
4413
+ zend_bitset_incl (worklist , op -> op2_def );
4414
+ }
4415
+ }
4416
+ if (op -> result_use == var && op -> result_def >= 0 ) {
4417
+ if (!(ssa -> var_info [op -> result_def ].type & MAY_BE_REF )) {
4418
+ zend_bitset_incl (worklist , op -> result_def );
4419
+ }
4420
+ }
4421
+ } FOREACH_USE_END ();
4422
+ }
4423
+ } WHILE_WORKLIST_END ();
4424
+
4425
+ free_alloca (worklist , use_heap );
4426
+ return SUCCESS ;
4427
+ }
4428
+
4276
4429
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
4430
{
4278
4431
zend_ssa_var_info * ssa_var_info ;
@@ -4302,6 +4455,10 @@ ZEND_API int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_arra
4302
4455
ssa_var_info [i ].has_range = 0 ;
4303
4456
}
4304
4457
4458
+ if (zend_mark_cv_references (op_array , script , ssa ) != SUCCESS ) {
4459
+ return FAILURE ;
4460
+ }
4461
+
4305
4462
if (zend_infer_ranges (op_array , ssa ) != SUCCESS ) {
4306
4463
return FAILURE ;
4307
4464
}
0 commit comments