// File: baziotis[P]minijava-cpp/typecheck.cpp
// Function: TypeTable::compute_and_print_offsets_for_type(IdType*, unsigned long, unsigned long, VirtualTable*)
void TypeTable::compute_and_print_offsets_for_type(IdType *type, size_t start_fields, size_t start_methods, VirtualTable *vtable) {
    if (type == NULL) {
      return;
    }
    IdType *parent = type->parent;
    if (parent) {
        // Inherits, so include the parent at the start of the type.
        emit("%%class.%s = type { %%class.%s", type->id, parent->id);
    } else {
        // The first parent in the inheritance tree - create
        // a vptr.
        emit("%%class.%s = type { i8 (...)**", type->id);
    }

    // Process methods first to know how many methods we have so we
    // can emit the respective virtual pointer.
    int num_methods = start_methods / 8;
    size_t running_offset = start_methods;
    for (Method *method: type->methods) {
        if (!check_method_for_overriding(method, type, vtable)) {
            if (config.offsets) {
                printf("%s.%s: %zd\n", type->id, method->id, running_offset);
            }
            method->offset = running_offset;
            running_offset += 8;
            ++num_methods;
            vtable->insert(method, type->id);
        }
    }
    size_t methods_size = running_offset - start_methods;

    // Generate offsets for fields and also emit the fields.
    running_offset = start_fields;
    for (Local *field : type->fields) {
        field->offset = running_offset;
        if (config.offsets) {
            printf("%s.%s: %zd\n", type->id, field->id, field->offset);
        }
        emit(", ");
        if (field->type == this->bool_type) {
            emit("i1");
            running_offset += 1;
        } else if (field->type == this->int_type) {
            emit("i32");
            running_offset += 4;
        } else if (field->type == this->int_arr_type) {
            emit("i32*");
            running_offset += 8;
        } else {
            IdType *idtype = field->type->is_IdType();
            assert(idtype);
            emit("%%class.%s*", idtype->id);
            running_offset += 8;
        }
    }
    emit(" }\n");

    size_t fields_size = running_offset - start_fields;

    start_fields = start_fields + fields_size;
    type->__sizeof = start_fields;
    start_methods = start_methods + methods_size;

    Buf<VMethod> vmethods = vtable->vmethods;
    type->vmethods_len = vmethods.len;
    emit("@.%s = global [%d x i8*]\n[\n", type->id, vmethods.len);
    ssize_t i = 0;
    for (ssize_t i = 0; i < vmethods.len; ++i) {
        VMethod vmethod = vmethods[i];
        emit("i8* bitcast (");
        emit_vmethod_signature(type, vmethod.method); 
        emit(" @%s__%s to i8*)", vmethod.enclosing, vmethod.method->id);
        if (i != vmethods.len - 1) {
            emit(",");
        }
        emit("\n");
    }
    emit("]\n");
    
    assert(type->children);
    auto children = *(type->children);
    size_t len = children.len;
    if (len) {
        Buf<VMethod> deep_copy;
        // We only need deep copy for more than one children.
        RestorePair save[VirtualTable::nbuckets];
        if (len > 1) {
            deep_copy = vtable->vmethods.deep_copy();
            vtable->save_first_buckets(save);
        }
        compute_and_print_offsets_for_type(children[0], start_fields, start_methods, vtable);
        if (len > 1) {
            for (ssize_t index = 1; index < len; ++index) {
                vtable->vmethods = deep_copy;
                vtable->restore_first_buckets(save);
                IdType *child = children[index];
                compute_and_print_offsets_for_type(child, start_fields, start_methods, vtable);
                vtable->vmethods.free();
                if (index != len - 1) {
                    deep_copy = vtable->vmethods.deep_copy();
                }
            }
        }
    }

    type->invalidate_children();
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x360, %rsp            # imm = 0x360
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x358(%rbp)
cmpq $0x0, -0x10(%rbp)
jne 0xc2f6
jmp 0xc9ad
movq -0x10(%rbp), %rax
movq 0x78(%rax), %rax
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
je 0xc329
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
movq -0x30(%rbp), %rax
movq 0x8(%rax), %rdx
leaq 0xf4bc(%rip), %rdi      # 0x1b7dc
movb $0x0, %al
callq 0x5b70
jmp 0xc33f
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
leaq 0xf4c3(%rip), %rdi      # 0x1b7fb
movb $0x0, %al
callq 0x5b70
movq -0x20(%rbp), %rax
shrq $0x3, %rax
movl %eax, -0x34(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x10(%rbp), %rax
addq $0x40, %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rdi
callq 0x15680
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %rdi
callq 0x156a0
movq %rax, -0x58(%rbp)
movq -0x50(%rbp), %rax
cmpq -0x58(%rbp), %rax
je 0xc41d
movq -0x50(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rdi
movq -0x10(%rbp), %rsi
movq -0x28(%rbp), %rdx
callq 0xc030
testb $0x1, %al
jne 0xc40a
leaq 0x1869b(%rip), %rax     # 0x24a48
testb $0x1, 0x3(%rax)
je 0xc3d4
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
movq -0x60(%rbp), %rax
movq (%rax), %rdx
movq -0x40(%rbp), %rcx
leaq 0xf44d(%rip), %rdi      # 0x1b81a
movb $0x0, %al
callq 0x2030
movq -0x40(%rbp), %rcx
movq -0x60(%rbp), %rax
movq %rcx, 0x48(%rax)
movq -0x40(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x40(%rbp)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
movq -0x28(%rbp), %rdi
movq -0x60(%rbp), %rsi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdx
callq 0x156c0
jmp 0xc40c
movq -0x50(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x50(%rbp)
jmp 0xc378
movq -0x40(%rbp), %rax
subq -0x20(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x10(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rdi
callq 0x15780
movq %rax, -0x78(%rbp)
movq -0x70(%rbp), %rdi
callq 0x157a0
movq %rax, -0x80(%rbp)
movq -0x78(%rbp), %rax
cmpq -0x80(%rbp), %rax
je 0xc5e8
movq -0x78(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x88(%rbp)
movq -0x40(%rbp), %rcx
movq -0x88(%rbp), %rax
movq %rcx, 0x10(%rax)
leaq 0x185bf(%rip), %rax     # 0x24a48
testb $0x1, 0x3(%rax)
je 0xc4ba
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
movq -0x88(%rbp), %rax
movq (%rax), %rdx
movq -0x88(%rbp), %rax
movq 0x10(%rax), %rcx
leaq 0xf367(%rip), %rdi      # 0x1b81a
movb $0x0, %al
callq 0x2030
leaq 0xfbe1(%rip), %rdi      # 0x1c0a2
movb $0x0, %al
callq 0x5b70
movq -0x358(%rbp), %rcx
movq -0x88(%rbp), %rax
movq 0x8(%rax), %rax
cmpq 0x8(%rcx), %rax
jne 0xc4ff
leaq 0xdd7b(%rip), %rdi      # 0x1a262
movb $0x0, %al
callq 0x5b70
movq -0x40(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x40(%rbp)
jmp 0xc5d5
movq -0x358(%rbp), %rcx
movq -0x88(%rbp), %rax
movq 0x8(%rax), %rax
cmpq 0x10(%rcx), %rax
jne 0xc536
leaq 0xdd47(%rip), %rdi      # 0x1a265
movb $0x0, %al
callq 0x5b70
movq -0x40(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x40(%rbp)
jmp 0xc5d3
movq -0x358(%rbp), %rcx
movq -0x88(%rbp), %rax
movq 0x8(%rax), %rax
cmpq 0x18(%rcx), %rax
jne 0xc56a
leaq 0xdd14(%rip), %rdi      # 0x1a269
movb $0x0, %al
callq 0x5b70
movq -0x40(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x40(%rbp)
jmp 0xc5d1
movq -0x88(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x7960
movq %rax, -0x90(%rbp)
cmpq $0x0, -0x90(%rbp)
je 0xc58d
jmp 0xc5ac
leaq 0xf292(%rip), %rdi      # 0x1b826
leaq 0xf1c3(%rip), %rsi      # 0x1b75e
movl $0x156, %edx            # imm = 0x156
leaq 0xf286(%rip), %rcx      # 0x1b82d
callq 0x20d0
movq -0x90(%rbp), %rax
movq 0x8(%rax), %rsi
leaq 0xf2cc(%rip), %rdi      # 0x1b88a
movb $0x0, %al
callq 0x5b70
movq -0x40(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x40(%rbp)
jmp 0xc5d3
jmp 0xc5d5
jmp 0xc5d7
movq -0x78(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x78(%rbp)
jmp 0xc457
leaq 0xf2a7(%rip), %rdi      # 0x1b896
movb $0x0, %al
callq 0x5b70
movq -0x40(%rbp), %rax
subq -0x18(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x18(%rbp), %rax
addq -0x98(%rbp), %rax
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x80(%rax)
movq -0x20(%rbp), %rax
addq -0x68(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x28(%rbp), %rax
movq 0x1308(%rax), %rcx
movq %rcx, -0xb0(%rbp)
movq 0x1310(%rax), %rcx
movq %rcx, -0xa8(%rbp)
movq 0x1318(%rax), %rax
movq %rax, -0xa0(%rbp)
movq -0xa8(%rbp), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x70(%rax)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
movq -0xa8(%rbp), %rdx
leaq 0xf218(%rip), %rdi      # 0x1b89a
movb $0x0, %al
callq 0x5b70
movq $0x0, -0xb8(%rbp)
movq $0x0, -0xc0(%rbp)
movq -0xc0(%rbp), %rax
cmpq -0xa8(%rbp), %rax
jae 0xc762
movq -0xc0(%rbp), %rsi
leaq -0xb0(%rbp), %rdi
callq 0x157c0
movq (%rax), %rcx
movq %rcx, -0xd0(%rbp)
movq 0x8(%rax), %rax
movq %rax, -0xc8(%rbp)
leaq 0xf1d4(%rip), %rdi      # 0x1b8b6
movb $0x0, %al
callq 0x5b70
movq -0x10(%rbp), %rdi
movq -0xd0(%rbp), %rsi
callq 0x6210
movq -0xc8(%rbp), %rsi
movq -0xd0(%rbp), %rax
movq (%rax), %rdx
leaq 0xf1b3(%rip), %rdi      # 0x1b8c4
movb $0x0, %al
callq 0x5b70
movq -0xc0(%rbp), %rax
movq -0xa8(%rbp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
je 0xc73d
leaq 0xeeb9(%rip), %rdi      # 0x1b5ef
movb $0x0, %al
callq 0x5b70
leaq 0xe000(%rip), %rdi      # 0x1a744
movb $0x0, %al
callq 0x5b70
movq -0xc0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc0(%rbp)
jmp 0xc69f
leaq 0xe00e(%rip), %rdi      # 0x1a777
movb $0x0, %al
callq 0x5b70
movq -0x10(%rbp), %rax
cmpq $0x0, 0x88(%rax)
je 0xc780
jmp 0xc79f
leaq 0xf14e(%rip), %rdi      # 0x1b8d5
leaq 0xefd0(%rip), %rsi      # 0x1b75e
movl $0x173, %edx            # imm = 0x173
leaq 0xf093(%rip), %rcx      # 0x1b82d
callq 0x20d0
movq -0x10(%rbp), %rax
movq 0x88(%rax), %rax
movq (%rax), %rcx
movq %rcx, -0xe8(%rbp)
movq 0x8(%rax), %rcx
movq %rcx, -0xe0(%rbp)
movq 0x10(%rax), %rax
movq %rax, -0xd8(%rbp)
movq -0xe0(%rbp), %rax
movq %rax, -0xf0(%rbp)
cmpq $0x0, -0xf0(%rbp)
je 0xc9a4
leaq -0x108(%rbp), %rdi
callq 0x157f0
cmpq $0x1, -0xf0(%rbp)
jbe 0xc84d
movq -0x28(%rbp), %rsi
addq $0x1308, %rsi           # imm = 0x1308
leaq -0x328(%rbp), %rdi
callq 0x15820
movq -0x328(%rbp), %rax
movq %rax, -0x108(%rbp)
movq -0x320(%rbp), %rax
movq %rax, -0x100(%rbp)
movq -0x318(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0x28(%rbp), %rdi
leaq -0x310(%rbp), %rsi
callq 0x15880
leaq -0xe8(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x15910
movq -0x358(%rbp), %rdi
movq (%rax), %rsi
movq -0x18(%rbp), %rdx
movq -0x20(%rbp), %rcx
movq -0x28(%rbp), %r8
callq 0xc2c0
cmpq $0x1, -0xf0(%rbp)
jbe 0xc9a2
movq $0x1, -0x330(%rbp)
movq -0x330(%rbp), %rax
cmpq -0xf0(%rbp), %rax
jae 0xc9a0
movq -0x28(%rbp), %rax
movq -0x108(%rbp), %rcx
movq %rcx, 0x1308(%rax)
movq -0x100(%rbp), %rcx
movq %rcx, 0x1310(%rax)
movq -0xf8(%rbp), %rcx
movq %rcx, 0x1318(%rax)
movq -0x28(%rbp), %rdi
leaq -0x310(%rbp), %rsi
callq 0x15970
movq -0x330(%rbp), %rsi
leaq -0xe8(%rbp), %rdi
callq 0x15910
movq -0x358(%rbp), %rdi
movq (%rax), %rax
movq %rax, -0x338(%rbp)
movq -0x338(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x20(%rbp), %rcx
movq -0x28(%rbp), %r8
callq 0xc2c0
movq -0x28(%rbp), %rdi
addq $0x1308, %rdi           # imm = 0x1308
callq 0x15a00
movq -0x330(%rbp), %rax
movq -0xf0(%rbp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
je 0xc987
movq -0x28(%rbp), %rsi
addq $0x1308, %rsi           # imm = 0x1308
leaq -0x350(%rbp), %rdi
callq 0x15820
movq -0x350(%rbp), %rax
movq %rax, -0x108(%rbp)
movq -0x348(%rbp), %rax
movq %rax, -0x100(%rbp)
movq -0x340(%rbp), %rax
movq %rax, -0xf8(%rbp)
jmp 0xc989
movq -0x330(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x330(%rbp)
jmp 0xc891
jmp 0xc9a2
jmp 0xc9a4
movq -0x10(%rbp), %rdi
callq 0x15a50
addq $0x360, %rsp            # imm = 0x360
popq %rbp
retq
nopw %cs:(%rax,%rax)