kern_return_t CollectorHeapIntrospector::enumerate(task_t task, void* context, unsigned typeMask, vm_address_t zoneAddress, memory_reader_t reader, vm_range_recorder_t recorder)
{
    RemoteMemoryReader memoryReader(task, reader);
    CollectorHeapIntrospector* zone = memoryReader(reinterpret_cast<CollectorHeapIntrospector*>(zoneAddress));
    CollectorHeap* heap = memoryReader(zone->m_heap);

    if (!heap->blocks)
        return 0;

    CollectorBlock** blocks = memoryReader(heap->blocks);
    for (unsigned i = 0; i < heap->usedBlocks; i++) {
        vm_address_t remoteBlockAddress = reinterpret_cast<vm_address_t>(blocks[i]);
        vm_range_t ptrRange = { remoteBlockAddress, sizeof(CollectorBlock) };

        if (typeMask & (MALLOC_PTR_REGION_RANGE_TYPE | MALLOC_ADMIN_REGION_RANGE_TYPE))
            (*recorder)(task, context, MALLOC_PTR_REGION_RANGE_TYPE, &ptrRange, 1);

        // Recording individual cells causes frequent false-positives.  Any garbage cells
        // which have yet to be collected are labeled as leaks.  Recording on a per-block
        // basis provides less detail but avoids these false-positives.
        if (memoryReader(blocks[i])->usedCells && (typeMask & MALLOC_PTR_IN_USE_RANGE_TYPE))
            (*recorder)(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, &ptrRange, 1);
    }

    return 0;
}
    bool decodeForSize(const Vector<char>& data, int fmt)
    {
        void* rxi = 0;
        bool result = false;
        MemReader memoryReader((unsigned char*)data.data(), data.size());

        if (m_sizeInitialized) {
            if (!m_decoder->setSize(m_w, m_h))
                return m_decoder->setFailed();
            return true;
        }

        if (!m_memoryManager)
            return false;

        // The rest of the code expects that the first 8 bytes has already been read.
        // The signature for these files is 8 bytes.
        memoryReader.SetOffset(8);


        switch (fmt) {
        case RxIImageDecoder::FormatRdi:
            rxi = RdiBirth(m_memoryManager, &memoryReader);
            break;
        case RxIImageDecoder::FormatRgi:
            rxi = RgiBirth(m_memoryManager, &memoryReader);
            break;
        case RxIImageDecoder::FormatRpi:
            rxi = RpiBirth(m_memoryManager, &memoryReader);
            break;
        case RxIImageDecoder::FormatRwi:
            rxi = RwiBirth(m_memoryManager, &memoryReader);
            break;
        case RxIImageDecoder::FormatUnknown:
            ASSERT_NOT_REACHED();
        }

        if (!rxi)
            return false;

        switch (fmt) {
        case RxIImageDecoder::FormatRdi:
            result = RdiGetWH(rxi, &m_w, &m_h);
            break;
        case RxIImageDecoder::FormatRgi:
            result = RgiGetWH(rxi, &m_w, &m_h);
            break;
        case RxIImageDecoder::FormatRpi:
            result = RpiGetWH(rxi, &m_w, &m_h);
            break;
        case RxIImageDecoder::FormatRwi:
            result = RwiGetWH(rxi, &m_w, &m_h);
            break;
        case RxIImageDecoder::FormatUnknown:
            ASSERT_NOT_REACHED();
            break;
        }

        if (!result) {
            delete m_memoryReader;
            m_memoryReader = 0;
            return false;
        }
        m_sizeInitialized = true;

        switch (fmt) {
        case RxIImageDecoder::FormatRdi:
            RdiDeath(rxi);
            break;
        case RxIImageDecoder::FormatRgi:
            RgiDeath(rxi);
            break;
        case RxIImageDecoder::FormatRpi:
            RpiDeath(rxi);
            break;
        case RxIImageDecoder::FormatRwi:
            RwiDeath(rxi);
            break;
        case RxIImageDecoder::FormatUnknown:
            ASSERT_NOT_REACHED();
            break;
        }

        // We can fill in the size now that the header is available.
        if (!m_decoder->setSize(m_w, m_h))
            return m_decoder->setFailed();

        return true;
    }