@@ -319,6 +319,126 @@ static zend_bool opline_supports_assign_contraction(
319
319
return 1 ;
320
320
}
321
321
322
+ int zend_dfa_optimize_calls (zend_op_array * op_array , zend_ssa * ssa )
323
+ {
324
+ zend_func_info * func_info = ZEND_FUNC_INFO (op_array );
325
+ int removed_ops = 0 ;
326
+
327
+ if (func_info -> callee_info ) {
328
+ zend_call_info * call_info = func_info -> callee_info ;
329
+ static zend_function * in_array_function = NULL ;
330
+
331
+ if (!in_array_function ) {
332
+ in_array_function = zend_hash_str_find_ptr (CG (function_table ), "in_array" , sizeof ("in_array" )- 1 );
333
+ }
334
+ do {
335
+ if (call_info -> callee_func == in_array_function
336
+ && (call_info -> caller_init_opline -> extended_value == 2
337
+ || (call_info -> caller_init_opline -> extended_value == 3
338
+ && (call_info -> caller_call_opline - 1 )-> opcode == ZEND_SEND_VAL
339
+ && (call_info -> caller_call_opline - 1 )-> op1_type == IS_CONST ))) {
340
+
341
+ zend_op * send_array ;
342
+ zend_op * send_needly ;
343
+ zend_bool strict = 0 ;
344
+
345
+ if (call_info -> caller_init_opline -> extended_value == 2 ) {
346
+ send_array = call_info -> caller_call_opline - 1 ;
347
+ send_needly = call_info -> caller_call_opline - 2 ;
348
+ } else {
349
+ if (zend_is_true (CT_CONSTANT_EX (op_array , (call_info -> caller_call_opline - 1 )-> op1 .constant ))) {
350
+ strict = 1 ;
351
+ }
352
+ send_array = call_info -> caller_call_opline - 2 ;
353
+ send_needly = call_info -> caller_call_opline - 3 ;
354
+ }
355
+
356
+ if (send_array -> opcode == ZEND_SEND_VAL
357
+ && send_array -> op1_type == IS_CONST
358
+ && Z_TYPE_P (CT_CONSTANT_EX (op_array , send_array -> op1 .constant )) == IS_ARRAY
359
+ && (send_needly -> opcode == ZEND_SEND_VAL
360
+ || send_needly -> opcode == ZEND_SEND_VAR )
361
+ ) {
362
+ int ok = 1 ;
363
+
364
+ HashTable * src = Z_ARRVAL_P (CT_CONSTANT_EX (op_array , send_array -> op1 .constant ));
365
+ HashTable * dst ;
366
+ zval * val , tmp ;
367
+ zend_ulong idx ;
368
+
369
+ ZVAL_TRUE (& tmp );
370
+ dst = emalloc (sizeof (HashTable ));
371
+ zend_hash_init (dst , zend_hash_num_elements (src ), NULL , ZVAL_PTR_DTOR , 0 );
372
+ if (strict ) {
373
+ ZEND_HASH_FOREACH_VAL (src , val ) {
374
+ if (Z_TYPE_P (val ) == IS_STRING ) {
375
+ zend_hash_add (dst , Z_STR_P (val ), & tmp );
376
+ } else if (Z_TYPE_P (val ) == IS_LONG ) {
377
+ zend_hash_index_add (dst , Z_LVAL_P (val ), & tmp );
378
+ } else {
379
+ zend_array_destroy (dst );
380
+ ok = 0 ;
381
+ break ;
382
+ }
383
+ } ZEND_HASH_FOREACH_END ();
384
+ } else {
385
+ ZEND_HASH_FOREACH_VAL (src , val ) {
386
+ if (Z_TYPE_P (val ) != IS_STRING || ZEND_HANDLE_NUMERIC (Z_STR_P (val ), idx )) {
387
+ zend_array_destroy (dst );
388
+ ok = 0 ;
389
+ break ;
390
+ }
391
+ zend_hash_add (dst , Z_STR_P (val ), & tmp );
392
+ } ZEND_HASH_FOREACH_END ();
393
+ }
394
+
395
+ if (ok ) {
396
+ uint32_t op_num = send_needly - op_array -> opcodes ;
397
+ zend_ssa_op * ssa_op = ssa -> ops + op_num ;
398
+
399
+ if (ssa_op -> op1_use >= 0 ) {
400
+ /* Reconstruct SSA */
401
+ int var_num = ssa_op -> op1_use ;
402
+ zend_ssa_var * var = ssa -> vars + var_num ;
403
+
404
+ ZEND_ASSERT (ssa_op -> op1_def < 0 );
405
+ zend_ssa_unlink_use_chain (ssa , op_num , ssa_op -> op1_use );
406
+ ssa_op -> op1_use = -1 ;
407
+ ssa_op -> op1_use_chain = -1 ;
408
+ op_num = call_info -> caller_call_opline - op_array -> opcodes ;
409
+ ssa_op = ssa -> ops + op_num ;
410
+ ssa_op -> op1_use = var_num ;
411
+ ssa_op -> op1_use_chain = var -> use_chain ;
412
+ var -> use_chain = op_num ;
413
+ }
414
+
415
+ ZVAL_ARR (& tmp , dst );
416
+
417
+ /* Update opcode */
418
+ call_info -> caller_call_opline -> opcode = ZEND_IN_ARRAY ;
419
+ call_info -> caller_call_opline -> extended_value = strict ;
420
+ call_info -> caller_call_opline -> op1_type = send_needly -> op1_type ;
421
+ call_info -> caller_call_opline -> op1 .num = send_needly -> op1 .num ;
422
+ call_info -> caller_call_opline -> op2_type = IS_CONST ;
423
+ call_info -> caller_call_opline -> op2 .constant = zend_optimizer_add_literal (op_array , & tmp );
424
+ if (call_info -> caller_init_opline -> extended_value == 3 ) {
425
+ MAKE_NOP (call_info -> caller_call_opline - 1 );
426
+ }
427
+ MAKE_NOP (call_info -> caller_init_opline );
428
+ MAKE_NOP (send_needly );
429
+ MAKE_NOP (send_array );
430
+ removed_ops ++ ;
431
+
432
+ }
433
+ }
434
+ }
435
+ call_info = call_info -> next_callee ;
436
+ } while (call_info );
437
+ }
438
+
439
+ return removed_ops ;
440
+ }
441
+
322
442
void zend_dfa_optimize_op_array (zend_op_array * op_array , zend_optimizer_ctx * ctx , zend_ssa * ssa , zend_call_info * * call_map )
323
443
{
324
444
if (ctx -> debug_level & ZEND_DUMP_BEFORE_DFA_PASS ) {
@@ -332,8 +452,18 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
332
452
zend_op * opline ;
333
453
zval tmp ;
334
454
335
- if (sccp_optimize_op_array (op_array , ssa , call_map )) {
336
- remove_nops = 1 ;
455
+ if (ZEND_OPTIMIZER_PASS_8 & ctx -> optimization_level ) {
456
+ if (sccp_optimize_op_array (op_array , ssa , call_map )) {
457
+ remove_nops = 1 ;
458
+ }
459
+ if (ZEND_FUNC_INFO (op_array )) {
460
+ if (zend_dfa_optimize_calls (op_array , ssa )) {
461
+ remove_nops = 1 ;
462
+ }
463
+ }
464
+ if (ctx -> debug_level & ZEND_DUMP_AFTER_SCCP_PASS ) {
465
+ zend_dump_op_array (op_array , ZEND_DUMP_SSA , "after sccp pass" , ssa );
466
+ }
337
467
}
338
468
339
469
for (v = op_array -> last_var ; v < ssa -> vars_count ; v ++ ) {
@@ -581,122 +711,6 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
581
711
}
582
712
}
583
713
584
- if (ZEND_FUNC_INFO (op_array )) {
585
- zend_func_info * func_info = ZEND_FUNC_INFO (op_array );
586
-
587
- if (func_info -> callee_info ) {
588
- zend_call_info * call_info = func_info -> callee_info ;
589
- static zend_function * in_array_function = NULL ;
590
-
591
- if (!in_array_function ) {
592
- in_array_function = zend_hash_str_find_ptr (CG (function_table ), "in_array" , sizeof ("in_array" )- 1 );
593
- }
594
- do {
595
- if (call_info -> callee_func == in_array_function
596
- && (call_info -> caller_init_opline -> extended_value == 2
597
- || (call_info -> caller_init_opline -> extended_value == 3
598
- && (call_info -> caller_call_opline - 1 )-> opcode == ZEND_SEND_VAL
599
- && (call_info -> caller_call_opline - 1 )-> op1_type == IS_CONST ))) {
600
-
601
- zend_op * send_array ;
602
- zend_op * send_needly ;
603
- zend_bool strict = 0 ;
604
-
605
- if (call_info -> caller_init_opline -> extended_value == 2 ) {
606
- send_array = call_info -> caller_call_opline - 1 ;
607
- send_needly = call_info -> caller_call_opline - 2 ;
608
- } else {
609
- if (zend_is_true (CT_CONSTANT_EX (op_array , (call_info -> caller_call_opline - 1 )-> op1 .constant ))) {
610
- strict = 1 ;
611
- }
612
- send_array = call_info -> caller_call_opline - 2 ;
613
- send_needly = call_info -> caller_call_opline - 3 ;
614
- }
615
-
616
- if (send_array -> opcode == ZEND_SEND_VAL
617
- && send_array -> op1_type == IS_CONST
618
- && Z_TYPE_P (CT_CONSTANT_EX (op_array , send_array -> op1 .constant )) == IS_ARRAY
619
- && (send_needly -> opcode == ZEND_SEND_VAL
620
- || send_needly -> opcode == ZEND_SEND_VAR )
621
- ) {
622
- int ok = 1 ;
623
-
624
- HashTable * src = Z_ARRVAL_P (CT_CONSTANT_EX (op_array , send_array -> op1 .constant ));
625
- HashTable * dst ;
626
- zval * val , tmp ;
627
- zend_ulong idx ;
628
-
629
- ZVAL_TRUE (& tmp );
630
- dst = emalloc (sizeof (HashTable ));
631
- zend_hash_init (dst , zend_hash_num_elements (src ), NULL , ZVAL_PTR_DTOR , 0 );
632
- if (strict ) {
633
- ZEND_HASH_FOREACH_VAL (src , val ) {
634
- if (Z_TYPE_P (val ) == IS_STRING ) {
635
- zend_hash_add (dst , Z_STR_P (val ), & tmp );
636
- } else if (Z_TYPE_P (val ) == IS_LONG ) {
637
- zend_hash_index_add (dst , Z_LVAL_P (val ), & tmp );
638
- } else {
639
- zend_array_destroy (dst );
640
- ok = 0 ;
641
- break ;
642
- }
643
- } ZEND_HASH_FOREACH_END ();
644
- } else {
645
- ZEND_HASH_FOREACH_VAL (src , val ) {
646
- if (Z_TYPE_P (val ) != IS_STRING || ZEND_HANDLE_NUMERIC (Z_STR_P (val ), idx )) {
647
- zend_array_destroy (dst );
648
- ok = 0 ;
649
- break ;
650
- }
651
- zend_hash_add (dst , Z_STR_P (val ), & tmp );
652
- } ZEND_HASH_FOREACH_END ();
653
- }
654
-
655
- if (ok ) {
656
- uint32_t op_num = send_needly - op_array -> opcodes ;
657
- zend_ssa_op * ssa_op = ssa -> ops + op_num ;
658
-
659
- if (ssa_op -> op1_use >= 0 ) {
660
- /* Reconstruct SSA */
661
- int var_num = ssa_op -> op1_use ;
662
- zend_ssa_var * var = ssa -> vars + var_num ;
663
-
664
- ZEND_ASSERT (ssa_op -> op1_def < 0 );
665
- zend_ssa_unlink_use_chain (ssa , op_num , ssa_op -> op1_use );
666
- ssa_op -> op1_use = -1 ;
667
- ssa_op -> op1_use_chain = -1 ;
668
- op_num = call_info -> caller_call_opline - op_array -> opcodes ;
669
- ssa_op = ssa -> ops + op_num ;
670
- ssa_op -> op1_use = var_num ;
671
- ssa_op -> op1_use_chain = var -> use_chain ;
672
- var -> use_chain = op_num ;
673
- }
674
-
675
- ZVAL_ARR (& tmp , dst );
676
-
677
- /* Update opcode */
678
- call_info -> caller_call_opline -> opcode = ZEND_IN_ARRAY ;
679
- call_info -> caller_call_opline -> extended_value = strict ;
680
- call_info -> caller_call_opline -> op1_type = send_needly -> op1_type ;
681
- call_info -> caller_call_opline -> op1 .num = send_needly -> op1 .num ;
682
- call_info -> caller_call_opline -> op2_type = IS_CONST ;
683
- call_info -> caller_call_opline -> op2 .constant = zend_optimizer_add_literal (op_array , & tmp );
684
- if (call_info -> caller_init_opline -> extended_value == 3 ) {
685
- MAKE_NOP (call_info -> caller_call_opline - 1 );
686
- }
687
- MAKE_NOP (call_info -> caller_init_opline );
688
- MAKE_NOP (send_needly );
689
- MAKE_NOP (send_array );
690
- remove_nops = 1 ;
691
-
692
- }
693
- }
694
- }
695
- call_info = call_info -> next_callee ;
696
- } while (call_info );
697
- }
698
- }
699
-
700
714
if (remove_nops ) {
701
715
zend_ssa_remove_nops (op_array , ssa );
702
716
}
0 commit comments