@@ -547,12 +547,37 @@ static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const ze
547547 return opline -> opcode == ZEND_BRK ? jmp_to -> brk : jmp_to -> cont ;
548548}
549549
550+ static void emit_live_range_raw (
551+ zend_op_array * op_array , uint32_t var_num , uint32_t kind , uint32_t start , uint32_t end ,
552+ zend_op * orig_def_opline , zend_needs_live_range_cb needs_live_range ) {
553+ zend_live_range * range ;
554+ if (start == end ) {
555+ /* Trivial live-range, no need to store it. */
556+ return ;
557+ }
558+
559+ /* Check hook to determine whether a live range is necessary, e.g. based on type info. */
560+ if (needs_live_range && !needs_live_range (op_array , orig_def_opline )) {
561+ return ;
562+ }
563+
564+ op_array -> last_live_range ++ ;
565+ op_array -> live_range = erealloc (op_array -> live_range ,
566+ sizeof (zend_live_range ) * op_array -> last_live_range );
567+
568+ ZEND_ASSERT (start < end );
569+ range = & op_array -> live_range [op_array -> last_live_range - 1 ];
570+ range -> var = (uint32_t ) (intptr_t ) ZEND_CALL_VAR_NUM (NULL , op_array -> last_var + var_num );
571+ range -> var |= kind ;
572+ range -> start = start ;
573+ range -> end = end ;
574+ }
575+
550576static void emit_live_range (
551577 zend_op_array * op_array , uint32_t var_num , uint32_t start , uint32_t end ,
552578 zend_needs_live_range_cb needs_live_range ) {
553579 zend_op * def_opline = & op_array -> opcodes [start ], * orig_def_opline = def_opline ;
554580 zend_op * use_opline = & op_array -> opcodes [end ];
555- zend_live_range * range ;
556581 uint32_t kind = ZEND_LIVE_TMPVAR ;
557582
558583 switch (def_opline -> opcode ) {
@@ -587,7 +612,8 @@ static void emit_live_range(
587612 break ;
588613 /* Objects created via ZEND_NEW are only fully initialized
589614 * after the DO_FCALL (constructor call). */
590- case ZEND_NEW : {
615+ case ZEND_NEW :
616+ {
591617 int level = 0 ;
592618 while (def_opline + 1 < use_opline ) {
593619 def_opline ++ ;
@@ -618,29 +644,35 @@ static void emit_live_range(
618644 }
619645 break ;
620646 }
647+ case ZEND_COPY_TMP :
648+ {
649+ /* COPY_TMP has a split live-range: One from the definition until the use in
650+ * "null" branch, and another from the start of the "non-null" branch to the
651+ * FREE opcode. */
652+ zend_op * block_start_op = use_opline ;
653+ while ((block_start_op - 1 )-> opcode == ZEND_FREE ) {
654+ block_start_op -- ;
655+ }
656+ start = block_start_op - op_array -> opcodes ;
657+ emit_live_range_raw (
658+ op_array , var_num , kind , start , end , orig_def_opline , needs_live_range );
659+
660+ do {
661+ use_opline -- ;
662+ } while (
663+ (use_opline -> op1_type & (IS_TMP_VAR |IS_VAR ) && use_opline -> op1 .var == var_num ) ||
664+ (use_opline -> op2_type & (IS_TMP_VAR |IS_VAR ) && use_opline -> op2 .var == var_num )
665+ );
666+ start = def_opline + 1 - op_array -> opcodes ;
667+ end = use_opline - op_array -> opcodes ;
668+ emit_live_range_raw (
669+ op_array , var_num , kind , start , end , orig_def_opline , needs_live_range );
670+ return ;
671+ }
621672 }
622673
623674 start = def_opline + 1 - op_array -> opcodes ;
624- if (start == end ) {
625- /* Trivial live-range, no need to store it. */
626- return ;
627- }
628-
629- /* Check hook to determine whether a live range is necessary, e.g. based on type info. */
630- if (needs_live_range && !needs_live_range (op_array , orig_def_opline )) {
631- return ;
632- }
633-
634- op_array -> last_live_range ++ ;
635- op_array -> live_range = erealloc (op_array -> live_range ,
636- sizeof (zend_live_range ) * op_array -> last_live_range );
637-
638- ZEND_ASSERT (start < end );
639- range = & op_array -> live_range [op_array -> last_live_range - 1 ];
640- range -> var = (uint32_t ) (intptr_t ) ZEND_CALL_VAR_NUM (NULL , op_array -> last_var + var_num );
641- range -> var |= kind ;
642- range -> start = start ;
643- range -> end = end ;
675+ emit_live_range_raw (op_array , var_num , kind , start , end , orig_def_opline , needs_live_range );
644676}
645677
646678static zend_bool is_fake_def (zend_op * opline ) {
0 commit comments