@@ -713,6 +713,116 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) {
713713#define Z_TYPE_FLAGS_SHIFT 8
714714#define Z_TYPE_INFO_EXTRA_SHIFT 16
715715
716+ /* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */
717+ #define GC_NOT_COLLECTABLE (1<<4)
718+ #define GC_PROTECTED (1<<5) /* used for recursion detection */
719+ #define GC_IMMUTABLE (1<<6) /* can't be changed in place */
720+ #define GC_PERSISTENT (1<<7) /* allocated using malloc */
721+ #define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */
722+
723+ #define GC_TYPE_MASK 0x0000000f
724+ #define GC_FLAGS_MASK 0x000003f0
725+ #define GC_INFO_MASK 0xfffffc00
726+ #define GC_FLAGS_SHIFT 0
727+ #define GC_INFO_SHIFT 10
728+
729+ static zend_always_inline uint8_t zval_gc_type (uint32_t gc_type_info ) {
730+ return (gc_type_info & GC_TYPE_MASK );
731+ }
732+
733+ static zend_always_inline uint32_t zval_gc_flags (uint32_t gc_type_info ) {
734+ return (gc_type_info >> GC_FLAGS_SHIFT ) & (GC_FLAGS_MASK >> GC_FLAGS_SHIFT );
735+ }
736+
737+ static zend_always_inline uint32_t zval_gc_info (uint32_t gc_type_info ) {
738+ return (gc_type_info >> GC_INFO_SHIFT );
739+ }
740+
741+ #define GC_TYPE_INFO (p ) (p)->gc.u.type_info
742+ #define GC_TYPE (p ) zval_gc_type(GC_TYPE_INFO(p))
743+ #define GC_FLAGS (p ) zval_gc_flags(GC_TYPE_INFO(p))
744+ #define GC_INFO (p ) zval_gc_info(GC_TYPE_INFO(p))
745+
746+ #define GC_ADD_FLAGS (p , flags ) do { \
747+ GC_TYPE_INFO(p) |= (flags) << GC_FLAGS_SHIFT; \
748+ } while (0)
749+ #define GC_DEL_FLAGS (p , flags ) do { \
750+ GC_TYPE_INFO(p) &= ~((flags) << GC_FLAGS_SHIFT); \
751+ } while (0)
752+
753+ #ifndef ZEND_RC_DEBUG
754+ # define ZEND_RC_DEBUG 0
755+ #endif
756+
757+ #if ZEND_RC_DEBUG
758+ extern ZEND_API bool zend_rc_debug ;
759+ /* The GC_PERSISTENT flag is reused for IS_OBJ_WEAKLY_REFERENCED on objects.
760+ * Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */
761+ # define ZEND_RC_MOD_CHECK (p ) do { \
762+ if (zend_rc_debug) { \
763+ uint8_t type = zval_gc_type((p)->u.type_info); \
764+ if (type != IS_OBJECT && type != IS_NULL) { \
765+ ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \
766+ ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \
767+ } \
768+ } \
769+ } while (0)
770+ # define GC_MAKE_PERSISTENT_LOCAL (p ) do { \
771+ GC_ADD_FLAGS(p, GC_PERSISTENT_LOCAL); \
772+ } while (0)
773+ #else
774+ # define ZEND_RC_MOD_CHECK (p ) \
775+ do { } while (0)
776+ # define GC_MAKE_PERSISTENT_LOCAL (p ) \
777+ do { } while (0)
778+ #endif
779+
780+ static zend_always_inline uint32_t zend_gc_refcount (const zend_refcounted_h * p ) {
781+ return p -> refcount ;
782+ }
783+
784+ static zend_always_inline uint32_t zend_gc_set_refcount (zend_refcounted_h * p , uint32_t rc ) {
785+ p -> refcount = rc ;
786+ return p -> refcount ;
787+ }
788+
789+ static zend_always_inline uint32_t zend_gc_addref (zend_refcounted_h * p ) {
790+ ZEND_RC_MOD_CHECK (p );
791+ return ++ (p -> refcount );
792+ }
793+
794+ static zend_always_inline void zend_gc_try_addref (zend_refcounted_h * p ) {
795+ if (!(p -> u .type_info & GC_IMMUTABLE )) {
796+ ZEND_RC_MOD_CHECK (p );
797+ ++ p -> refcount ;
798+ }
799+ }
800+
801+ static zend_always_inline void zend_gc_try_delref (zend_refcounted_h * p ) {
802+ if (!(p -> u .type_info & GC_IMMUTABLE )) {
803+ ZEND_RC_MOD_CHECK (p );
804+ -- p -> refcount ;
805+ }
806+ }
807+
808+ static zend_always_inline uint32_t zend_gc_delref (zend_refcounted_h * p ) {
809+ ZEND_ASSERT (p -> refcount > 0 );
810+ ZEND_RC_MOD_CHECK (p );
811+ return -- (p -> refcount );
812+ }
813+
814+ static zend_always_inline uint32_t zend_gc_addref_ex (zend_refcounted_h * p , uint32_t rc ) {
815+ ZEND_RC_MOD_CHECK (p );
816+ p -> refcount += rc ;
817+ return p -> refcount ;
818+ }
819+
820+ static zend_always_inline uint32_t zend_gc_delref_ex (zend_refcounted_h * p , uint32_t rc ) {
821+ ZEND_RC_MOD_CHECK (p );
822+ p -> refcount -= rc ;
823+ return p -> refcount ;
824+ }
825+
716826#define GC_REFCOUNT (p ) zend_gc_refcount(&(p)->gc)
717827#define GC_SET_REFCOUNT (p , rc ) zend_gc_set_refcount(&(p)->gc, rc)
718828#define GC_ADDREF (p ) zend_gc_addref(&(p)->gc)
@@ -754,36 +864,6 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) {
754864 } \
755865 } while (0)
756866
757- #define GC_TYPE_MASK 0x0000000f
758- #define GC_FLAGS_MASK 0x000003f0
759- #define GC_INFO_MASK 0xfffffc00
760- #define GC_FLAGS_SHIFT 0
761- #define GC_INFO_SHIFT 10
762-
763- static zend_always_inline uint8_t zval_gc_type (uint32_t gc_type_info ) {
764- return (gc_type_info & GC_TYPE_MASK );
765- }
766-
767- static zend_always_inline uint32_t zval_gc_flags (uint32_t gc_type_info ) {
768- return (gc_type_info >> GC_FLAGS_SHIFT ) & (GC_FLAGS_MASK >> GC_FLAGS_SHIFT );
769- }
770-
771- static zend_always_inline uint32_t zval_gc_info (uint32_t gc_type_info ) {
772- return (gc_type_info >> GC_INFO_SHIFT );
773- }
774-
775- #define GC_TYPE_INFO (p ) (p)->gc.u.type_info
776- #define GC_TYPE (p ) zval_gc_type(GC_TYPE_INFO(p))
777- #define GC_FLAGS (p ) zval_gc_flags(GC_TYPE_INFO(p))
778- #define GC_INFO (p ) zval_gc_info(GC_TYPE_INFO(p))
779-
780- #define GC_ADD_FLAGS (p , flags ) do { \
781- GC_TYPE_INFO(p) |= (flags) << GC_FLAGS_SHIFT; \
782- } while (0)
783- #define GC_DEL_FLAGS (p , flags ) do { \
784- GC_TYPE_INFO(p) &= ~((flags) << GC_FLAGS_SHIFT); \
785- } while (0)
786-
787867#define Z_GC_TYPE (zval ) GC_TYPE(Z_COUNTED(zval))
788868#define Z_GC_TYPE_P (zval_p ) Z_GC_TYPE(*(zval_p))
789869
@@ -795,13 +875,6 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) {
795875#define Z_GC_TYPE_INFO (zval ) GC_TYPE_INFO(Z_COUNTED(zval))
796876#define Z_GC_TYPE_INFO_P (zval_p ) Z_GC_TYPE_INFO(*(zval_p))
797877
798- /* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */
799- #define GC_NOT_COLLECTABLE (1<<4)
800- #define GC_PROTECTED (1<<5) /* used for recursion detection */
801- #define GC_IMMUTABLE (1<<6) /* can't be changed in place */
802- #define GC_PERSISTENT (1<<7) /* allocated using malloc */
803- #define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */
804-
805878#define GC_NULL (IS_NULL | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))
806879#define GC_STRING (IS_STRING | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))
807880#define GC_ARRAY IS_ARRAY
@@ -1299,79 +1372,6 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) {
12991372#define Z_TRY_ADDREF (z ) Z_TRY_ADDREF_P(&(z))
13001373#define Z_TRY_DELREF (z ) Z_TRY_DELREF_P(&(z))
13011374
1302- #ifndef ZEND_RC_DEBUG
1303- # define ZEND_RC_DEBUG 0
1304- #endif
1305-
1306- #if ZEND_RC_DEBUG
1307- extern ZEND_API bool zend_rc_debug ;
1308- /* The GC_PERSISTENT flag is reused for IS_OBJ_WEAKLY_REFERENCED on objects.
1309- * Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */
1310- # define ZEND_RC_MOD_CHECK (p ) do { \
1311- if (zend_rc_debug) { \
1312- uint8_t type = zval_gc_type((p)->u.type_info); \
1313- if (type != IS_OBJECT && type != IS_NULL) { \
1314- ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \
1315- ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \
1316- } \
1317- } \
1318- } while (0)
1319- # define GC_MAKE_PERSISTENT_LOCAL (p ) do { \
1320- GC_ADD_FLAGS(p, GC_PERSISTENT_LOCAL); \
1321- } while (0)
1322- #else
1323- # define ZEND_RC_MOD_CHECK (p ) \
1324- do { } while (0)
1325- # define GC_MAKE_PERSISTENT_LOCAL (p ) \
1326- do { } while (0)
1327- #endif
1328-
1329- static zend_always_inline uint32_t zend_gc_refcount (const zend_refcounted_h * p ) {
1330- return p -> refcount ;
1331- }
1332-
1333- static zend_always_inline uint32_t zend_gc_set_refcount (zend_refcounted_h * p , uint32_t rc ) {
1334- p -> refcount = rc ;
1335- return p -> refcount ;
1336- }
1337-
1338- static zend_always_inline uint32_t zend_gc_addref (zend_refcounted_h * p ) {
1339- ZEND_RC_MOD_CHECK (p );
1340- return ++ (p -> refcount );
1341- }
1342-
1343- static zend_always_inline void zend_gc_try_addref (zend_refcounted_h * p ) {
1344- if (!(p -> u .type_info & GC_IMMUTABLE )) {
1345- ZEND_RC_MOD_CHECK (p );
1346- ++ p -> refcount ;
1347- }
1348- }
1349-
1350- static zend_always_inline void zend_gc_try_delref (zend_refcounted_h * p ) {
1351- if (!(p -> u .type_info & GC_IMMUTABLE )) {
1352- ZEND_RC_MOD_CHECK (p );
1353- -- p -> refcount ;
1354- }
1355- }
1356-
1357- static zend_always_inline uint32_t zend_gc_delref (zend_refcounted_h * p ) {
1358- ZEND_ASSERT (p -> refcount > 0 );
1359- ZEND_RC_MOD_CHECK (p );
1360- return -- (p -> refcount );
1361- }
1362-
1363- static zend_always_inline uint32_t zend_gc_addref_ex (zend_refcounted_h * p , uint32_t rc ) {
1364- ZEND_RC_MOD_CHECK (p );
1365- p -> refcount += rc ;
1366- return p -> refcount ;
1367- }
1368-
1369- static zend_always_inline uint32_t zend_gc_delref_ex (zend_refcounted_h * p , uint32_t rc ) {
1370- ZEND_RC_MOD_CHECK (p );
1371- p -> refcount -= rc ;
1372- return p -> refcount ;
1373- }
1374-
13751375static zend_always_inline uint32_t zval_refcount_p (const zval * pz ) {
13761376#if ZEND_DEBUG
13771377 ZEND_ASSERT (Z_REFCOUNTED_P (pz ) || Z_TYPE_P (pz ) == IS_ARRAY );
0 commit comments