@@ -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 }
@@ -150,7 +167,8 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
150167 break ;
151168 case ZEND_INIT_STATIC_METHOD_CALL :
152169 if (opline -> op1_type == IS_CONST ) {
153- LITERAL_INFO (opline -> op1 .constant , 2 );
170+ LITERAL_INFO (opline -> op1 .constant ,
171+ (opline -> result .num & 0x80000000 ) ? 3 : 2 );
154172 }
155173 if (opline -> op2_type == IS_CONST ) {
156174 LITERAL_INFO (opline -> op2 .constant , 2 );
@@ -200,14 +218,20 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
200218 }
201219 break ;
202220 case ZEND_FETCH_CLASS :
203- case ZEND_INSTANCEOF :
204221 if (opline -> op2_type == IS_CONST ) {
205222 LITERAL_INFO (opline -> op2 .constant , 2 );
206223 }
207224 break ;
225+ case ZEND_INSTANCEOF :
226+ if (opline -> op2_type == IS_CONST ) {
227+ LITERAL_INFO (opline -> op2 .constant ,
228+ (opline -> extended_value & ZEND_INSTANCEOF_GENERIC_FLAG ) ? 3 : 2 );
229+ }
230+ break ;
208231 case ZEND_NEW :
209232 if (opline -> op1_type == IS_CONST ) {
210- LITERAL_INFO (opline -> op1 .constant , 2 );
233+ LITERAL_INFO (opline -> op1 .constant ,
234+ (opline -> op2 .num & 0x80000000 ) ? 3 : 2 );
211235 }
212236 break ;
213237 case ZEND_DECLARE_CLASS :
@@ -568,30 +592,32 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
568592 }
569593 }
570594 break ;
571- case ZEND_INIT_STATIC_METHOD_CALL :
595+ case ZEND_INIT_STATIC_METHOD_CALL : {
596+ uint32_t generic_flag = opline -> result .num & 0x80000000 ;
572597 if (opline -> op2_type == IS_CONST ) {
573598 // op2 static method
574599 if (opline -> op1_type == IS_CONST ) {
575600 opline -> result .num = add_static_slot (& hash , op_array ,
576601 opline -> op1 .constant ,
577602 opline -> op2 .constant ,
578603 LITERAL_STATIC_METHOD ,
579- & cache_size );
604+ & cache_size ) | generic_flag ;
580605 } else {
581- opline -> result .num = cache_size ;
606+ opline -> result .num = cache_size | generic_flag ;
582607 cache_size += 2 * sizeof (void * );
583608 }
584609 } else if (opline -> op1_type == IS_CONST ) {
585610 // op1 class
586611 if (class_slot [opline -> op1 .constant ] >= 0 ) {
587- opline -> result .num = class_slot [opline -> op1 .constant ];
612+ opline -> result .num = class_slot [opline -> op1 .constant ] | generic_flag ;
588613 } else {
589- opline -> result .num = cache_size ;
614+ opline -> result .num = cache_size | generic_flag ;
590615 cache_size += sizeof (void * );
591- class_slot [opline -> op1 .constant ] = opline -> result . num ;
616+ class_slot [opline -> op1 .constant ] = cache_size - sizeof ( void * ) ;
592617 }
593618 }
594619 break ;
620+ }
595621 case ZEND_DEFINED :
596622 // op1 const
597623 if (const_slot [opline -> op1 .constant ] >= 0 ) {
@@ -665,7 +691,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
665691 }
666692 break ;
667693 case ZEND_FETCH_CLASS :
668- case ZEND_INSTANCEOF :
669694 if (opline -> op2_type == IS_CONST ) {
670695 // op2 class
671696 if (class_slot [opline -> op2 .constant ] >= 0 ) {
@@ -677,15 +702,29 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
677702 }
678703 }
679704 break ;
705+ case ZEND_INSTANCEOF :
706+ if (opline -> op2_type == IS_CONST ) {
707+ // op2 class — preserve generic flag
708+ uint32_t generic_flag = opline -> extended_value & ZEND_INSTANCEOF_GENERIC_FLAG ;
709+ if (class_slot [opline -> op2 .constant ] >= 0 ) {
710+ opline -> extended_value = class_slot [opline -> op2 .constant ] | generic_flag ;
711+ } else {
712+ opline -> extended_value = cache_size | generic_flag ;
713+ cache_size += sizeof (void * );
714+ class_slot [opline -> op2 .constant ] = cache_size - sizeof (void * );
715+ }
716+ }
717+ break ;
680718 case ZEND_NEW :
681719 if (opline -> op1_type == IS_CONST ) {
682- // op1 class
720+ // op1 class — preserve generic flag
721+ uint32_t generic_flag = opline -> op2 .num & 0x80000000 ;
683722 if (class_slot [opline -> op1 .constant ] >= 0 ) {
684- opline -> op2 .num = class_slot [opline -> op1 .constant ];
723+ opline -> op2 .num = class_slot [opline -> op1 .constant ] | generic_flag ;
685724 } else {
686- opline -> op2 .num = cache_size ;
725+ opline -> op2 .num = cache_size | generic_flag ;
687726 cache_size += sizeof (void * );
688- class_slot [opline -> op1 .constant ] = opline -> op2 . num ;
727+ class_slot [opline -> op1 .constant ] = cache_size - sizeof ( void * ) ;
689728 }
690729 }
691730 break ;
0 commit comments