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