while (zv != end) {
if (Z_REFCOUNTED_P(zv)) {
ref = Z_COUNTED_P(zv);
- GC_REFCOUNT(ref)--;
- gc_mark_grey(ref);
+ ZEND_ASSERT(GC_REFCOUNT(ref) > 0);
+ GC_DELREF(ref);
+ if (!GC_REF_CHECK_COLOR(ref, GC_GREY)) {
+ GC_REF_SET_COLOR(ref, GC_GREY);
+ GC_STACK_PUSH(ref);
+ }
}
zv++;
}
if (EXPECTED(!ht)) {
ref = Z_COUNTED_P(zv);
- GC_REFCOUNT(ref)--;
- goto tail_call;
+ ZEND_ASSERT(GC_REFCOUNT(ref) > 0);
+ GC_DELREF(ref);
+ if (!GC_REF_CHECK_COLOR(ref, GC_GREY)) {
+ GC_REF_SET_COLOR(ref, GC_GREY);
+ continue;
+ }
+ goto next;
}
} else {
- return;
+ goto next;
}
} else if (GC_TYPE(ref) == IS_ARRAY) {
if (((zend_array*)ref) == &EG(symbol_table)) {
} else if (GC_TYPE(ref) == IS_REFERENCE) {
if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
ref = Z_COUNTED(((zend_reference*)ref)->val);
- GC_REFCOUNT(ref)--;
- goto tail_call;
+ ZEND_ASSERT(GC_REFCOUNT(ref) > 0);
+ GC_DELREF(ref);
+ if (!GC_REF_CHECK_COLOR(ref, GC_GREY)) {
+ GC_REF_SET_COLOR(ref, GC_GREY);
+ continue;
+ }
}
- return;
+ goto next;
} else {
- return;
+ goto next;
}
- if (!ht->nNumUsed) return;
+ if (!ht->nNumUsed) goto next;
p = ht->arData;
end = p + ht->nNumUsed;
while (1) {
}
if (Z_REFCOUNTED_P(zv)) {
ref = Z_COUNTED_P(zv);
- GC_REFCOUNT(ref)--;
- gc_mark_grey(ref);
+ ZEND_ASSERT(GC_REFCOUNT(ref) > 0);
+ GC_DELREF(ref);
+ if (!GC_REF_CHECK_COLOR(ref, GC_GREY)) {
+ GC_REF_SET_COLOR(ref, GC_GREY);
+ GC_STACK_PUSH(ref);
+ }
}
p++;
}
zv = Z_INDIRECT_P(zv);
}
ref = Z_COUNTED_P(zv);
- GC_REFCOUNT(ref)--;
- goto tail_call;
+ ZEND_ASSERT(GC_REFCOUNT(ref) > 0);
+ GC_DELREF(ref);
+ if (!GC_REF_CHECK_COLOR(ref, GC_GREY)) {
+ GC_REF_SET_COLOR(ref, GC_GREY);
+ continue;
+ }
+
+next:
+ ref = GC_STACK_POP();
+ } while (ref);
+}
+
+/* Two-Finger compaction algorithm */
+static void gc_compact(void)
+{
+ if (GC_G(num_roots) + GC_FIRST_ROOT != GC_G(first_unused)) {
+ if (GC_G(num_roots)) {
+ gc_root_buffer *free = GC_IDX2PTR(GC_FIRST_ROOT);
+ gc_root_buffer *scan = GC_IDX2PTR(GC_G(first_unused) - 1);
+ gc_root_buffer *end = GC_IDX2PTR(GC_G(num_roots));
+ uint32_t idx;
+ zend_refcounted *p;
+
+ while (free < scan) {
+ while (!GC_IS_UNUSED(free->ref)) {
+ free++;
+ }
+ while (GC_IS_UNUSED(scan->ref)) {
+ scan--;
+ }
+ if (scan > free) {
+ p = scan->ref;
+ free->ref = p;
+ p = GC_GET_PTR(p);
+ idx = gc_compress(GC_PTR2IDX(free));
+ GC_REF_SET_INFO(p, idx | GC_REF_COLOR(p));
+ free++;
+ scan--;
+ if (scan <= end) {
+ break;
+ }
+ }
+ }
+ }
+ GC_G(unused) = GC_INVALID;
+ GC_G(first_unused) = GC_G(num_roots) + GC_FIRST_ROOT;
}
}