@@ -1213,39 +1213,147 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */
12131213}
12141214/* }}} */
12151215
1216+ static zend_class_mutable_data * zend_allocate_mutable_data (zend_class_entry * class_type ) /* {{{ */
1217+ {
1218+ zend_class_mutable_data * mutable_data ;
1219+
1220+ ZEND_ASSERT (class_type -> ce_flags & ZEND_ACC_IMMUTABLE );
1221+ ZEND_ASSERT (ZEND_MAP_PTR (class_type -> mutable_data ) != NULL );
1222+ ZEND_ASSERT (ZEND_MAP_PTR_GET_IMM (class_type -> mutable_data ) == NULL );
1223+
1224+ mutable_data = zend_arena_alloc (& CG (arena ), sizeof (zend_class_mutable_data ));
1225+ memset (mutable_data , 0 , sizeof (zend_class_mutable_data ));
1226+ mutable_data -> ce_flags = class_type -> ce_flags ;
1227+ ZEND_MAP_PTR_SET_IMM (class_type -> mutable_data , mutable_data );
1228+
1229+ return mutable_data ;
1230+ }
1231+ /* }}} */
1232+
1233+ ZEND_API HashTable * zend_separate_class_constants_table (zend_class_entry * class_type ) /* {{{ */
1234+ {
1235+ zend_class_mutable_data * mutable_data ;
1236+ HashTable * constants_table ;
1237+ zend_string * key ;
1238+ zend_class_constant * new_c , * c ;
1239+
1240+ constants_table = zend_arena_alloc (& CG (arena ), sizeof (HashTable ));
1241+ zend_hash_init (constants_table , zend_hash_num_elements (& class_type -> constants_table ), NULL , NULL , 0 );
1242+ zend_hash_extend (constants_table , zend_hash_num_elements (& class_type -> constants_table ), 0 );
1243+
1244+ ZEND_HASH_FOREACH_STR_KEY_PTR (& class_type -> constants_table , key , c ) {
1245+ if (Z_TYPE (c -> value ) == IS_CONSTANT_AST ) {
1246+ new_c = zend_arena_alloc (& CG (arena ), sizeof (zend_class_constant ));
1247+ memcpy (new_c , c , sizeof (zend_class_constant ));
1248+ c = new_c ;
1249+ }
1250+ _zend_hash_append_ptr (constants_table , key , c );
1251+ } ZEND_HASH_FOREACH_END ();
1252+
1253+ ZEND_ASSERT (class_type -> ce_flags & ZEND_ACC_IMMUTABLE );
1254+ ZEND_ASSERT (ZEND_MAP_PTR (class_type -> mutable_data ) != NULL );
1255+
1256+ mutable_data = ZEND_MAP_PTR_GET_IMM (class_type -> mutable_data );
1257+ if (!mutable_data ) {
1258+ mutable_data = zend_allocate_mutable_data (class_type );
1259+ }
1260+
1261+ mutable_data -> constants_table = constants_table ;
1262+
1263+ return constants_table ;
1264+ }
1265+
12161266ZEND_API zend_result zend_update_class_constants (zend_class_entry * class_type ) /* {{{ */
12171267{
1218- if (!(class_type -> ce_flags & ZEND_ACC_CONSTANTS_UPDATED )) {
1219- zend_class_constant * c ;
1220- zval * val ;
1221- zend_property_info * prop_info ;
1268+ zend_class_mutable_data * mutable_data = NULL ;
1269+ zval * default_properties_table = NULL ;
1270+ zval * static_members_table = NULL ;
1271+ zend_class_constant * c ;
1272+ zval * val ;
1273+ zend_property_info * prop_info ;
1274+ uint32_t ce_flags ;
12221275
1223- if (class_type -> parent ) {
1224- if (UNEXPECTED (zend_update_class_constants (class_type -> parent ) != SUCCESS )) {
1225- return FAILURE ;
1276+ ce_flags = class_type -> ce_flags ;
1277+
1278+ if (ce_flags & ZEND_ACC_CONSTANTS_UPDATED ) {
1279+ return SUCCESS ;
1280+ }
1281+
1282+ if (ce_flags & ZEND_ACC_IMMUTABLE ) {
1283+ mutable_data = ZEND_MAP_PTR_GET_IMM (class_type -> mutable_data );
1284+ if (mutable_data ) {
1285+ ce_flags = mutable_data -> ce_flags ;
1286+ if (ce_flags & ZEND_ACC_CONSTANTS_UPDATED ) {
1287+ return SUCCESS ;
12261288 }
1289+ } else {
1290+ mutable_data = zend_allocate_mutable_data (class_type );
12271291 }
1292+ }
12281293
1229- ZEND_HASH_FOREACH_PTR (& class_type -> constants_table , c ) {
1230- val = & c -> value ;
1231- if (Z_TYPE_P (val ) == IS_CONSTANT_AST ) {
1294+ if (class_type -> parent ) {
1295+ if (UNEXPECTED (zend_update_class_constants (class_type -> parent ) != SUCCESS )) {
1296+ return FAILURE ;
1297+ }
1298+ }
1299+
1300+ if (ce_flags & ZEND_ACC_HAS_AST_CONSTANTS ) {
1301+ HashTable * constants_table ;
1302+
1303+ if (ce_flags & ZEND_ACC_IMMUTABLE ) {
1304+ constants_table = mutable_data -> constants_table ;
1305+ if (!constants_table ) {
1306+ constants_table = zend_separate_class_constants_table (class_type );
1307+ }
1308+ } else {
1309+ constants_table = & class_type -> constants_table ;
1310+ }
1311+ ZEND_HASH_FOREACH_PTR (constants_table , c ) {
1312+ if (Z_TYPE (c -> value ) == IS_CONSTANT_AST ) {
1313+ val = & c -> value ;
12321314 if (UNEXPECTED (zval_update_constant_ex (val , c -> ce ) != SUCCESS )) {
12331315 return FAILURE ;
12341316 }
12351317 }
12361318 } ZEND_HASH_FOREACH_END ();
1319+ }
12371320
1238- if (class_type -> default_static_members_count && !CE_STATIC_MEMBERS (class_type )) {
1239- if (class_type -> type == ZEND_INTERNAL_CLASS || (class_type -> ce_flags & (ZEND_ACC_IMMUTABLE |ZEND_ACC_PRELOADED ))) {
1321+ if (class_type -> default_static_members_count ) {
1322+ static_members_table = CE_STATIC_MEMBERS (class_type );
1323+ if (!static_members_table ) {
1324+ if (class_type -> type == ZEND_INTERNAL_CLASS || (ce_flags & (ZEND_ACC_IMMUTABLE |ZEND_ACC_PRELOADED ))) {
12401325 zend_class_init_statics (class_type );
1326+ static_members_table = CE_STATIC_MEMBERS (class_type );
12411327 }
12421328 }
1329+ }
1330+
1331+ default_properties_table = class_type -> default_properties_table ;
1332+ if ((ce_flags & ZEND_ACC_IMMUTABLE )
1333+ && (ce_flags & ZEND_ACC_HAS_AST_PROPERTIES )) {
1334+ zval * src , * dst , * end ;
1335+
1336+ default_properties_table = mutable_data -> default_properties_table ;
1337+ if (!default_properties_table ) {
1338+ default_properties_table = zend_arena_alloc (& CG (arena ), sizeof (zval ) * class_type -> default_properties_count );
1339+ src = class_type -> default_properties_table ;
1340+ dst = default_properties_table ;
1341+ end = dst + class_type -> default_properties_count ;
1342+ do {
1343+ ZVAL_COPY_VALUE_PROP (dst , src );
1344+ src ++ ;
1345+ dst ++ ;
1346+ } while (dst != end );
1347+ mutable_data -> default_properties_table = default_properties_table ;
1348+ }
1349+ }
12431350
1351+ if (ce_flags & (ZEND_ACC_HAS_AST_PROPERTIES |ZEND_ACC_HAS_AST_STATICS )) {
12441352 ZEND_HASH_FOREACH_PTR (& class_type -> properties_info , prop_info ) {
12451353 if (prop_info -> flags & ZEND_ACC_STATIC ) {
1246- val = CE_STATIC_MEMBERS ( class_type ) + prop_info -> offset ;
1354+ val = static_members_table + prop_info -> offset ;
12471355 } else {
1248- val = (zval * )((char * )class_type -> default_properties_table + prop_info -> offset - OBJ_PROP_TO_OFFSET (0 ));
1356+ val = (zval * )((char * )default_properties_table + prop_info -> offset - OBJ_PROP_TO_OFFSET (0 ));
12491357 }
12501358 if (Z_TYPE_P (val ) == IS_CONSTANT_AST ) {
12511359 if (ZEND_TYPE_IS_SET (prop_info -> type )) {
@@ -1268,8 +1376,21 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
12681376 }
12691377 }
12701378 } ZEND_HASH_FOREACH_END ();
1379+ }
12711380
1272- class_type -> ce_flags |= ZEND_ACC_CONSTANTS_UPDATED ;
1381+ ce_flags |= ZEND_ACC_CONSTANTS_UPDATED ;
1382+ ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS ;
1383+ ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES ;
1384+ if (class_type -> ce_flags & ZEND_ACC_IMMUTABLE ) {
1385+ ce_flags &= ~ZEND_ACC_HAS_AST_STATICS ;
1386+ if (mutable_data ) {
1387+ mutable_data -> ce_flags = ce_flags ;
1388+ }
1389+ } else {
1390+ if (!(ce_flags & ZEND_ACC_PRELOADED )) {
1391+ ce_flags &= ~ZEND_ACC_HAS_AST_STATICS ;
1392+ }
1393+ class_type -> ce_flags = ce_flags ;
12731394 }
12741395
12751396 return SUCCESS ;
@@ -1279,7 +1400,7 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
12791400static zend_always_inline void _object_properties_init (zend_object * object , zend_class_entry * class_type ) /* {{{ */
12801401{
12811402 if (class_type -> default_properties_count ) {
1282- zval * src = class_type -> default_properties_table ;
1403+ zval * src = CE_DEFAULT_PROPERTIES_TABLE ( class_type ) ;
12831404 zval * dst = object -> properties_table ;
12841405 zval * end = src + class_type -> default_properties_count ;
12851406
@@ -3809,6 +3930,11 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
38093930 property_info = zend_arena_alloc (& CG (arena ), sizeof (zend_property_info ));
38103931 if (Z_TYPE_P (property ) == IS_CONSTANT_AST ) {
38113932 ce -> ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED ;
3933+ if (access_type & ZEND_ACC_STATIC ) {
3934+ ce -> ce_flags |= ZEND_ACC_HAS_AST_STATICS ;
3935+ } else {
3936+ ce -> ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES ;
3937+ }
38123938 }
38133939 }
38143940
@@ -4124,6 +4250,7 @@ ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *c
41244250 c -> ce = ce ;
41254251 if (Z_TYPE_P (value ) == IS_CONSTANT_AST ) {
41264252 ce -> ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED ;
4253+ ce -> ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS ;
41274254 }
41284255
41294256 if (!zend_hash_add_ptr (& ce -> constants_table , name , c )) {
0 commit comments