src/runtime/collect.c
// Advances `rtti` through one set of entries, also advancing `object` and marking any pointers.
Advances `rtti` through one set of entries, also advancing `object` and marking any pointers.
Advances ` rtti ` through one set of entries also advancing ` object ` and marking any pointers .
static void rtti_go(uint32_t** rtti, uint64_t** object) {
    while(true) {
        uint32_t entry = *(*rtti)++;
        uint32_t type = (entry & 0b110) >> 1;
        switch (type) {
        case 0b00: {
            uint32_t size = (entry >> 3) & 0b11111;
            uint32_t bitset = entry >> 8;
            for (int word = 0; word < size; word++, *object += 1) {
                if (bitset & (1 << word)) {
                    mark((uint64_t**)*object);
                }
            }
            break;
        }
        case 0b01: {
            uint32_t tag_bytes = ((entry >> 3) & 0b111) + 1;
            uint32_t offset_bytes = (entry >> 6) & 0b111;
            uint32_t variants = (entry >> 9) & ((1 << 11) - 1);
            uint32_t total_size = entry >> 20;
            uint64_t mask = (1UL << (tag_bytes * 8)) - 1;
            uint64_t tag = (**object >> (offset_bytes * 8)) & mask;
            if (tag >= variants) {
                panic("tag %lu in word %lu out of range, expected one of %u variants\n", tag, **object, variants);
            }
            uint64_t* end = *object + total_size;
            *object += 1;
            for (int v = 0; v < variants; v++) {
                if (v == tag)
                    rtti_go(rtti, object);
                else
                    rtti_skip(rtti);
            }
            *object = end;
            break;
        }
        case 0b10: {
            bool pointer = (entry & 0b1000) != 0;
            uint32_t size = entry >> 4;
            for (int word = 0; word < size; word++, *object += 1) {
                if (pointer) {
                    mark((uint64_t**)*object);
                }
            }
            break;
        }
        default:
            panic("Not supported: type %u\n", type);
        }
        if (entry & 1)
            continue;
        else
            break;
    }
}
static void rtti_go ( uint32_t * * rtti , uint64_t * * object ) { while ( true ) { uint32_t entry = * ( * rtti ) ++ ; uint32_t type = ( entry & 0b110 ) >> 1 ; switch ( type ) { case 0b00 : { uint32_t size = ( entry >> 3 ) & 0b11111 ; uint32_t bitset = entry >> 8 ; for ( int word = 0 ; word < size ; word ++ , * object += 1 ) { if ( bitset & ( 1 << word ) ) { mark ( ( uint64_t * * ) * object ) ; } } break ; } case 0b01 : { uint32_t tag_bytes = ( ( entry >> 3 ) & 0b111 ) + 1 ; uint32_t offset_bytes = ( entry >> 6 ) & 0b111 ; uint32_t variants = ( entry >> 9 ) & ( ( 1 << 11 ) - 1 ) ; uint32_t total_size = entry >> 20 ; uint64_t mask = ( 1UL << ( tag_bytes * 8 ) ) - 1 ; uint64_t tag = ( * * object >> ( offset_bytes * 8 ) ) & mask ; if ( tag >= variants ) { panic ( " \n " , tag , * * object , variants ) ; } uint64_t * end = * object + total_size ; * object += 1 ; for ( int v = 0 ; v < variants ; v ++ ) { if ( v == tag ) rtti_go ( rtti , object ) ; else rtti_skip ( rtti ) ; } * object = end ; break ; } case 0b10 : { bool pointer = ( entry & 0b1000 ) != 0 ; uint32_t size = entry >> 4 ; for ( int word = 0 ; word < size ; word ++ , * object += 1 ) { if ( pointer ) { mark ( ( uint64_t * * ) * object ) ; } } break ; } default : panic ( " \n " , type ) ; } if ( entry & 1 ) continue ; else break ; } }
Advances `rtti` through one set of entries, also advancing `object` and marking any pointers.
Advances ` rtti ` through one set of entries also advancing ` object ` and marking any pointers .
// Bitset // Case split // 0..0 0..0 000 000 01 0 // ---- ---- --- --- -- - whether there's another struct member after this // |    |    |   |   | // |    |    |   |   01 is the type for a case split // |    |    |   3-bit size of the tag in bytes (up to 8) // |    |    3-bit offset of the tag in bytes from the end of the last entry // |    11-bit number of variants // 12-bit size of the variant in words, including the tag // Only works on little-endian systems // Example: // Offset 1, size 2 // little-endian bytes //      AAAA BBBB CCCC DDDD //           --------- // to uint64_t //      DDDDCCCCBBBBAAAA // offset 1 --> //      0000DDDDCCCCBBBB // size 2       -------- //      00000000CCCCBBBB // The variant might not occupy the entire space if it's not the biggest one // But the next entry doesn't start until after the total size // RLE