@@ -94,11 +94,28 @@ static zend_string *create_str_cache_key(zval *literal, uint8_t num_related)
9494 Z_STRVAL_P (literal ), Z_STRLEN_P (literal ),
9595 Z_STRVAL_P (literal + 1 ), Z_STRLEN_P (literal + 1 ));
9696 } else if (num_related == 3 ) {
97- ZEND_ASSERT (Z_TYPE_P (literal + 1 ) == IS_STRING && Z_TYPE_P (literal + 2 ) == IS_STRING );
98- key = zend_string_concat3 (
99- Z_STRVAL_P (literal ), Z_STRLEN_P (literal ),
100- Z_STRVAL_P (literal + 1 ), Z_STRLEN_P (literal + 1 ),
101- Z_STRVAL_P (literal + 2 ), Z_STRLEN_P (literal + 2 ));
97+ if (Z_TYPE_P (literal + 2 ) == IS_PTR || Z_TYPE_P (literal + 2 ) == IS_LONG ) {
98+ /* Generic args literal (IS_PTR or IS_LONG pointer) — include pointer value
99+ * in key to prevent merging across different generic instantiations */
100+ char ptr_buf [32 ];
101+ uintptr_t ptr_val = (Z_TYPE_P (literal + 2 ) == IS_PTR )
102+ ? (uintptr_t )Z_PTR_P (literal + 2 )
103+ : (uintptr_t )Z_LVAL_P (literal + 2 );
104+ int ptr_len = snprintf (ptr_buf , sizeof (ptr_buf ), "G%lx" , (unsigned long )ptr_val );
105+ ZEND_ASSERT (Z_TYPE_P (literal + 1 ) == IS_STRING );
106+ size_t len = Z_STRLEN_P (literal ) + Z_STRLEN_P (literal + 1 ) + ptr_len ;
107+ key = zend_string_alloc (len , 0 );
108+ memcpy (ZSTR_VAL (key ), Z_STRVAL_P (literal ), Z_STRLEN_P (literal ));
109+ memcpy (ZSTR_VAL (key ) + Z_STRLEN_P (literal ), Z_STRVAL_P (literal + 1 ), Z_STRLEN_P (literal + 1 ));
110+ memcpy (ZSTR_VAL (key ) + Z_STRLEN_P (literal ) + Z_STRLEN_P (literal + 1 ), ptr_buf , ptr_len );
111+ ZSTR_VAL (key )[len ] = '\0' ;
112+ } else {
113+ ZEND_ASSERT (Z_TYPE_P (literal + 1 ) == IS_STRING && Z_TYPE_P (literal + 2 ) == IS_STRING );
114+ key = zend_string_concat3 (
115+ Z_STRVAL_P (literal ), Z_STRLEN_P (literal ),
116+ Z_STRVAL_P (literal + 1 ), Z_STRLEN_P (literal + 1 ),
117+ Z_STRVAL_P (literal + 2 ), Z_STRLEN_P (literal + 2 ));
118+ }
102119 } else {
103120 ZEND_ASSERT (0 && "Currently not needed" );
104121 }
@@ -151,7 +168,8 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
151168 break ;
152169 case ZEND_INIT_STATIC_METHOD_CALL :
153170 if (opline -> op1_type == IS_CONST ) {
154- LITERAL_INFO (opline -> op1 .constant , 2 );
171+ LITERAL_INFO (opline -> op1 .constant ,
172+ (opline -> result .num & 0x80000000 ) ? 3 : 2 );
155173 }
156174 if (opline -> op2_type == IS_CONST ) {
157175 LITERAL_INFO (opline -> op2 .constant , 2 );
@@ -201,14 +219,20 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
201219 }
202220 break ;
203221 case ZEND_FETCH_CLASS :
204- case ZEND_INSTANCEOF :
205222 if (opline -> op2_type == IS_CONST ) {
206223 LITERAL_INFO (opline -> op2 .constant , 2 );
207224 }
208225 break ;
226+ case ZEND_INSTANCEOF :
227+ if (opline -> op2_type == IS_CONST ) {
228+ LITERAL_INFO (opline -> op2 .constant ,
229+ (opline -> extended_value & ZEND_INSTANCEOF_GENERIC_FLAG ) ? 3 : 2 );
230+ }
231+ break ;
209232 case ZEND_NEW :
210233 if (opline -> op1_type == IS_CONST ) {
211- LITERAL_INFO (opline -> op1 .constant , 2 );
234+ LITERAL_INFO (opline -> op1 .constant ,
235+ (opline -> op2 .num & 0x80000000 ) ? 3 : 2 );
212236 }
213237 break ;
214238 case ZEND_DECLARE_CLASS :
@@ -569,30 +593,32 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
569593 }
570594 }
571595 break ;
572- case ZEND_INIT_STATIC_METHOD_CALL :
596+ case ZEND_INIT_STATIC_METHOD_CALL : {
597+ uint32_t generic_flag = opline -> result .num & 0x80000000 ;
573598 if (opline -> op2_type == IS_CONST ) {
574599 // op2 static method
575600 if (opline -> op1_type == IS_CONST ) {
576601 opline -> result .num = add_static_slot (& hash , op_array ,
577602 opline -> op1 .constant ,
578603 opline -> op2 .constant ,
579604 LITERAL_STATIC_METHOD ,
580- & cache_size );
605+ & cache_size ) | generic_flag ;
581606 } else {
582- opline -> result .num = cache_size ;
607+ opline -> result .num = cache_size | generic_flag ;
583608 cache_size += 2 * sizeof (void * );
584609 }
585610 } else if (opline -> op1_type == IS_CONST ) {
586611 // op1 class
587612 if (class_slot [opline -> op1 .constant ] >= 0 ) {
588- opline -> result .num = class_slot [opline -> op1 .constant ];
613+ opline -> result .num = class_slot [opline -> op1 .constant ] | generic_flag ;
589614 } else {
590- opline -> result .num = cache_size ;
615+ opline -> result .num = cache_size | generic_flag ;
591616 cache_size += sizeof (void * );
592- class_slot [opline -> op1 .constant ] = opline -> result . num ;
617+ class_slot [opline -> op1 .constant ] = cache_size - sizeof ( void * ) ;
593618 }
594619 }
595620 break ;
621+ }
596622 case ZEND_DEFINED :
597623 // op1 const
598624 if (const_slot [opline -> op1 .constant ] >= 0 ) {
@@ -666,7 +692,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
666692 }
667693 break ;
668694 case ZEND_FETCH_CLASS :
669- case ZEND_INSTANCEOF :
670695 if (opline -> op2_type == IS_CONST ) {
671696 // op2 class
672697 if (class_slot [opline -> op2 .constant ] >= 0 ) {
@@ -678,15 +703,29 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
678703 }
679704 }
680705 break ;
706+ case ZEND_INSTANCEOF :
707+ if (opline -> op2_type == IS_CONST ) {
708+ // op2 class — preserve generic flag
709+ uint32_t generic_flag = opline -> extended_value & ZEND_INSTANCEOF_GENERIC_FLAG ;
710+ if (class_slot [opline -> op2 .constant ] >= 0 ) {
711+ opline -> extended_value = class_slot [opline -> op2 .constant ] | generic_flag ;
712+ } else {
713+ opline -> extended_value = cache_size | generic_flag ;
714+ cache_size += sizeof (void * );
715+ class_slot [opline -> op2 .constant ] = cache_size - sizeof (void * );
716+ }
717+ }
718+ break ;
681719 case ZEND_NEW :
682720 if (opline -> op1_type == IS_CONST ) {
683- // op1 class
721+ // op1 class — preserve generic flag
722+ uint32_t generic_flag = opline -> op2 .num & 0x80000000 ;
684723 if (class_slot [opline -> op1 .constant ] >= 0 ) {
685- opline -> op2 .num = class_slot [opline -> op1 .constant ];
724+ opline -> op2 .num = class_slot [opline -> op1 .constant ] | generic_flag ;
686725 } else {
687- opline -> op2 .num = cache_size ;
726+ opline -> op2 .num = cache_size | generic_flag ;
688727 cache_size += sizeof (void * );
689- class_slot [opline -> op1 .constant ] = opline -> op2 . num ;
728+ class_slot [opline -> op1 .constant ] = cache_size - sizeof ( void * ) ;
690729 }
691730 }
692731 break ;
0 commit comments