25
25
#include "zend_portability.h"
26
26
#include "zend_long.h"
27
27
#include "zend_rc_debug.h"
28
- #include "zend_refcounted.h"
29
28
#include "zend_result.h"
30
29
#include "zend_type_code.h"
31
30
@@ -84,6 +83,7 @@ typedef struct _zend_execute_data zend_execute_data;
84
83
85
84
typedef struct _zval_struct zval ;
86
85
86
+ typedef struct _zend_refcounted zend_refcounted ;
87
87
typedef struct _zend_string zend_string ;
88
88
typedef struct _zend_array zend_array ;
89
89
typedef struct _zend_object zend_object ;
@@ -333,6 +333,17 @@ struct _zval_struct {
333
333
} u2 ;
334
334
};
335
335
336
+ typedef struct _zend_refcounted_h {
337
+ uint32_t refcount ; /* reference counter 32-bit */
338
+ union {
339
+ uint32_t type_info ;
340
+ } u ;
341
+ } zend_refcounted_h ;
342
+
343
+ struct _zend_refcounted {
344
+ zend_refcounted_h gc ;
345
+ };
346
+
336
347
struct _zend_string {
337
348
zend_refcounted_h gc ;
338
349
zend_ulong h ; /* hash value */
@@ -577,12 +588,33 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) {
577
588
578
589
#define Z_TYPE_FLAGS_SHIFT 8
579
590
591
+ #define GC_REFCOUNT (p ) zend_gc_refcount(&(p)->gc)
592
+ #define GC_SET_REFCOUNT (p , rc ) zend_gc_set_refcount(&(p)->gc, rc)
593
+ #define GC_ADDREF (p ) zend_gc_addref(&(p)->gc)
594
+ #define GC_DELREF (p ) zend_gc_delref(&(p)->gc)
595
+ #define GC_ADDREF_EX (p , rc ) zend_gc_addref_ex(&(p)->gc, rc)
596
+ #define GC_DELREF_EX (p , rc ) zend_gc_delref_ex(&(p)->gc, rc)
597
+ #define GC_TRY_ADDREF (p ) zend_gc_try_addref(&(p)->gc)
598
+ #define GC_TRY_DELREF (p ) zend_gc_try_delref(&(p)->gc)
599
+
580
600
#define GC_TYPE_MASK 0x0000000f
581
601
#define GC_FLAGS_MASK 0x000003f0
582
602
#define GC_INFO_MASK 0xfffffc00
583
603
#define GC_FLAGS_SHIFT 0
584
604
#define GC_INFO_SHIFT 10
585
605
606
+ static zend_always_inline uint8_t zval_gc_type (uint32_t gc_type_info ) {
607
+ return (gc_type_info & GC_TYPE_MASK );
608
+ }
609
+
610
+ static zend_always_inline uint32_t zval_gc_flags (uint32_t gc_type_info ) {
611
+ return (gc_type_info >> GC_FLAGS_SHIFT ) & (GC_FLAGS_MASK >> GC_FLAGS_SHIFT );
612
+ }
613
+
614
+ static zend_always_inline uint32_t zval_gc_info (uint32_t gc_type_info ) {
615
+ return (gc_type_info >> GC_INFO_SHIFT );
616
+ }
617
+
586
618
#define GC_TYPE_INFO (p ) (p)->gc.u.type_info
587
619
#define GC_TYPE (p ) zval_gc_type(GC_TYPE_INFO(p))
588
620
#define GC_FLAGS (p ) zval_gc_flags(GC_TYPE_INFO(p))
@@ -606,6 +638,21 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) {
606
638
#define Z_GC_TYPE_INFO (zval ) GC_TYPE_INFO(Z_COUNTED(zval))
607
639
#define Z_GC_TYPE_INFO_P (zval_p ) Z_GC_TYPE_INFO(*(zval_p))
608
640
641
+ /* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */
642
+ #define GC_NOT_COLLECTABLE (1<<4)
643
+ #define GC_PROTECTED (1<<5) /* used for recursion detection */
644
+ #define GC_IMMUTABLE (1<<6) /* can't be changed in place */
645
+ #define GC_PERSISTENT (1<<7) /* allocated using malloc */
646
+ #define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */
647
+
648
+ #define GC_NULL (IS_NULL | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))
649
+ #define GC_STRING (IS_STRING | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))
650
+ #define GC_ARRAY IS_ARRAY
651
+ #define GC_OBJECT IS_OBJECT
652
+ #define GC_RESOURCE (IS_RESOURCE | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))
653
+ #define GC_REFERENCE (IS_REFERENCE | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))
654
+ #define GC_CONSTANT_AST (IS_CONSTANT_AST | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))
655
+
609
656
/* zval.u1.v.type_flags */
610
657
#define IS_TYPE_REFCOUNTED (1<<0)
611
658
#define IS_TYPE_COLLECTABLE (1<<1)
@@ -1087,6 +1134,52 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) {
1087
1134
do { } while (0)
1088
1135
#endif
1089
1136
1137
+ static zend_always_inline uint32_t zend_gc_refcount (const zend_refcounted_h * p ) {
1138
+ return p -> refcount ;
1139
+ }
1140
+
1141
+ static zend_always_inline uint32_t zend_gc_set_refcount (zend_refcounted_h * p , uint32_t rc ) {
1142
+ p -> refcount = rc ;
1143
+ return p -> refcount ;
1144
+ }
1145
+
1146
+ static zend_always_inline uint32_t zend_gc_addref (zend_refcounted_h * p ) {
1147
+ ZEND_RC_MOD_CHECK (p );
1148
+ return ++ (p -> refcount );
1149
+ }
1150
+
1151
+ static zend_always_inline void zend_gc_try_addref (zend_refcounted_h * p ) {
1152
+ if (!(p -> u .type_info & GC_IMMUTABLE )) {
1153
+ ZEND_RC_MOD_CHECK (p );
1154
+ ++ p -> refcount ;
1155
+ }
1156
+ }
1157
+
1158
+ static zend_always_inline void zend_gc_try_delref (zend_refcounted_h * p ) {
1159
+ if (!(p -> u .type_info & GC_IMMUTABLE )) {
1160
+ ZEND_RC_MOD_CHECK (p );
1161
+ -- p -> refcount ;
1162
+ }
1163
+ }
1164
+
1165
+ static zend_always_inline uint32_t zend_gc_delref (zend_refcounted_h * p ) {
1166
+ ZEND_ASSERT (p -> refcount > 0 );
1167
+ ZEND_RC_MOD_CHECK (p );
1168
+ return -- (p -> refcount );
1169
+ }
1170
+
1171
+ static zend_always_inline uint32_t zend_gc_addref_ex (zend_refcounted_h * p , uint32_t rc ) {
1172
+ ZEND_RC_MOD_CHECK (p );
1173
+ p -> refcount += rc ;
1174
+ return p -> refcount ;
1175
+ }
1176
+
1177
+ static zend_always_inline uint32_t zend_gc_delref_ex (zend_refcounted_h * p , uint32_t rc ) {
1178
+ ZEND_RC_MOD_CHECK (p );
1179
+ p -> refcount -= rc ;
1180
+ return p -> refcount ;
1181
+ }
1182
+
1090
1183
static zend_always_inline uint32_t zval_refcount_p (const zval * pz ) {
1091
1184
#if ZEND_DEBUG
1092
1185
ZEND_ASSERT (Z_REFCOUNTED_P (pz ) || Z_TYPE_P (pz ) == IS_ARRAY );
0 commit comments