@@ -1490,14 +1490,32 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke
1490
1490
zend_error_noreturn (E_COMPILE_ERROR , "Access level to %s::$%s must be %s (as in class %s)%s" , ZSTR_VAL (ce -> name ), ZSTR_VAL (key ), zend_visibility_string (parent_info -> flags ), ZSTR_VAL (parent_info -> ce -> name ), (parent_info -> flags & ZEND_ACC_PUBLIC ) ? "" : " or weaker" );
1491
1491
}
1492
1492
if (!(child_info -> flags & ZEND_ACC_STATIC ) && !(parent_info -> flags & ZEND_ACC_VIRTUAL )) {
1493
+ /* If we added hooks to the child property, we use the child's slot for
1494
+ * storage to keep the parent slot set to IS_UNDEF. This automatically
1495
+ * picks the slow path in the JIT. */
1496
+ bool use_child_prop = !parent_info -> hooks && child_info -> hooks ;
1497
+
1498
+ if (use_child_prop && child_info -> offset == ZEND_VIRTUAL_PROPERTY_OFFSET ) {
1499
+ child_info -> offset = OBJ_PROP_TO_OFFSET (ce -> default_properties_count );
1500
+ ce -> default_properties_count ++ ;
1501
+ ce -> default_properties_table = perealloc (ce -> default_properties_table , sizeof (zval ) * ce -> default_properties_count , ce -> type == ZEND_INTERNAL_CLASS );
1502
+ zval * property_default_ptr = & ce -> default_properties_table [OBJ_PROP_TO_NUM (child_info -> offset )];
1503
+ ZVAL_UNDEF (property_default_ptr );
1504
+ Z_PROP_FLAG_P (property_default_ptr ) = IS_PROP_UNINIT ;
1505
+ }
1506
+
1493
1507
int parent_num = OBJ_PROP_TO_NUM (parent_info -> offset );
1494
1508
if (child_info -> offset != ZEND_VIRTUAL_PROPERTY_OFFSET ) {
1495
- int child_num = OBJ_PROP_TO_NUM (child_info -> offset );
1496
-
1497
1509
/* Don't keep default properties in GC (they may be freed by opcache) */
1498
1510
zval_ptr_dtor_nogc (& (ce -> default_properties_table [parent_num ]));
1499
- ce -> default_properties_table [parent_num ] = ce -> default_properties_table [child_num ];
1500
- ZVAL_UNDEF (& ce -> default_properties_table [child_num ]);
1511
+
1512
+ if (use_child_prop ) {
1513
+ ZVAL_UNDEF (& ce -> default_properties_table [parent_num ]);
1514
+ } else {
1515
+ int child_num = OBJ_PROP_TO_NUM (child_info -> offset );
1516
+ ce -> default_properties_table [parent_num ] = ce -> default_properties_table [child_num ];
1517
+ ZVAL_UNDEF (& ce -> default_properties_table [child_num ]);
1518
+ }
1501
1519
} else {
1502
1520
/* Default value was removed in child, remove it from parent too. */
1503
1521
if (ZEND_TYPE_IS_SET (child_info -> type )) {
@@ -1507,7 +1525,9 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke
1507
1525
}
1508
1526
}
1509
1527
1510
- child_info -> offset = parent_info -> offset ;
1528
+ if (!use_child_prop ) {
1529
+ child_info -> offset = parent_info -> offset ;
1530
+ }
1511
1531
child_info -> flags &= ~ZEND_ACC_VIRTUAL ;
1512
1532
}
1513
1533
@@ -1682,7 +1702,8 @@ void zend_build_properties_info_table(zend_class_entry *ce)
1682
1702
ZEND_HASH_MAP_FOREACH_PTR (& ce -> properties_info , prop ) {
1683
1703
if (prop -> ce == ce && (prop -> flags & ZEND_ACC_STATIC ) == 0
1684
1704
&& !(prop -> flags & ZEND_ACC_VIRTUAL )) {
1685
- table [OBJ_PROP_TO_NUM (prop -> offset )] = prop ;
1705
+ uint32_t prop_table_offset = OBJ_PROP_TO_NUM (!(prop -> prototype -> flags & ZEND_ACC_VIRTUAL ) ? prop -> prototype -> offset : prop -> offset );
1706
+ table [prop_table_offset ] = prop ;
1686
1707
}
1687
1708
} ZEND_HASH_FOREACH_END ();
1688
1709
}
@@ -1696,8 +1717,12 @@ ZEND_API void zend_verify_hooked_property(zend_class_entry *ce, zend_property_in
1696
1717
/* We specified a default value (otherwise offset would be -1), but the virtual flag wasn't
1697
1718
* removed during inheritance. */
1698
1719
if ((prop_info -> flags & ZEND_ACC_VIRTUAL ) && prop_info -> offset != ZEND_VIRTUAL_PROPERTY_OFFSET ) {
1699
- zend_error_noreturn (E_COMPILE_ERROR ,
1700
- "Cannot specify default value for virtual hooked property %s::$%s" , ZSTR_VAL (ce -> name ), ZSTR_VAL (prop_name ));
1720
+ if (Z_TYPE (ce -> default_properties_table [OBJ_PROP_TO_NUM (prop_info -> offset )]) == IS_UNDEF ) {
1721
+ prop_info -> offset = ZEND_VIRTUAL_PROPERTY_OFFSET ;
1722
+ } else {
1723
+ zend_error_noreturn (E_COMPILE_ERROR ,
1724
+ "Cannot specify default value for virtual hooked property %s::$%s" , ZSTR_VAL (ce -> name ), ZSTR_VAL (prop_name ));
1725
+ }
1701
1726
}
1702
1727
/* If the property turns backed during inheritance and no type and default value are set, we want
1703
1728
* the default value to be null. */
0 commit comments