85# define ZEND_GC_DEBUG 0
89#define GC_ADDRESS 0x0fffffu
90#define GC_COLOR 0x300000u
92#define GC_BLACK 0x000000u
93#define GC_WHITE 0x100000u
94#define GC_GREY 0x200000u
95#define GC_PURPLE 0x300000u
99# define GC_TRACE(format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__);
100# define GC_TRACE_REF(ref, format, ...) \
102 gc_trace_ref((zend_refcounted *) ref); \
103 fprintf(stderr, format "\n", ##__VA_ARGS__); \
105# define GC_TRACE_SET_COLOR(ref, color) \
106 GC_TRACE_REF(ref, "->%s", gc_color_name(color))
108# define GC_TRACE_REF(ref, format, ...)
109# define GC_TRACE_SET_COLOR(ref, new_color)
110# define GC_TRACE(str)
114#define GC_REF_ADDRESS(ref) \
115 (((GC_TYPE_INFO(ref)) & (GC_ADDRESS << GC_INFO_SHIFT)) >> GC_INFO_SHIFT)
117#define GC_REF_COLOR(ref) \
118 (((GC_TYPE_INFO(ref)) & (GC_COLOR << GC_INFO_SHIFT)) >> GC_INFO_SHIFT)
120#define GC_REF_CHECK_COLOR(ref, color) \
121 ((GC_TYPE_INFO(ref) & (GC_COLOR << GC_INFO_SHIFT)) == ((color) << GC_INFO_SHIFT))
123#define GC_REF_SET_INFO(ref, info) do { \
124 GC_TYPE_INFO(ref) = \
125 (GC_TYPE_INFO(ref) & (GC_TYPE_MASK | GC_FLAGS_MASK)) | \
126 ((info) << GC_INFO_SHIFT); \
129#define GC_REF_SET_COLOR(ref, c) do { \
130 GC_TRACE_SET_COLOR(ref, c); \
131 GC_TYPE_INFO(ref) = \
132 (GC_TYPE_INFO(ref) & ~(GC_COLOR << GC_INFO_SHIFT)) | \
133 ((c) << GC_INFO_SHIFT); \
136#define GC_REF_SET_BLACK(ref) do { \
137 GC_TRACE_SET_COLOR(ref, GC_BLACK); \
138 GC_TYPE_INFO(ref) &= ~(GC_COLOR << GC_INFO_SHIFT); \
141#define GC_REF_SET_PURPLE(ref) do { \
142 GC_TRACE_SET_COLOR(ref, GC_PURPLE); \
143 GC_TYPE_INFO(ref) |= (GC_COLOR << GC_INFO_SHIFT); \
151#define GC_GARBAGE 0x2
152#define GC_DTOR_GARBAGE 0x3
154#define GC_GET_PTR(ptr) \
155 ((void*)(((uintptr_t)(ptr)) & ~GC_BITS))
157#define GC_IS_ROOT(ptr) \
158 ((((uintptr_t)(ptr)) & GC_BITS) == GC_ROOT)
159#define GC_IS_UNUSED(ptr) \
160 ((((uintptr_t)(ptr)) & GC_BITS) == GC_UNUSED)
161#define GC_IS_GARBAGE(ptr) \
162 ((((uintptr_t)(ptr)) & GC_BITS) == GC_GARBAGE)
163#define GC_IS_DTOR_GARBAGE(ptr) \
164 ((((uintptr_t)(ptr)) & GC_BITS) == GC_DTOR_GARBAGE)
166#define GC_MAKE_GARBAGE(ptr) \
167 ((void*)(((uintptr_t)(ptr)) | GC_GARBAGE))
168#define GC_MAKE_DTOR_GARBAGE(ptr) \
169 ((void*)(((uintptr_t)(ptr)) | GC_DTOR_GARBAGE))
172#define GC_IDX2PTR(idx) (GC_G(buf) + (idx))
173#define GC_PTR2IDX(ptr) ((ptr) - GC_G(buf))
175#define GC_IDX2LIST(idx) ((void*)(uintptr_t)(((idx) * sizeof(void*)) | GC_UNUSED))
176#define GC_LIST2IDX(list) (((uint32_t)(uintptr_t)(list)) / sizeof(void*))
180#define GC_FIRST_ROOT 1
182#define GC_DEFAULT_BUF_SIZE (16 * 1024)
183#define GC_BUF_GROW_STEP (128 * 1024)
185#define GC_MAX_UNCOMPRESSED (512 * 1024)
186#define GC_MAX_BUF_SIZE 0x40000000
188#define GC_THRESHOLD_DEFAULT (10000 + GC_FIRST_ROOT)
189#define GC_THRESHOLD_STEP 10000
190#define GC_THRESHOLD_MAX 1000000000
191#define GC_THRESHOLD_TRIGGER 100
194#define GC_HAS_DESTRUCTORS (1<<0)
197#define Z_FROM_WEAKMAP_KEY (1<<0)
198#define Z_FROM_WEAKMAP (1<<1)
202#define GC_FROM_WEAKMAP_KEY(zv) \
203 (Z_TYPE_INFO_P((zv)) & (Z_FROM_WEAKMAP_KEY << Z_TYPE_INFO_EXTRA_SHIFT))
205#define GC_SET_FROM_WEAKMAP_KEY(zv) do { \
207 Z_TYPE_INFO_P(_z) = Z_TYPE_INFO_P(_z) | (Z_FROM_WEAKMAP_KEY << Z_TYPE_INFO_EXTRA_SHIFT); \
210#define GC_UNSET_FROM_WEAKMAP_KEY(zv) do { \
212 Z_TYPE_INFO_P(_z) = Z_TYPE_INFO_P(_z) & ~(Z_FROM_WEAKMAP_KEY << Z_TYPE_INFO_EXTRA_SHIFT); \
217#define GC_FROM_WEAKMAP(zv) \
218 (Z_TYPE_INFO_P((zv)) & (Z_FROM_WEAKMAP << Z_TYPE_INFO_EXTRA_SHIFT))
220#define GC_SET_FROM_WEAKMAP(zv) do { \
222 Z_TYPE_INFO_P(_z) = Z_TYPE_INFO_P(_z) | (Z_FROM_WEAKMAP << Z_TYPE_INFO_EXTRA_SHIFT); \
225#define GC_UNSET_FROM_WEAKMAP(zv) do { \
227 Z_TYPE_INFO_P(_z) = Z_TYPE_INFO_P(_z) & ~(Z_FROM_WEAKMAP << Z_TYPE_INFO_EXTRA_SHIFT); \
231#define GC_HAS_UNUSED() \
232 (GC_G(unused) != GC_INVALID)
233#define GC_FETCH_UNUSED() \
235#define GC_LINK_UNUSED(root) \
238#define GC_HAS_NEXT_UNUSED_UNDER_THRESHOLD() \
239 (GC_G(first_unused) < GC_G(gc_threshold))
240#define GC_HAS_NEXT_UNUSED() \
241 (GC_G(first_unused) != GC_G(buf_size))
242#define GC_FETCH_NEXT_UNUSED() \
243 gc_fetch_next_unused()
279 uint32_t root_buf_length;
280 uint32_t root_buf_peak;
281 uint32_t zval_possible_root;
282 uint32_t zval_buffered;
283 uint32_t zval_remove_from_buffer;
284 uint32_t zval_marked_grey;
289static int gc_globals_id;
290static size_t gc_globals_offset;
291#define GC_G(v) ZEND_TSRMG_FAST(gc_globals_offset, zend_gc_globals *, v)
293#define GC_G(v) (gc_globals.v)
298# define GC_BENCH_INC(counter) GC_G(counter)++
299# define GC_BENCH_DEC(counter) GC_G(counter)--
300# define GC_BENCH_PEAK(peak, counter) do { \
301 if (GC_G(counter) > GC_G(peak)) { \
302 GC_G(peak) = GC_G(counter); \
306# define GC_BENCH_INC(counter)
307# define GC_BENCH_DEC(counter)
308# define GC_BENCH_PEAK(peak, counter)
312#define GC_STACK_SEGMENT_SIZE (((4096 - ZEND_MM_OVERHEAD) / sizeof(void*)) - 2)
322#define GC_STACK_DCL(init) \
323 gc_stack *_stack = init; \
326#define GC_STACK_PUSH(ref) \
327 gc_stack_push(&_stack, &_top, ref);
329#define GC_STACK_POP() \
330 gc_stack_pop(&_stack, &_top)
336 segment->
prev = stack;
338 stack->
next = segment;
346 (*stack) = gc_stack_next(*stack);
349 (*stack)->data[(*top)++] = ref;
355 if (!(*stack)->prev) {
358 (*stack) = (*stack)->prev;
363 return (*stack)->data[--(*
top)];
367static void gc_stack_free(
gc_stack *stack)
428 idx =
GC_G(first_unused);
429 GC_G(first_unused) =
GC_G(first_unused) + 1;
434static const char *gc_color_name(uint32_t
color) {
440 default:
return "unknown";
446 fprintf(stderr,
"[%p] rc=%d addr=%d %s object(%s)#%d ",
452 fprintf(stderr,
"[%p] rc=%d addr=%d %s array(%d) ",
455 zend_hash_num_elements(arr));
457 fprintf(stderr,
"[%p] rc=%d addr=%d %s %s ",
475 if (gc_globals->buf) {
476 free(gc_globals->buf);
477 gc_globals->buf =
NULL;
483 gc_globals->gc_enabled = 0;
484 gc_globals->gc_active = 0;
485 gc_globals->gc_protected = 1;
486 gc_globals->gc_full = 0;
488 gc_globals->buf =
NULL;
493 gc_globals->num_roots = 0;
495 gc_globals->gc_runs = 0;
496 gc_globals->collected = 0;
497 gc_globals->collector_time = 0;
498 gc_globals->dtor_time = 0;
499 gc_globals->free_time = 0;
500 gc_globals->activated_at = 0;
503 gc_globals->dtor_end = 0;
504 gc_globals->dtor_fiber =
NULL;
505 gc_globals->dtor_fiber_running =
false;
508 gc_globals->root_buf_length = 0;
509 gc_globals->root_buf_peak = 0;
510 gc_globals->zval_possible_root = 0;
511 gc_globals->zval_buffered = 0;
512 gc_globals->zval_remove_from_buffer = 0;
513 gc_globals->zval_marked_grey = 0;
520 ts_allocate_fast_id(&gc_globals_id, &gc_globals_offset,
sizeof(
zend_gc_globals), (ts_allocate_ctor) gc_globals_ctor_ex, (ts_allocate_dtor) root_buffer_dtor);
522 gc_globals_ctor_ex(&gc_globals);
529 root_buffer_dtor(&gc_globals);
546 GC_G(collector_time) = 0;
553 GC_G(dtor_fiber_running) =
false;
556 GC_G(root_buf_length) = 0;
557 GC_G(root_buf_peak) = 0;
558 GC_G(zval_possible_root) = 0;
559 GC_G(zval_buffered) = 0;
560 GC_G(zval_remove_from_buffer) = 0;
561 GC_G(zval_marked_grey) = 0;
565 GC_G(activated_at) = zend_hrtime();
591 return old_protected;
599static void gc_grow_root_buffer(
void)
604 if (!
GC_G(gc_full)) {
613 new_size =
GC_G(buf_size) * 2;
621 GC_G(buf_size) = new_size;
624static void gc_adjust_threshold(
int count)
626 uint32_t new_threshold;
638 if (new_threshold >
GC_G(buf_size)) {
639 gc_grow_root_buffer();
641 if (new_threshold <=
GC_G(buf_size)) {
642 GC_G(gc_threshold) = new_threshold;
650 GC_G(gc_threshold) = new_threshold;
678 gc_grow_root_buffer();
689 idx = gc_compress(idx);
714 gc_possible_root_when_full(ref);
725 idx = gc_compress(idx);
744 gc_grow_root_buffer();
758 idx = gc_compress(idx);
770 gc_remove_from_roots(root);
787 gc_remove_compressed(ref, idx);
793 gc_remove_from_roots(root);
816 for (;
n != 0;
n-=2) {
854 for (;
n != 0;
n-=2) {
895 for (;
n != 0;
n--) {
911 for (;
n != 0;
n--) {
946 for (;
n != 0;
n--) {
1017 for (;
n != 0;
n-=2) {
1043 for (;
n != 0;
n--) {
1071 for (;
n != 0;
n--) {
1086 for (;
n != 0;
n--) {
1121 for (;
n != 0;
n--) {
1171static void gc_compact(
void)
1174 if (
GC_G(num_roots)) {
1181 while (free < scan) {
1207static void gc_mark_roots(
gc_stack *stack)
1219 gc_mark_grey(
current->ref, stack);
1243 gc_stack_next(_stack);
1246 _stack->next->prev =
NULL;
1247 gc_scan_black(ref, _stack->next);
1248 _stack->next->prev = _stack;
1263 for (;
n != 0;
n--) {
1284 for (;
n != 0;
n--) {
1299 for (;
n != 0;
n--) {
1333 for (;
n != 0;
n--) {
1379static void gc_scan_roots(
gc_stack *stack)
1388 while (idx !=
end) {
1400 while (idx !=
GC_G(first_unused)) {
1422 gc_grow_root_buffer();
1432 idx = gc_compress(idx);
1461 gc_add_garbage(ref);
1473 for (;
n != 0;
n--) {
1494 for (;
n != 0;
n--) {
1519 for (;
n != 0;
n--) {
1535 for (;
n != 0;
n--) {
1562 gc_add_garbage(ref);
1574 for (;
n != 0;
n--) {
1625static int gc_collect_roots(uint32_t *
flags,
gc_stack *stack)
1638 gc_remove_from_roots(
current);
1650 while (idx !=
end) {
1657 count += gc_collect_white(ref,
flags, stack);
1704 for (;
n != 0;
n--) {
1719 for (;
n != 0;
n--) {
1734 for (;
n != 0;
n--) {
1761 for (;
n != 0;
n--) {
1795static void zend_get_gc_buffer_release(
void);
1796static void zend_gc_check_root_tmpvars(
void);
1797static void zend_gc_remove_root_tmpvars(
void);
1818 while (idx !=
end) {
1828 if (fiber !=
NULL) {
1829 GC_G(dtor_idx) = idx;
1851static zend_fiber *gc_create_destructor_fiber(
void)
1856 GC_TRACE(
"starting destructor fiber");
1859 gc_create_destructor_fiber_error();
1866 GC_G(dtor_fiber) = fiber;
1869 gc_start_destructor_fiber_error();
1882 GC_G(dtor_end) =
GC_G(first_unused);
1885 fiber = gc_create_destructor_fiber();
1892 GC_TRACE(
"resumed from destructor fiber");
1897 GC_TRACE(
"destructor fiber suspended by destructor");
1902 zend_object_release(&fiber->
std);
1903 fiber = gc_create_destructor_fiber();
1907 GC_TRACE(
"destructor fiber suspended itself");
1915 int total_count = 0;
1916 bool should_rerun_gc = 0;
1917 bool did_rerun_gc = 0;
1920 if (
GC_G(num_roots) && !
GC_G(gc_active)) {
1921 zend_gc_remove_root_tmpvars();
1925 if (
GC_G(num_roots)) {
1929 uint32_t gc_flags = 0;
1936 if (
GC_G(gc_active)) {
1937 GC_G(collector_time) += zend_hrtime() - start_time;
1943 GC_G(gc_active) = 1;
1946 gc_mark_roots(&stack);
1948 gc_scan_roots(&stack);
1951 count = gc_collect_roots(&gc_flags, &stack);
1953 if (!
GC_G(num_roots)) {
1956 gc_stack_free(&stack);
1957 GC_G(gc_active) = 0;
1971 should_rerun_gc = 1;
1979 while (idx !=
end) {
2002 while (idx !=
end) {
2005 count -= gc_remove_nested_data_from_buffer(
p,
current, &stack);
2016 gc_call_destructors_in_fiber(
end);
2018 GC_G(dtor_time) += zend_hrtime() - dtor_start_time;
2022 zend_get_gc_buffer_release();
2023 GC_G(collector_time) += zend_hrtime() - start_time;
2028 gc_stack_free(&stack);
2034 while (idx !=
end) {
2083 GC_G(free_time) += zend_hrtime() - free_start_time;
2087 total_count +=
count;
2088 GC_G(gc_active) = 0;
2096 if (should_rerun_gc && !did_rerun_gc) {
2102 zend_get_gc_buffer_release();
2106 GC_G(gc_active) = 1;
2107 zend_gc_check_root_tmpvars();
2108 GC_G(gc_active) = 0;
2110 GC_G(collector_time) += zend_hrtime() - start_time;
2124 status->application_time = zend_hrtime() -
GC_G(activated_at);
2125 status->collector_time =
GC_G(collector_time);
2139 size_t old_capacity = gc_buffer->
end - gc_buffer->
start;
2140 size_t new_capacity = old_capacity == 0 ? 64 : old_capacity * 2;
2142 gc_buffer->
end = gc_buffer->
start + new_capacity;
2143 gc_buffer->
cur = gc_buffer->
start + old_capacity;
2146static void zend_get_gc_buffer_release(
void) {
2156static void zend_gc_check_root_tmpvars(
void) {
2158 for (;
ex;
ex =
ex->prev_execute_data) {
2164 uint32_t op_num =
ex->opline -
ex->func->op_array.opcodes;
2165 for (uint32_t i = 0; i <
func->op_array.last_live_range; i++) {
2167 if (range->start > op_num) {
2170 if (range->end <= op_num) {
2186static void zend_gc_remove_root_tmpvars(
void) {
2188 for (;
ex;
ex =
ex->prev_execute_data) {
2194 uint32_t op_num =
ex->opline -
ex->func->op_array.opcodes;
2195 for (uint32_t i = 0; i <
func->op_array.last_live_range; i++) {
2197 if (range->start > op_num) {
2200 if (range->end <= op_num) {
2217void gc_bench_print(
void)
2219 fprintf(stderr,
"GC Statistics\n");
2220 fprintf(stderr,
"-------------\n");
2222 fprintf(stderr,
"Collected: %d\n",
GC_G(collected));
2223 fprintf(stderr,
"Root buffer length: %d\n",
GC_G(root_buf_length));
2224 fprintf(stderr,
"Root buffer peak: %d\n\n",
GC_G(root_buf_peak));
2225 fprintf(stderr,
" Possible Remove from Marked\n");
2226 fprintf(stderr,
" Root Buffered buffer grey\n");
2227 fprintf(stderr,
" -------- -------- ----------- ------\n");
2228 fprintf(stderr,
"ZVAL %8d %8d %9d %8d\n",
GC_G(zval_possible_root),
GC_G(zval_buffered),
GC_G(zval_remove_from_buffer),
GC_G(zval_marked_grey));
2233size_t zend_gc_globals_size(
void)
2248 GC_G(dtor_fiber_running) =
true;
2250 idx =
GC_G(dtor_idx);
2259 GC_G(dtor_fiber_running) =
false;
2264 if (
GC_G(dtor_fiber) == fiber) {
2277 .handler =
ZEND_FN(gc_destructor_fiber),
2283 "gc_destructor_fiber",
2284 strlen(
"gc_destructor_fiber"),
fprintf($stream, string $format, mixed ... $values)
count(Countable|array $value, int $mode=COUNT_NORMAL)
zend_ffi_ctype_name_buf buf
unsigned const char * end
unsigned char key[REFLECTION_KEY_LEN]
zend_test_fiber * active_fiber
zend_refcounted * data[GC_STACK_SEGMENT_SIZE]
zend_function * destructor
zend_function * function_handler
zend_fcall_info_cache fci_cache
zend_hrtime_t collector_time
zend_hrtime_t activated_at
zend_object_dtor_obj_t dtor_obj
zend_object_free_obj_t free_obj
zend_object_get_gc_t get_gc
const zend_object_handlers * handlers
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format,...)
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
ZEND_API const char * zend_get_type_by_const(int type)
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
#define ZEND_FUNCTION(name)
#define perealloc(ptr, size, persistent)
#define pemalloc(size, persistent)
#define erealloc(ptr, size)
#define ZEND_USER_CODE(type)
#define ZEND_INTERNAL_FUNCTION
#define ZEND_CALL_VAR(call, n)
struct _zend_live_range zend_live_range
struct _zend_internal_function zend_internal_function
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
ZEND_API void zend_fiber_resume(zend_fiber *fiber, zval *value, zval *return_value)
ZEND_API zend_class_entry * zend_ce_fiber
ZEND_API void zend_fiber_suspend(zend_fiber *fiber, zval *value, zval *return_value)
ZEND_API zend_result zend_fiber_start(zend_fiber *fiber, zval *return_value)
@ ZEND_FIBER_FLAG_DESTROYED
union _zend_function zend_function
struct _zend_gc_globals zend_gc_globals
#define GC_BENCH_DEC(counter)
#define GC_HAS_NEXT_UNUSED()
#define GC_LINK_UNUSED(root)
#define GC_HAS_DESTRUCTORS
ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref)
#define GC_THRESHOLD_STEP
#define GC_FETCH_UNUSED()
#define GC_DEFAULT_BUF_SIZE
#define GC_FETCH_NEXT_UNUSED()
#define GC_IS_GARBAGE(ptr)
#define GC_TRACE_REF(ref, format,...)
#define GC_IS_DTOR_GARBAGE(ptr)
#define GC_MAKE_GARBAGE(ptr)
#define GC_TRACE_SET_COLOR(ref, new_color)
ZEND_API void zend_get_gc_buffer_grow(zend_get_gc_buffer *gc_buffer)
#define GC_FROM_WEAKMAP(zv)
void gc_globals_dtor(void)
#define GC_MAKE_DTOR_GARBAGE(ptr)
#define GC_STACK_SEGMENT_SIZE
#define GC_REF_ADDRESS(ref)
#define GC_FROM_WEAKMAP_KEY(zv)
#define GC_THRESHOLD_TRIGGER
#define GC_LIST2IDX(list)
struct _gc_stack gc_stack
#define GC_REF_CHECK_COLOR(ref, color)
void gc_globals_ctor(void)
ZEND_API bool gc_protect(bool protect)
ZEND_API int(* gc_collect_cycles)(void)
#define GC_REF_COLOR(ref)
#define GC_STACK_PUSH(ref)
#define GC_REF_SET_BLACK(ref)
#define GC_REF_SET_INFO(ref, info)
#define GC_HAS_NEXT_UNUSED_UNDER_THRESHOLD()
#define GC_SET_FROM_WEAKMAP(zv)
#define GC_UNSET_FROM_WEAKMAP_KEY(zv)
#define GC_IS_UNUSED(ptr)
ZEND_API void zend_gc_get_status(zend_gc_status *status)
#define GC_UNSET_FROM_WEAKMAP(zv)
ZEND_API bool gc_enabled(void)
#define GC_SET_FROM_WEAKMAP_KEY(zv)
#define GC_BENCH_INC(counter)
ZEND_API zend_get_gc_buffer * zend_get_gc_buffer_create(void)
ZEND_API int zend_gc_collect_cycles(void)
#define GC_STACK_DCL(init)
#define GC_THRESHOLD_DEFAULT
ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
#define GC_BENCH_PEAK(peak, counter)
ZEND_API bool gc_protected(void)
struct _gc_root_buffer gc_root_buffer
#define GC_REF_SET_COLOR(ref, c)
#define GC_MAX_UNCOMPRESSED
struct _zend_gc_status zend_gc_status
#define GC_REMOVE_FROM_BUFFER(p)
struct _zend_fiber zend_fiber
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
#define HT_ALLOW_COW_VIOLATION(ht)
ZEND_API void zend_objects_destroy_object(zend_object *object)
#define SET_OBJ_INVALID(o)
#define ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(h)
#define zend_never_inline
#define EXPECTED(condition)
#define zend_always_inline
#define UNEXPECTED(condition)
struct _zend_array zend_array
struct _zend_object zend_object
ZEND_API zend_string_init_interned_func_t zend_string_init_interned
#define Z_OPT_REFCOUNTED_P(zval_p)
#define Z_REFCOUNTED_P(zval_p)
struct _zend_array HashTable
#define IS_OBJ_FREE_CALLED
#define Z_COUNTED_P(zval_p)
#define IS_OBJ_DESTRUCTOR_CALLED
#define Z_REFCOUNTED(zval)
struct _zend_refcounted zend_refcounted
#define Z_INDIRECT_P(zval_p)
ZEND_RESULT_CODE zend_result
#define IS_OBJ_WEAKLY_REFERENCED
struct _zend_execute_data zend_execute_data
struct _zend_reference zend_reference
#define GC_ADD_FLAGS(p, flags)
ZEND_API void ZEND_FASTCALL rc_dtor_func(zend_refcounted *p)
HashTable * zend_weakmap_get_gc(zend_object *object, zval **table, int *n)
HashTable * zend_weakmap_get_object_entry_gc(zend_object *object, zval **table, int *n)
HashTable * zend_weakmap_get_key_entry_gc(zend_object *object, zval **table, int *n)
HashTable * zend_weakmap_get_object_key_entry_gc(zend_object *object, zval **table, int *n)
HashTable * zend_weakmap_get_entry_gc(zend_object *object, zval **table, int *n)