static void sweep()

in libs/base/gc.cpp [487:583]


static void sweep(int flags) {
    RefBlock *prevFreePtr = NULL;
    uint32_t freeSize = 0;
    uint32_t totalSize = 0;
    uint32_t maxFreeBlock = 0;
    firstFree = NULL;

    gcStats.numGC++;

    for (auto h = firstBlock; h; h = h->next) {
        auto d = h->data;
        auto words = BYTES_TO_WORDS(h->blockSize);
        auto end = d + words;
        totalSize += words;
        VLOG("sweep: %p - %p", d, end);
        while (d < end) {
            if (IS_LIVE(d->vtable)) {
                VVLOG("Live %p", d);
                d->setVT(d->vt() & ~MARKED_MASK);
                d += getObjectSize(d);
            } else {
                auto start = (RefBlock *)d;
                while (d < end) {
                    if (IS_FREE(d->vtable)) {
                        VVLOG("Free %p", d);
                    } else if (IS_LIVE(d->vtable)) {
                        break;
                    } else if (IS_ARRAY(d->vtable)) {
                        VVLOG("Dead Arr %p", d);
                    } else {
                        VVLOG("Dead Obj %p", d);
                        GC_CHECK(d->vtable->magic == VTABLE_MAGIC, 41);
                        d->destroyVT();
                        VVLOG("destroyed");
                    }
                    d += getObjectSize(d);
                }
                auto sz = d - (RefObject *)start;
                freeSize += sz;
                if (sz > (int)maxFreeBlock)
                    maxFreeBlock = sz;
#ifdef PXT_GC_CHECKS
                memset((void *)start, 0xff, WORDS_TO_BYTES(sz));
#endif
                start->setVT((sz << 2) | FREE_MASK);
                if (sz > 1) {
                    start->nextFree = NULL;
                    if (!prevFreePtr) {
                        firstFree = start;
                    } else {
                        prevFreePtr->nextFree = start;
                    }
                    prevFreePtr = start;
                }
            }
        }
    }

    if (midPtr) {
        uint32_t currFree = 0;
#ifdef PXT_ESP32
        auto limit = freeSize * 1 / 4;
#else
        auto limit = freeSize * 1 / 2;
#endif
        for (auto p = firstFree; p; p = p->nextFree) {
            auto len = VAR_BLOCK_WORDS(p->vtable);
            currFree += len;
            if (currFree > limit) {
                midPtr = (uint8_t *)p + ((limit - currFree + len) << 2);
                break;
            }
        }
    }

    freeSize = WORDS_TO_BYTES(freeSize);
    totalSize = WORDS_TO_BYTES(totalSize);
    maxFreeBlock = WORDS_TO_BYTES(maxFreeBlock);

    gcStats.lastFreeBytes = freeSize;
    gcStats.lastMaxBlockBytes = maxFreeBlock;

    if (gcStats.minFreeBytes == 0 || gcStats.minFreeBytes > freeSize)
        gcStats.minFreeBytes = freeSize;

    if (flags & 1)
        DMESG("GC %d/%d free; %d maxBlock", freeSize, totalSize, maxFreeBlock);
    else
        LOG("GC %d/%d free; %d maxBlock", freeSize, totalSize, maxFreeBlock);

#ifndef GC_GET_HEAP_SIZE
    // if the heap is 90% full, allocate a new block
    if (freeSize * 10 <= totalSize) {
        allocateBlock();
    }
#endif
}