// File: /workspace/github_cpp_makefile_star2_O3/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 0x2116
leaq 0x136f(%rip), %r15      # 0x30d0
movl (%rcx,%rsi,4), %edi
cmpq $0x6, %rdi
ja 0x20ea
movslq (%r15,%rdi,4), %rdi
addq %r15, %rdi
jmpq *%rdi
incl %esi
movl %esi, 0x810(%rbx)
cmpq %rsi, %rdx
jbe 0x2116
movl (%rcx,%rsi,4), %esi
movq 0x18(%rax), %rcx
movq 0x20(%rax), %rdx
subq %rcx, %rdx
sarq $0x3, %rdx
cmpq %rsi, %rdx
jbe 0x2116
movq (%rcx,%rsi,8), %rax
movl 0x800(%rbx), %ecx
leal 0x1(%rcx), %edx
movl %edx, 0x800(%rbx)
movq %rax, (%rbx,%rcx,8)
jmp 0x20ea
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movq (%rbx,%rcx,8), %r14
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r12
movq %r14, %rdi
callq 0x25c8
ucomiss 0x12e4(%rip), %xmm0     # 0x30cc
jne 0x1df0
jnp 0x2124
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movq %r12, %rdi
callq 0x25c8
movss %xmm0, 0x4(%rsp)
movq %r14, %rdi
callq 0x25c8
jmp 0x1ff6
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movq (%rbx,%rcx,8), %r14
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r12
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movq %r12, %rdi
callq 0x25c8
movss %xmm0, 0x4(%rsp)
movq %r14, %rdi
callq 0x25c8
movss 0x4(%rsp), %xmm1
subss %xmm0, %xmm1
jmp 0x2000
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movq (%rbx,%rcx,8), %r14
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r12
cmpb $0x3, (%r12)
movb (%r14), %bpl
jne 0x1fa9
cmpb $0x3, %bpl
je 0x212d
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movq 0x8(%r12), %r12
movq %r14, %rdi
callq 0x25c8
cvttss2si %xmm0, %rsi
movq %r12, %rdi
callq 0x21a6
jmp 0x1fd5
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movq (%rbx,%rcx,8), %r14
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r12
cmpb $0x3, (%r14)
je 0x1eed
cmpb $0x3, (%r12)
jne 0x2023
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movl $0x20, %edi
callq 0x10c0
movq %rax, %rbp
leaq 0x8(%rsp), %rdi
movq %r12, %rsi
callq 0x2636
leaq 0x28(%rsp), %rdi
movq %r14, %rsi
callq 0x2636
movq 0x8(%rsp), %rcx
movl $0xf, %edi
leaq 0x18(%rsp), %rax
cmpq %rax, %rcx
je 0x1f3a
movq 0x18(%rsp), %rdi
movq 0x10(%rsp), %r8
movq 0x28(%rsp), %rsi
movq 0x30(%rsp), %rdx
leaq (%rdx,%r8), %rax
cmpq %rdi, %rax
jbe 0x1f6f
movl $0xf, %edi
leaq 0x38(%rsp), %r9
cmpq %r9, %rsi
je 0x1f66
movq 0x38(%rsp), %rdi
cmpq %rdi, %rax
jbe 0x2052
leaq 0x8(%rsp), %rdi
callq 0x1040
jmp 0x2060
movl 0x800(%rbx), %eax
decl %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %rsi
leaq 0x8(%rsp), %rdi
callq 0x2636
movq 0x8(%rsp), %rdi
callq 0x1110
jmp 0x20d6
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
cmpb $0x3, %bpl
jne 0x1fe0
movq 0x8(%r14), %r14
movq %r12, %rdi
callq 0x25c8
cvttss2si %xmm0, %rsi
movq %r14, %rdi
callq 0x21a6
movb $0x3, (%r13)
movq %rax, 0x8(%r13)
jmp 0x200b
movq %r12, %rdi
callq 0x25c8
movss %xmm0, 0x4(%rsp)
movq %r14, %rdi
callq 0x25c8
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 0x20ea
movl $0x10, %edi
callq 0x10c0
movq %rax, %r13
movq %r12, %rdi
callq 0x25c8
movss %xmm0, 0x4(%rsp)
movq %r14, %rdi
callq 0x25c8
movss 0x4(%rsp), %xmm1
addss %xmm0, %xmm1
jmp 0x2000
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 0x2084
movq %rsi, (%rbp)
movq (%rcx), %rdx
movq %rdx, 0x10(%rbp)
jmp 0x208a
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 0x20d6
callq 0x10b0
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x20ea
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 0x1d61
leaq 0xfcf(%rip), %rdi       # 0x30ec
xorl %eax, %eax
callq 0x1100
leaq 0x100b(%rip), %rdi      # 0x3136
jmp 0x2134
leaq 0x1027(%rip), %rdi      # 0x315b
callq 0x1110
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2193
jmp 0x2193
jmp 0x2193
movq %rax, %rbx
jmp 0x216a
movq %rax, %rbx
movq 0x28(%rsp), %rdi
leaq 0x38(%rsp), %rax
cmpq %rax, %rdi
je 0x216a
callq 0x10b0
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x2185
callq 0x10b0
jmp 0x2185
jmp 0x2193
movq %rax, %rbx
movq %rbp, %rdi
callq 0x10b0
jmp 0x2196
jmp 0x2193
jmp 0x2193
movq %rax, %rbx
movq %r13, %rdi
callq 0x10b0
movq %rbx, %rdi
callq 0x1130