// File: /workspace/github_cpp_makefile_star2_O1/ConsoleTVs[P]VirtualMachine/src/vm.cpp
// Function: VM::Instance::run()
void Instance::run()
{
    this->program_counter = 0;
    // The run basically is a big loop with a switch inside
    // We stop the loop when the exit OPCODE is found.
    for (uint32_t instruction;;this->program_counter++) {
        // Get need a way to get the instruction that we need to run
        // thus we need a program counter :)
        // This will get the current executing instruction
        instruction = GET_INSTRUCTION(this->program_counter);

        // Let's define what our opcodes actually do!
        switch (instruction) {
            case OP_CONSTANT: {
                // We add a new constant to the stack.
                // We got the index of the constant pool in the next program_counter
                //
                push(this->program->constants.at(GET_INSTRUCTION(++this->program_counter)));
                break;
            }
            case OP_ADD: {
                // We pop the last 2 values on the stack and further perform an addition
                Value *a = this->pop();
                Value *b = this->pop();

                // The following addition need to be done by a separate action, since two classes cannot be added!
                // We need a way to add two separate values of diferent types. An example would be to define them in
                // the class. As we defined a to_float method, we can now push a new value to the stack that's the
                // addition of the 2 poped values as a float. Keep in mind it's b - a, not a - b because of how
                // a stack works. First in, last out!

                // Check if you're adding a string at some of the operans:
                if (a->type == VALUE_STRING || b->type == VALUE_STRING) push(new Value(new std::string(b->to_string() + a->to_string())));
                else push(new Value(b->to_float() + a->to_float()));

                break;
            }
            case OP_SUB: {
                // We pop the last 2 values on the stack and further perform a substraction
                Value *a = this->pop();
                Value *b = this->pop();

                push(new Value(b->to_float() - a->to_float()));
                break;
            }
            case OP_MUL: {
                // We pop the last 2 values on the stack and further perform a multiplication
                Value *a = this->pop();
                Value *b = this->pop();

                // Check if we want to multiply a string.
                if (b->type == VALUE_STRING && a->type == VALUE_STRING) { printf("Can't multiply two strings\n"); return; }
                else if (b->type == VALUE_STRING) push(new Value(multiplyString(b->svalue, a->to_float())));
                else if (a->type == VALUE_STRING) push(new Value(multiplyString(a->svalue, b->to_float())));
                else push(new Value(b->to_float() * a->to_float()));

                break;
            }
            case OP_DIV: {
                // We pop the last 2 values on the stack and further perform a division
                Value *a = this->pop();
                Value *b = this->pop();

                // Keep in mind a division by 0 cannot be performed.
                // Let's check to avoid that:
                if (a->to_float() == 0) {
                    printf("A division by 0 was found. Aborting.\n");
                    return;
                }

                push(new Value(b->to_float() * a->to_float()));
                break;
            }
            case OP_PRINT: {
                // When the print opcode is found, we pop and print the last
                // value on the stack. So we need a way to represent the values as string
                auto value = pop();
                printf("%s\n", value->to_string().c_str());
                break;
            }
            case OP_EXIT: { return; }
        }
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rdi, %rbx
movl $0x0, 0x810(%rdi)
movq 0x808(%rdi), %rax
movq (%rax), %rcx
movq 0x8(%rax), %rdi
movq %rdi, %rdx
subq %rcx, %rdx
sarq $0x2, %rdx
xorl %esi, %esi
cmpq %rcx, %rdi
je 0x2246
leaq 0x12b3(%rip), %r14      # 0x30d0
movl (%rcx,%rsi,4), %edi
cmpq $0x6, %rdi
ja 0x221a
movslq (%r14,%rdi,4), %rdi
addq %r14, %rdi
jmpq *%rdi
incl %esi
movl %esi, 0x810(%rbx)
cmpq %rsi, %rdx
jbe 0x2246
movl (%rcx,%rsi,4), %esi
movq 0x18(%rax), %rcx
movq 0x20(%rax), %rdx
subq %rcx, %rdx
sarq $0x3, %rdx
cmpq %rsi, %rdx
jbe 0x2246
movq (%rcx,%rsi,8), %rax
movl 0x800(%rbx), %ecx
leal 0x1(%rcx), %edx
movl %edx, 0x800(%rbx)
movq %rax, (%rbx,%rcx,8)
jmp 0x221a
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq (%rbx,%rcx,8), %r15
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r12
movq %r15, %rdi
callq 0x26e4
movss %xmm0, (%rsp)
ucomiss 0x121d(%rip), %xmm0     # 0x30cc
jne 0x1eb7
jnp 0x20eb
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movq %r12, %rdi
callq 0x26e4
movss %xmm0, 0x4(%rsp)
movq %r15, %rdi
callq 0x26e4
movss 0x4(%rsp), %xmm1
mulss %xmm0, %xmm1
movb $0x1, (%r13)
movss %xmm1, 0x8(%r13)
movl 0x800(%rbx), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq %r13, (%rbx,%rax,8)
jmp 0x20f7
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq (%rbx,%rcx,8), %r15
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r12
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movq %r12, %rdi
callq 0x26e4
movss %xmm0, (%rsp)
movq %r15, %rdi
callq 0x26e4
movss (%rsp), %xmm1
subss %xmm0, %xmm1
jmp 0x215f
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq (%rbx,%rcx,8), %r12
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %rbp
movb (%rbp), %al
cmpb $0x3, %al
jne 0x20af
cmpb $0x3, (%r12)
je 0x2254
cmpb $0x3, %al
jne 0x20af
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movq 0x8(%rbp), %r15
movq %r12, %rdi
callq 0x26e4
cvttss2si %xmm0, %rsi
movq %r15, %rdi
callq 0x22cd
jmp 0x20e0
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq (%rbx,%rcx,8), %r12
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r15
cmpb $0x3, (%r12)
je 0x1ff1
cmpb $0x3, (%r15)
jne 0x2134
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movl $0x20, %edi
callq 0x10c0
movq %rax, %rbp
leaq 0x8(%rsp), %rdi
movq %r15, %rsi
callq 0x2752
leaq 0x28(%rsp), %rdi
movq %r12, %rsi
callq 0x2752
movq 0x8(%rsp), %rcx
movl $0xf, %esi
leaq 0x18(%rsp), %rax
cmpq %rax, %rcx
je 0x203e
movq 0x18(%rsp), %rsi
movq 0x10(%rsp), %r8
movq 0x30(%rsp), %rdx
leaq (%rdx,%r8), %rax
cmpq %rsi, %rax
jbe 0x2070
movl $0xf, %esi
leaq 0x38(%rsp), %rdi
cmpq %rdi, 0x28(%rsp)
je 0x2067
movq 0x38(%rsp), %rsi
cmpq %rsi, %rax
jbe 0x2182
movq 0x28(%rsp), %rsi
leaq 0x8(%rsp), %rdi
callq 0x1040
jmp 0x2190
movl 0x800(%rbx), %eax
decl %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %rsi
leaq 0x8(%rsp), %rdi
callq 0x2752
movq 0x8(%rsp), %rdi
callq 0x1110
jmp 0x2206
movb (%r12), %r15b
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
cmpb $0x3, %r15b
jne 0x2114
movq 0x8(%r12), %r15
movq %rbp, %rdi
callq 0x26e4
cvttss2si %xmm0, %rsi
movq %r15, %rdi
callq 0x22cd
movb $0x3, (%r13)
movq %rax, 0x8(%r13)
jmp 0x216a
leaq 0x1044(%rip), %rdi      # 0x3136
callq 0x1110
movss (%rsp), %xmm0
ucomiss 0xfc9(%rip), %xmm0      # 0x30cc
jne 0x221a
jp 0x221a
jmp 0x2260
movq %rbp, %rdi
callq 0x26e4
movss %xmm0, (%rsp)
movq %r12, %rdi
callq 0x26e4
movss (%rsp), %xmm1
mulss %xmm0, %xmm1
jmp 0x215f
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movq %r15, %rdi
callq 0x26e4
movss %xmm0, (%rsp)
movq %r12, %rdi
callq 0x26e4
movss (%rsp), %xmm1
addss %xmm0, %xmm1
movb $0x1, (%r13)
movss %xmm1, 0x8(%r13)
movl 0x800(%rbx), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq %r13, (%rbx,%rax,8)
jmp 0x221a
leaq 0x28(%rsp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x10d0
movq %rbp, %rdx
addq $0x10, %rdx
movq %rdx, (%rbp)
movq (%rax), %rsi
leaq 0x10(%rax), %rcx
cmpq %rcx, %rsi
je 0x21b4
movq %rsi, (%rbp)
movq (%rcx), %rdx
movq %rdx, 0x10(%rbp)
jmp 0x21ba
movups (%rcx), %xmm0
movups %xmm0, (%rdx)
movq %rax, %rdx
addq $0x8, %rdx
movq 0x8(%rax), %rsi
movq %rsi, 0x8(%rbp)
movq %rcx, (%rax)
movq $0x0, (%rdx)
movb $0x0, (%rcx)
movb $0x3, (%r13)
movq %rbp, 0x8(%r13)
movl 0x800(%rbx), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq %r13, (%rbx,%rax,8)
movq 0x28(%rsp), %rdi
leaq 0x38(%rsp), %rax
cmpq %rax, %rdi
je 0x2206
callq 0x10b0
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x221a
callq 0x10b0
movl 0x810(%rbx), %esi
incl %esi
movl %esi, 0x810(%rbx)
movq 0x808(%rbx), %rax
movq (%rax), %rcx
movq 0x8(%rax), %rdx
subq %rcx, %rdx
sarq $0x2, %rdx
cmpq %rsi, %rdx
ja 0x1e1d
leaq 0xe9f(%rip), %rdi       # 0x30ec
xorl %eax, %eax
callq 0x1100
leaq 0xf00(%rip), %rdi       # 0x315b
callq 0x1110
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x22ba
jmp 0x22ba
jmp 0x22ba
jmp 0x22ba
movq %rax, %rbx
jmp 0x2293
movq %rax, %rbx
movq 0x28(%rsp), %rdi
leaq 0x38(%rsp), %rax
cmpq %rax, %rdi
je 0x2293
callq 0x10b0
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x22ae
callq 0x10b0
jmp 0x22ae
jmp 0x22ba
movq %rax, %rbx
movq %rbp, %rdi
callq 0x10b0
jmp 0x22bd
jmp 0x22ba
movq %rax, %rbx
movq %r13, %rdi
callq 0x10b0
movq %rbx, %rdi
callq 0x1130