@@ -281,6 +281,14 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
281
281
opline -> opcode = ZEND_SEND_VAL ;
282
282
opline -> op1 .constant = zend_optimizer_add_literal (op_array , val );
283
283
break ;
284
+ case ZEND_CASE :
285
+ opline -> opcode = ZEND_IS_EQUAL ;
286
+ opline -> op1 .constant = zend_optimizer_add_literal (op_array , val );
287
+ break ;
288
+ case ZEND_CASE_STRICT :
289
+ opline -> opcode = ZEND_IS_IDENTICAL ;
290
+ opline -> op1 .constant = zend_optimizer_add_literal (op_array , val );
291
+ break ;
284
292
case ZEND_SEPARATE :
285
293
case ZEND_SEND_VAR_NO_REF :
286
294
case ZEND_SEND_VAR_NO_REF_EX :
@@ -289,9 +297,6 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
289
297
/* This would require a non-local change.
290
298
* zend_optimizer_replace_by_const() supports this. */
291
299
return 0 ;
292
- case ZEND_CASE :
293
- case ZEND_CASE_STRICT :
294
- case ZEND_FETCH_LIST_R :
295
300
case ZEND_COPY_TMP :
296
301
case ZEND_FETCH_CLASS_NAME :
297
302
return 0 ;
@@ -562,72 +567,38 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
562
567
break ;
563
568
/* In most cases IS_TMP_VAR operand may be used only once.
564
569
* The operands are usually destroyed by the opcode handler.
565
- * ZEND_CASE[_STRICT] and ZEND_FETCH_LIST_R are exceptions, they keeps operand
566
- * unchanged, and allows its reuse. these instructions
567
- * usually terminated by ZEND_FREE that finally kills the value.
570
+ * However, there are some exception which keep the operand alive. In that case
571
+ * we want to try to replace all uses of the temporary.
568
572
*/
569
- case ZEND_FETCH_LIST_R : {
570
- zend_op * m = opline ;
571
-
572
- do {
573
- if (m -> opcode == ZEND_FETCH_LIST_R &&
574
- m -> op1_type == type &&
575
- m -> op1 .var == var ) {
576
- zval v ;
577
- ZVAL_COPY (& v , val );
578
- if (Z_TYPE (v ) == IS_STRING ) {
579
- zend_string_hash_val (Z_STR (v ));
580
- }
581
- m -> op1 .constant = zend_optimizer_add_literal (op_array , & v );
582
- m -> op1_type = IS_CONST ;
583
- }
584
- m ++ ;
585
- } while (m -> opcode != ZEND_FREE || m -> op1_type != type || m -> op1 .var != var );
586
-
587
- ZEND_ASSERT (m -> opcode == ZEND_FREE && m -> op1_type == type && m -> op1 .var == var );
588
- MAKE_NOP (m );
589
- zval_ptr_dtor_nogc (val );
590
- return 1 ;
591
- }
573
+ case ZEND_FETCH_LIST_R :
574
+ case ZEND_CASE :
575
+ case ZEND_CASE_STRICT :
592
576
case ZEND_SWITCH_LONG :
593
577
case ZEND_SWITCH_STRING :
594
578
case ZEND_MATCH :
595
- case ZEND_CASE :
596
- case ZEND_CASE_STRICT : {
579
+ case ZEND_JMP_NULL : {
597
580
zend_op * end = op_array -> opcodes + op_array -> last ;
598
581
while (opline < end ) {
599
582
if (opline -> op1_type == type && opline -> op1 .var == var ) {
600
- if (
601
- opline -> opcode == ZEND_CASE
602
- || opline -> opcode == ZEND_CASE_STRICT
603
- || opline -> opcode == ZEND_SWITCH_LONG
604
- || opline -> opcode == ZEND_SWITCH_STRING
605
- || opline -> opcode == ZEND_MATCH
606
- ) {
607
- zval v ;
608
-
609
- if (opline -> opcode == ZEND_CASE ) {
610
- opline -> opcode = ZEND_IS_EQUAL ;
611
- } else if (opline -> opcode == ZEND_CASE_STRICT ) {
612
- opline -> opcode = ZEND_IS_IDENTICAL ;
613
- }
614
- ZVAL_COPY (& v , val );
615
- if (Z_TYPE (v ) == IS_STRING ) {
616
- zend_string_hash_val (Z_STR (v ));
617
- }
618
- opline -> op1 .constant = zend_optimizer_add_literal (op_array , & v );
619
- opline -> op1_type = IS_CONST ;
620
- } else if (opline -> opcode == ZEND_FREE ) {
621
- if (opline -> extended_value == ZEND_FREE_SWITCH ) {
622
- /* We found the end of the switch. */
623
- MAKE_NOP (opline );
624
- break ;
625
- }
626
-
627
- ZEND_ASSERT (opline -> extended_value == ZEND_FREE_ON_RETURN );
628
- MAKE_NOP (opline );
629
- } else {
630
- ZEND_UNREACHABLE ();
583
+ /* If this opcode doesn't keep the operand alive, we're done. Check
584
+ * this early, because op replacement may modify the opline. */
585
+ bool is_last = opline -> opcode != ZEND_FETCH_LIST_R
586
+ && opline -> opcode != ZEND_CASE
587
+ && opline -> opcode != ZEND_CASE_STRICT
588
+ && opline -> opcode != ZEND_SWITCH_LONG
589
+ && opline -> opcode != ZEND_SWITCH_STRING
590
+ && opline -> opcode != ZEND_MATCH
591
+ && opline -> opcode != ZEND_JMP_NULL
592
+ && (opline -> opcode != ZEND_FREE
593
+ || opline -> extended_value != ZEND_FREE_ON_RETURN );
594
+
595
+ Z_TRY_ADDREF_P (val );
596
+ if (!zend_optimizer_update_op1_const (op_array , opline , val )) {
597
+ zval_ptr_dtor (val );
598
+ return 0 ;
599
+ }
600
+ if (is_last ) {
601
+ break ;
631
602
}
632
603
}
633
604
opline ++ ;
0 commit comments