Skip to content

Commit

Permalink
Clean up gc_scan() implementation
Browse files Browse the repository at this point in the history
The HT handling no longer needs to be shared, so move it into the
right branch. Also use a couple of early gotos to reduce nesting.
  • Loading branch information
nikic committed Jul 12, 2021
1 parent 5f8ed77 commit 5bde82a
Showing 1 changed file with 77 additions and 83 deletions.
160 changes: 77 additions & 83 deletions Zend/zend_gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,112 +991,106 @@ static void gc_mark_roots(gc_stack *stack)

static void gc_scan(zend_refcounted *ref, gc_stack *stack)
{
HashTable *ht = NULL;
Bucket *p, *end;
zval *zv;
GC_STACK_DCL(stack);

tail_call:
if (GC_REF_CHECK_COLOR(ref, GC_WHITE)) {
if (GC_REFCOUNT(ref) > 0) {
if (!GC_REF_CHECK_COLOR(ref, GC_BLACK)) {
GC_REF_SET_BLACK(ref);
if (UNEXPECTED(!_stack->next)) {
gc_stack_next(_stack);
}
/* Split stack and reuse the tail */
_stack->next->prev = NULL;
gc_scan_black(ref, _stack->next);
_stack->next->prev = _stack;
if (!GC_REF_CHECK_COLOR(ref, GC_WHITE)) {
goto next;
}

if (GC_REFCOUNT(ref) > 0) {
if (!GC_REF_CHECK_COLOR(ref, GC_BLACK)) {
GC_REF_SET_BLACK(ref);
if (UNEXPECTED(!_stack->next)) {
gc_stack_next(_stack);
}
} else {
if (GC_TYPE(ref) == IS_OBJECT) {
zend_object *obj = (zend_object*)ref;

if (EXPECTED(!(OBJ_FLAGS(ref) & IS_OBJ_FREE_CALLED))) {
int n;
zval *zv, *end;

ht = obj->handlers->get_gc(obj, &zv, &n);
if (UNEXPECTED(ht)) {
if (GC_REF_CHECK_COLOR(ht, GC_GREY)) {
GC_REF_SET_COLOR(ht, GC_WHITE);
GC_STACK_PUSH((zend_refcounted *) ht);
}
ht = NULL;
}
/* Split stack and reuse the tail */
_stack->next->prev = NULL;
gc_scan_black(ref, _stack->next);
_stack->next->prev = _stack;
}
goto next;
}

if (!n) goto next;
end = zv + n;
while (!Z_REFCOUNTED_P(--end)) {
if (zv == end) goto next;
}
while (zv != end) {
if (Z_REFCOUNTED_P(zv)) {
ref = Z_COUNTED_P(zv);
if (GC_REF_CHECK_COLOR(ref, GC_GREY)) {
GC_REF_SET_COLOR(ref, GC_WHITE);
GC_STACK_PUSH(ref);
}
}
zv++;
}
ref = Z_COUNTED_P(zv);
if (GC_REF_CHECK_COLOR(ref, GC_GREY)) {
GC_REF_SET_COLOR(ref, GC_WHITE);
goto tail_call;
}
}
goto next;
} else if (GC_TYPE(ref) == IS_ARRAY) {
ZEND_ASSERT((zend_array*)ref != &EG(symbol_table));
ht = (zend_array*)ref;
} else if (GC_TYPE(ref) == IS_REFERENCE) {
if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
ref = Z_COUNTED(((zend_reference*)ref)->val);
if (GC_REF_CHECK_COLOR(ref, GC_GREY)) {
GC_REF_SET_COLOR(ref, GC_WHITE);
goto tail_call;
}
if (GC_TYPE(ref) == IS_OBJECT) {
zend_object *obj = (zend_object*)ref;
if (EXPECTED(!(OBJ_FLAGS(ref) & IS_OBJ_FREE_CALLED))) {
int n;
zval *zv, *end;
HashTable *ht = obj->handlers->get_gc(obj, &zv, &n);
if (UNEXPECTED(ht)) {
if (GC_REF_CHECK_COLOR(ht, GC_GREY)) {
GC_REF_SET_COLOR(ht, GC_WHITE);
GC_STACK_PUSH((zend_refcounted *) ht);
}
goto next;
} else {
goto next;
}

if (!ht->nNumUsed) goto next;
p = ht->arData;
end = p + ht->nNumUsed;
while (1) {
end--;
zv = &end->val;
if (Z_TYPE_P(zv) == IS_INDIRECT) {
zv = Z_INDIRECT_P(zv);
}
if (Z_REFCOUNTED_P(zv)) {
break;
}
if (p == end) goto next;
if (!n) goto next;
end = zv + n;
while (!Z_REFCOUNTED_P(--end)) {
if (zv == end) goto next;
}
while (p != end) {
zv = &p->val;
if (Z_TYPE_P(zv) == IS_INDIRECT) {
zv = Z_INDIRECT_P(zv);
}
while (zv != end) {
if (Z_REFCOUNTED_P(zv)) {
ref = Z_COUNTED_P(zv);
if (GC_REF_CHECK_COLOR(ref, GC_GREY)) {
GC_REF_SET_COLOR(ref, GC_WHITE);
GC_STACK_PUSH(ref);
}
}
p++;
zv++;
}
ref = Z_COUNTED_P(zv);
if (GC_REF_CHECK_COLOR(ref, GC_GREY)) {
GC_REF_SET_COLOR(ref, GC_WHITE);
goto tail_call;
}
}
} else if (GC_TYPE(ref) == IS_ARRAY) {
HashTable *ht = (HashTable *)ref;
ZEND_ASSERT(ht != &EG(symbol_table));
if (!ht->nNumUsed) goto next;
p = ht->arData;
end = p + ht->nNumUsed;
while (1) {
end--;
zv = &end->val;
if (Z_TYPE_P(zv) == IS_INDIRECT) {
zv = Z_INDIRECT_P(zv);
}
if (Z_REFCOUNTED_P(zv)) {
break;
}
if (p == end) goto next;
}
while (p != end) {
zv = &p->val;
if (Z_TYPE_P(zv) == IS_INDIRECT) {
zv = Z_INDIRECT_P(zv);
}
ref = Z_COUNTED_P(zv);
if (Z_REFCOUNTED_P(zv)) {
ref = Z_COUNTED_P(zv);
if (GC_REF_CHECK_COLOR(ref, GC_GREY)) {
GC_REF_SET_COLOR(ref, GC_WHITE);
GC_STACK_PUSH(ref);
}
}
p++;
}
zv = &p->val;
if (Z_TYPE_P(zv) == IS_INDIRECT) {
zv = Z_INDIRECT_P(zv);
}
ref = Z_COUNTED_P(zv);
if (GC_REF_CHECK_COLOR(ref, GC_GREY)) {
GC_REF_SET_COLOR(ref, GC_WHITE);
goto tail_call;
}
} else if (GC_TYPE(ref) == IS_REFERENCE) {
if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
ref = Z_COUNTED(((zend_reference*)ref)->val);
if (GC_REF_CHECK_COLOR(ref, GC_GREY)) {
GC_REF_SET_COLOR(ref, GC_WHITE);
goto tail_call;
Expand Down

0 comments on commit 5bde82a

Please sign in to comment.