// File: /workspace/github_c_makefile_star2_O2/naleksiev[P]fin/src/fin_vm.c
// Function: fin_vm_interpret
void fin_vm_interpret(fin_ctx_t* ctx, fin_mod_func_t* func, fin_val_t* stack) {
    fin_mod_t* mod  = func->mod;
    fin_val_t* args = stack - func->args;
    fin_val_t* top  = stack + func->locals;
    uint8_t* ip   = func->code;

    FIN_VM_LOOP_BEGIN() {
        FIN_VM_OP(fin_op_load_const) {
            int32_t idx = *ip++;
            idx |= *ip++ << 8;
            *top++ = mod->consts[idx];
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_load_arg) {
            *top++ = args[*ip++];
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_store_arg) {
            args[*ip++] = *--top;
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_load_local) {
            *top++ = stack[*ip++];
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_store_local) {
            stack[*ip++] = *--top;
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_load_field) {
            if (top[-1].o)
                top[-1] = top[-1].o->fields[*ip++];
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_store_field) {
            if (top[-2].o)
                top[-2].o->fields[*ip++] = top[-1];
            top -= 2;
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_call) {
            int32_t idx = *ip++;
            idx |= *ip++ << 8;
            fin_mod_func_t* func = mod->binds[idx].func;
            fin_vm_invoke_int(ctx, func, top);
            top -= func->args - (func->ret_type ? 1 : 0);
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_branch) {
            int16_t offset = *ip++;
            offset |= *ip++ << 8;
            ip += offset;
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_branch_if) {
            if ((--top)->b) {
                int16_t offset = *ip++;
                offset |= *ip++ << 8;
                ip += offset;
            } else
                ip += 2;
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_branch_if_n) {
            if ((--top)->b)
                ip += 2;
            else {
                int16_t offset = *ip++;
                offset |= *ip++ << 8;
                ip += offset;
            }
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_return) {
            if (func->ret_type)
                args[0] = top[-1];
            return;
        }
        FIN_VM_OP(fin_op_pop) {
            top--;
            FIN_VM_NEXT();
        }
        FIN_VM_OP(fin_op_new) {
            top -= *ip;
            top->o = fin_obj_create(ctx->alloc, top, *ip);
            top++;
            ip++;
            FIN_VM_NEXT();
        }
    }
    FIN_VM_LOOP_END();
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rdx, %r14
movq %rdi, -0x30(%rbp)
movq (%rsi), %r13
movq 0x28(%rsi), %r15
movzbl 0x34(%rsi), %eax
shll $0x3, %eax
movq %rdx, %rbx
subq %rax, %rbx
movq %rsi, -0x38(%rbp)
movzbl 0x35(%rsi), %eax
leaq (%rdx,%rax,8), %r12
movzbl (%r15), %eax
incq %r15
leaq 0x5d2a(%rip), %rdi      # 0xd8b0
movq %rbx, -0x48(%rbp)
movq %rdx, -0x40(%rbp)
jmpq *(%rdi,%rax,8)
movzwl (%r15), %eax
leaq 0x2(%r15), %rcx
movq 0x18(%r13), %rdx
movq (%rdx,%rax,8), %rax
movq %rax, (%r12)
addq $0x8, %r12
addq $0x3, %r15
movzbl (%rcx), %eax
jmpq *(%rdi,%rax,8)
leaq 0x1(%r15), %rax
movzbl (%r15), %ecx
movq (%rbx,%rcx,8), %rcx
movq %rcx, (%r12)
addq $0x8, %r12
addq $0x2, %r15
movzbl (%rax), %eax
jmpq *(%rdi,%rax,8)
leaq 0x1(%r15), %rax
movzbl (%r15), %ecx
movq -0x8(%r12), %rdx
addq $-0x8, %r12
movq %rdx, (%rbx,%rcx,8)
addq $0x2, %r15
movzbl (%rax), %eax
jmpq *(%rdi,%rax,8)
leaq 0x1(%r15), %rax
movzbl (%r15), %ecx
movq (%r14,%rcx,8), %rcx
movq %rcx, (%r12)
addq $0x8, %r12
addq $0x2, %r15
movzbl (%rax), %eax
jmpq *(%rdi,%rax,8)
leaq 0x1(%r15), %rax
movzbl (%r15), %ecx
movq -0x8(%r12), %rdx
addq $-0x8, %r12
movq %rdx, (%r14,%rcx,8)
addq $0x2, %r15
movzbl (%rax), %eax
jmpq *(%rdi,%rax,8)
movq -0x8(%r12), %rax
testq %rax, %rax
je 0x7c48
movzbl (%r15), %ecx
incq %r15
movq 0x8(%rax,%rcx,8), %rax
movq %rax, -0x8(%r12)
movzbl (%r15), %eax
incq %r15
jmpq *(%rdi,%rax,8)
leaq -0x10(%r12), %rax
movq -0x10(%r12), %rcx
testq %rcx, %rcx
je 0x7c72
movzbl (%r15), %edx
incq %r15
movq -0x8(%r12), %rsi
movq %rsi, 0x8(%rcx,%rdx,8)
movzbl (%r15), %ecx
incq %r15
movq %rax, %r12
jmpq *(%rdi,%rcx,8)
movzwl (%r15), %eax
leaq 0x2(%r15), %r14
movq 0x20(%r13), %rcx
shll $0x4, %eax
movq %r13, %rbx
movq 0x8(%rcx,%rax), %r13
movq -0x30(%rbp), %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x7dba
leaq 0x5c04(%rip), %rdi      # 0xd8b0
movzbl 0x34(%r13), %eax
cmpq $0x1, 0x8(%r13)
movq %rbx, %r13
adcq $-0x1, %rax
negq %rax
leaq (%r12,%rax,8), %r12
addq $0x3, %r15
movzbl (%r14), %eax
movq -0x40(%rbp), %r14
movq -0x48(%rbp), %rbx
jmpq *(%rdi,%rax,8)
movswq (%r15), %rax
leaq (%r15,%rax), %rcx
addq $0x2, %rcx
addq %rax, %r15
addq $0x3, %r15
movzbl (%rcx), %eax
jmpq *(%rdi,%rax,8)
cmpb $0x1, -0x8(%r12)
leaq -0x8(%r12), %r12
jne 0x7d12
movswq (%r15), %rax
addq %rax, %r15
addq $0x2, %r15
movzbl (%r15), %eax
incq %r15
jmpq *(%rdi,%rax,8)
addq $0x2, %r15
movzbl (%r15), %eax
incq %r15
jmpq *(%rdi,%rax,8)
cmpb $0x1, -0x8(%r12)
leaq -0x8(%r12), %r12
jne 0x7d3b
addq $0x2, %r15
movzbl (%r15), %eax
incq %r15
jmpq *(%rdi,%rax,8)
movswq (%r15), %rax
addq %rax, %r15
addq $0x2, %r15
movzbl (%r15), %eax
incq %r15
jmpq *(%rdi,%rax,8)
movq -0x38(%rbp), %rax
cmpq $0x0, 0x8(%rax)
je 0x7d63
movq -0x8(%r12), %rax
movq %rax, (%rbx)
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
addq $-0x8, %r12
movzbl (%r15), %eax
incq %r15
jmpq *(%rdi,%rax,8)
movzbl (%r15), %edx
leal (,%rdx,8), %eax
subq %rax, %r12
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq %r12, %rsi
callq 0x764c
leaq 0x5b0c(%rip), %rdi      # 0xd8b0
movq %rax, (%r12)
addq $0x8, %r12
leaq 0x1(%r15), %rax
addq $0x2, %r15
movzbl (%rax), %eax
jmpq *(%rdi,%rax,8)