
value flag_owned (1)
value flag_no_owner (2)
value flag_shared (4)
value flag_on_stack (8)
value flag_has_vtable (16)
value flag_still_co_owned (32)
value flag_in_updates (64)
value flag_in_blanks (128)

value mark1 (1)
value mark2 (2)
value mark_leak (4)

macro gcdata "(" V:v1 ")" <{ return @offset(v1, u8, -8).@cast(GcData) }

value offmask (0xFFF8)

struct GcData {
    co_count: u32
    flags: u8
    propc: u8
    block_offset: u16
    vtable: ptr
    //
    fn item() GcItem { return @offset(this, u8, 8).@cast(GcItem) }

    // Mark
    fn is_marked() bool { return (this.block_offset & (mark1 + mark2)) == mark }
    fn set_mark() { this.block_offset = (this.block_offset & offmask) | mark }
    fn remove_mark() { this.block_offset = this.block_offset & offmask }

    fn has_leak_mark() bool { return (this.block_offset & (mark_leak)) == mark_leak }
    fn set_leak_mark() { this.block_offset = this.block_offset | mark_leak }
    fn remove_leak_mark() { this.block_offset = (this.block_offset & (0xFFFF - mark_leak)) }

    // Flags
    fn set_new() { this.flags = this.flags & (255 - flag_owned - flag_no_owner) }
    fn set_owned() { this.flags = (this.flags & (255 - flag_no_owner)) | flag_owned }
    fn set_no_owner() { this.flags = (this.flags & (255 - flag_owned)) | flag_no_owner }
    //
    fn is_new() bool { return (this.flags & (flag_owned + flag_no_owner)) == 0 }
    fn is_not_new() bool { return (this.flags & (flag_owned + flag_no_owner)) != 0 }
    fn is_owned() bool { return (this.flags & flag_owned) != 0 }
    fn is_owned_not_shared() bool { return (this.flags & (flag_owned + flag_shared)) == flag_owned }
    fn is_not_owned() bool { return (this.flags & flag_owned) == 0 }
    fn is_not_owned_not_shared() bool { return (this.flags & (flag_owned + flag_shared)) == 0 }
    fn is_no_owner_not_shared() bool { return (this.flags & (flag_no_owner + flag_shared)) == flag_no_owner }

    fn is_shared() bool { return (this.flags & flag_shared) != 0 }
    fn set_shared() { this.flags = this.flags | flag_shared }
    fn remove_shared() { this.flags = this.flags & (255 - flag_shared) }

    fn is_on_stack() bool { return (this.flags & flag_on_stack) != 0 }
    fn set_on_stack() { this.flags = this.flags | flag_on_stack }
    fn remove_on_stack() { this.flags = this.flags & (255 - flag_on_stack) }
    //
    fn has_vtable() bool { return (this.flags & flag_has_vtable) != 0 }
    fn set_has_vtable() { this.flags = this.flags | flag_has_vtable }
    fn remove_has_vtable() { this.flags = this.flags & (255 - flag_has_vtable) }
    //
    // fn is_custom_co_count() bool { return (this.flags & flag_custom_co_count) != 0 }
    // fn set_custom_co_count() { this.flags = this.flags | flag_custom_co_count }
    // fn remove_custom_co_count() { this.flags = this.flags & (255 - flag_custom_co_count) }
    //
    // fn is_still_co_owned() bool { return (this.flags & flag_still_co_owned) != 0 }
    // fn set_still_co_owned() { this.flags = this.flags | flag_still_co_owned }
    // fn remove_still_co_owned() { this.flags = this.flags & (255 - flag_still_co_owned) }
    //
    fn is_in_updates() bool { return (this.flags & flag_in_updates) != 0 }
    fn set_in_updates() { this.flags = this.flags | flag_in_updates }
    fn remove_in_updates() { this.flags = this.flags & (255 - flag_in_updates) }
    //
    fn is_in_blanks() bool { return (this.flags & flag_in_blanks) != 0 }
    fn set_in_blanks() { this.flags = this.flags | flag_in_blanks }
    fn remove_in_blanks() { this.flags = this.flags & (255 - flag_in_blanks) }

    //
    fn co_own() {
        atomic(this.co_count + 1)
    }

    fn dis_co_own() {
        atomic(this.co_count - 1)
    }
}

pointer GcItem {
}
