// File: /workspace/github_cpp_makefile_star2_O2/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
xorl %eax, %eax
leaq 0x8(%rsp), %r14
movl %eax, 0x810(%rbx)
movq 0x808(%rbx), %rdi
movl %eax, %esi
callq 0x1ed8
movl (%rax), %eax
cmpq $0x6, %rax
ja 0x1dd0
leaq 0x1575(%rip), %rcx      # 0x30b0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x808(%rbx), %rdi
leaq 0x18(%rdi), %r14
movl 0x810(%rbx), %esi
incl %esi
movl %esi, 0x810(%rbx)
callq 0x1ed8
movl (%rax), %esi
movq %r14, %rdi
leaq 0x8(%rsp), %r14
callq 0x1efa
movq (%rax), %rax
movl 0x800(%rbx), %ecx
leal 0x1(%rcx), %edx
movl %edx, 0x800(%rbx)
movq %rax, (%rbx,%rcx,8)
jmp 0x1dd0
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movq (%rbx,%rcx,8), %r15
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r12
movq %r15, %rdi
callq 0x2340
ucomiss 0x14f7(%rip), %xmm0     # 0x30ac
jne 0x1bbd
jnp 0x1e0a
pushq $0x10
popq %rdi
callq 0x10d0
movq %rax, %r14
movq %r12, %rdi
callq 0x2340
movss %xmm0, 0x4(%rsp)
movq %r15, %rdi
callq 0x2340
jmp 0x1da4
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movq (%rbx,%rcx,8), %r15
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r12
pushq $0x10
popq %rdi
callq 0x10d0
movq %rax, %r14
movq %r12, %rdi
callq 0x2340
movss %xmm0, 0x4(%rsp)
movq %r15, %rdi
callq 0x2340
movss 0x4(%rsp), %xmm1
subss %xmm0, %xmm1
jmp 0x1dae
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movq (%rbx,%rcx,8), %r12
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r15
cmpb $0x3, (%r15)
movb (%r12), %bpl
jne 0x1d59
cmpb $0x3, %bpl
je 0x1e13
pushq $0x10
popq %rdi
callq 0x10d0
movq %rax, %r14
movq 0x8(%r15), %r15
movq %r12, %rdi
callq 0x2340
cvttss2si %xmm0, %rsi
movq %r15, %rdi
callq 0x1e78
jmp 0x1d84
movl 0x800(%rbx), %eax
leal -0x1(%rax), %ecx
movq (%rbx,%rcx,8), %rbp
addl $-0x2, %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %r15
cmpb $0x3, (%rbp)
je 0x1cb2
cmpb $0x3, (%r15)
jne 0x1ddd
pushq $0x10
popq %rdi
callq 0x10d0
movq %rax, %r14
pushq $0x20
popq %rdi
callq 0x10d0
movq %rax, %r12
leaq 0x8(%rsp), %rdi
movq %r15, %rsi
callq 0x23b6
leaq 0x28(%rsp), %r13
movq %r13, %rdi
movq %rbp, %rsi
callq 0x23b6
movq %r12, %rdi
leaq 0x8(%rsp), %r15
movq %r15, %rsi
movq %r13, %rdx
callq 0x1f1b
movb $0x3, (%r14)
movq %r12, 0x8(%r14)
movl 0x800(%rbx), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq %r14, (%rbx,%rax,8)
movq %r13, %rdi
callq 0x1060
movq %r15, %rdi
callq 0x1060
movq %r15, %r14
jmp 0x1dd0
movl 0x800(%rbx), %eax
decl %eax
movl %eax, 0x800(%rbx)
movq (%rbx,%rax,8), %rsi
movq %r14, %rdi
callq 0x23b6
movq 0x8(%rsp), %rdi
callq 0x1130
movq %r14, %rdi
callq 0x1060
jmp 0x1dd0
pushq $0x10
popq %rdi
callq 0x10d0
movq %rax, %r14
cmpb $0x3, %bpl
jne 0x1d8e
movq 0x8(%r12), %r12
movq %r15, %rdi
callq 0x2340
cvttss2si %xmm0, %rsi
movq %r12, %rdi
callq 0x1e78
movb $0x3, (%r14)
movq %rax, 0x8(%r14)
jmp 0x1db8
movq %r15, %rdi
callq 0x2340
movss %xmm0, 0x4(%rsp)
movq %r12, %rdi
callq 0x2340
movss 0x4(%rsp), %xmm1
mulss %xmm0, %xmm1
movb $0x1, (%r14)
movss %xmm1, 0x8(%r14)
movl 0x800(%rbx), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x800(%rbx)
movq %r14, (%rbx,%rax,8)
leaq 0x8(%rsp), %r14
movl 0x810(%rbx), %eax
incl %eax
jmp 0x1b14
pushq $0x10
popq %rdi
callq 0x10d0
movq %rax, %r14
movq %r15, %rdi
callq 0x2340
movss %xmm0, 0x4(%rsp)
movq %rbp, %rdi
callq 0x2340
movss 0x4(%rsp), %xmm1
addss %xmm0, %xmm1
jmp 0x1dae
leaq 0x1305(%rip), %rdi      # 0x3116
jmp 0x1e1a
leaq 0x1321(%rip), %rdi      # 0x313b
callq 0x1130
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x1e65
jmp 0x1e65
jmp 0x1e65
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x1060
jmp 0x1e46
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x1060
jmp 0x1e57
jmp 0x1e65
movq %rax, %rbx
movq %r12, %rdi
callq 0x10c0
jmp 0x1e68
jmp 0x1e65
jmp 0x1e65
movq %rax, %rbx
movq %r14, %rdi
callq 0x10c0
movq %rbx, %rdi
callq 0x1160