@@ -40,9 +40,16 @@ static zend_arg_info zarginfo_class_UnitEnum_cases[sizeof(arginfo_class_UnitEnum
4040static zend_arg_info zarginfo_class_BackedEnum_from [sizeof (arginfo_class_BackedEnum_from )/sizeof (zend_internal_arg_info )];
4141static zend_arg_info zarginfo_class_BackedEnum_tryFrom [sizeof (arginfo_class_BackedEnum_tryFrom )/sizeof (zend_internal_arg_info )];
4242
43- zend_object * zend_enum_new (zval * result , zend_class_entry * ce , zend_string * case_name , zval * backing_value_zv )
43+ zend_object * zend_enum_new (zval * result , zend_class_entry * ce , int case_id , zend_string * case_name , zval * backing_value_zv )
4444{
45- zend_object * zobj = zend_objects_new (ce );
45+ zend_enum_obj * intern = zend_object_alloc (sizeof (* intern ), ce );
46+
47+ zend_object_std_init (& intern -> std , ce );
48+ object_properties_init (& intern -> std , ce );
49+
50+ intern -> case_id = case_id ;
51+
52+ zend_object * zobj = & intern -> std ;
4653 GC_ADD_FLAGS (zobj , GC_NOT_COLLECTABLE );
4754 ZVAL_OBJ (result , zobj );
4855
@@ -170,6 +177,7 @@ void zend_register_enum_ce(void)
170177 zend_ce_backed_enum -> interface_gets_implemented = zend_implement_backed_enum ;
171178
172179 memcpy (& zend_enum_object_handlers , & std_object_handlers , sizeof (zend_object_handlers ));
180+ zend_enum_object_handlers .offset = XtOffsetOf (zend_enum_obj , std );
173181 zend_enum_object_handlers .clone_obj = NULL ;
174182 zend_enum_object_handlers .compare = zend_objects_not_comparable ;
175183}
@@ -539,16 +547,18 @@ ZEND_API zend_class_entry *zend_register_internal_enum(
539547}
540548
541549static zend_ast_ref * create_enum_case_ast (
542- zend_string * class_name , zend_string * case_name , zval * value ) {
550+ zend_string * class_name , int case_id , zend_string * case_name ,
551+ zval * value ) {
543552 // TODO: Use custom node type for enum cases?
544- size_t size = sizeof (zend_ast_ref ) + zend_ast_size (3 )
545- + (value ? 3 : 2 ) * sizeof (zend_ast_zval );
553+ const size_t num_children = ZEND_AST_CONST_ENUM_INIT >> ZEND_AST_NUM_CHILDREN_SHIFT ;
554+ size_t size = sizeof (zend_ast_ref ) + zend_ast_size (num_children )
555+ + (value ? num_children : num_children - 1 ) * sizeof (zend_ast_zval );
546556 char * p = pemalloc (size , 1 );
547557 zend_ast_ref * ref = (zend_ast_ref * ) p ; p += sizeof (zend_ast_ref );
548558 GC_SET_REFCOUNT (ref , 1 );
549559 GC_TYPE_INFO (ref ) = GC_CONSTANT_AST | GC_PERSISTENT | GC_IMMUTABLE ;
550560
551- zend_ast * ast = (zend_ast * ) p ; p += zend_ast_size (3 );
561+ zend_ast * ast = (zend_ast * ) p ; p += zend_ast_size (num_children );
552562 ast -> kind = ZEND_AST_CONST_ENUM_INIT ;
553563 ast -> attr = 0 ;
554564 ast -> lineno = 0 ;
@@ -563,24 +573,47 @@ static zend_ast_ref *create_enum_case_ast(
563573 ast -> child [1 ] = (zend_ast * ) p ; p += sizeof (zend_ast_zval );
564574 ast -> child [1 ]-> kind = ZEND_AST_ZVAL ;
565575 ast -> child [1 ]-> attr = 0 ;
566- ZEND_ASSERT (ZSTR_IS_INTERNED (case_name ));
567- ZVAL_STR (zend_ast_get_zval (ast -> child [1 ]), case_name );
576+ ZVAL_LONG (zend_ast_get_zval (ast -> child [1 ]), case_id );
568577 Z_LINENO_P (zend_ast_get_zval (ast -> child [1 ])) = 0 ;
569578
579+ ast -> child [2 ] = (zend_ast * ) p ; p += sizeof (zend_ast_zval );
580+ ast -> child [2 ]-> kind = ZEND_AST_ZVAL ;
581+ ast -> child [2 ]-> attr = 0 ;
582+ ZEND_ASSERT (ZSTR_IS_INTERNED (case_name ));
583+ ZVAL_STR (zend_ast_get_zval (ast -> child [2 ]), case_name );
584+ Z_LINENO_P (zend_ast_get_zval (ast -> child [2 ])) = 0 ;
585+
570586 if (value ) {
571- ast -> child [2 ] = (zend_ast * ) p ; p += sizeof (zend_ast_zval );
572- ast -> child [2 ]-> kind = ZEND_AST_ZVAL ;
573- ast -> child [2 ]-> attr = 0 ;
587+ ast -> child [3 ] = (zend_ast * ) p ; p += sizeof (zend_ast_zval );
588+ ast -> child [3 ]-> kind = ZEND_AST_ZVAL ;
589+ ast -> child [3 ]-> attr = 0 ;
574590 ZEND_ASSERT (!Z_REFCOUNTED_P (value ));
575- ZVAL_COPY_VALUE (zend_ast_get_zval (ast -> child [2 ]), value );
576- Z_LINENO_P (zend_ast_get_zval (ast -> child [2 ])) = 0 ;
591+ ZVAL_COPY_VALUE (zend_ast_get_zval (ast -> child [3 ]), value );
592+ Z_LINENO_P (zend_ast_get_zval (ast -> child [3 ])) = 0 ;
577593 } else {
578- ast -> child [2 ] = NULL ;
594+ ast -> child [3 ] = NULL ;
579595 }
580596
581597 return ref ;
582598}
583599
600+ int zend_enum_next_case_id (zend_class_entry * enum_class )
601+ {
602+ ZEND_HASH_REVERSE_FOREACH_VAL (& enum_class -> constants_table , zval * zv ) {
603+ zend_class_constant * c = Z_PTR_P (zv );
604+ if (!(ZEND_CLASS_CONST_FLAGS (c ) & ZEND_CLASS_CONST_IS_CASE )) {
605+ continue ;
606+ }
607+ ZEND_ASSERT (Z_TYPE (c -> value ) == IS_CONSTANT_AST );
608+ zend_ast * ast = Z_ASTVAL (c -> value );
609+
610+ ZEND_ASSERT (ast -> kind == ZEND_AST_CONST_ENUM_INIT );
611+ return Z_LVAL_P (zend_ast_get_zval (ast -> child [1 ])) + 1 ;
612+ } ZEND_HASH_FOREACH_END ();
613+
614+ return 1 ;
615+ }
616+
584617ZEND_API void zend_enum_add_case (zend_class_entry * ce , zend_string * case_name , zval * value )
585618{
586619 if (value ) {
@@ -602,9 +635,11 @@ ZEND_API void zend_enum_add_case(zend_class_entry *ce, zend_string *case_name, z
602635 ZEND_ASSERT (ce -> enum_backing_type == IS_UNDEF );
603636 }
604637
638+ int case_id = zend_enum_next_case_id (ce );
639+
605640 zval ast_zv ;
606641 Z_TYPE_INFO (ast_zv ) = IS_CONSTANT_AST ;
607- Z_AST (ast_zv ) = create_enum_case_ast (ce -> name , case_name , value );
642+ Z_AST (ast_zv ) = create_enum_case_ast (ce -> name , case_id , case_name , value );
608643 zend_class_constant * c = zend_declare_class_constant_ex (
609644 ce , case_name , & ast_zv , ZEND_ACC_PUBLIC , NULL );
610645 ZEND_CLASS_CONST_FLAGS (c ) |= ZEND_CLASS_CONST_IS_CASE ;
0 commit comments