// File: /workspace/github_c_makefile_star2_O3/adamjedlicka[P]blu/src/vm/vm.c
// Function: callValue
static bool callValue(bluVM* vm, bluValue callee, int8_t argCount) {
	if (!IS_OBJ(callee)) {
		runtimeError(vm, "Can only call functions and classes.");
		return false;
	}

	switch (OBJ_TYPE(callee)) {

	case OBJ_BOUND_METHOD: {
		bluObjBoundMethod* boundMethod = AS_BOUND_METHOD(callee);

		// Replace the bound method with the new receiver so it's in the right slot when the method is called.
		vm->stackTop[-argCount - 1] = boundMethod->receiver;
		return call(vm, boundMethod->closure, argCount);
	}

	case OBJ_CLASS: {
		bluObjClass* class = AS_CLASS(callee);

		// Create the instance.
		vm->stackTop[-argCount - 1] = OBJ_VAL(bluNewInstance(vm, class));

		// Call the initializer, if there is one.
		bluValue initializer;
		if (bluTableGet(vm, &class->methods, vm->stringInitializer, &initializer)) {
			if (!callValue(vm, initializer, argCount)) {
				return false;
			}
		} else if (argCount != 0) {
			runtimeError(vm, "Expected 0 arguments but got %d.", argCount);
			return false;
		}

		if (class->construct != NULL) {
			class->construct(vm, AS_INSTANCE(vm->stackTop[-argCount - 1]));
		}

		return true;
	}

	case OBJ_CLOSURE: {
		return call(vm, AS_CLOSURE(callee), argCount);
	}

	case OBJ_NATIVE: {
		bluObjNative* native = AS_NATIVE(callee);

		if (argCount < native->arity) {
			runtimeError(vm, "Expected %d arguments but got %d.", native->arity, argCount);
			return false;
		}

		int8_t result = native->function(vm, argCount, vm->stackTop - argCount - 1);
		if (result < 0) {
			runtimeError(vm, "Something went wrong.");
			return false;
		}

		vm->stackTop -= argCount + 1 - result;

		return true;
	}

	default: {
		runtimeError(vm, "Can only call functions and classes.");
		return false;
	}
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rdi, %rbx
cmpl $0x3, %esi
jne 0x8be7
movq %rdx, %r14
movl (%rdx), %eax
decl %eax
cmpl $0x5, %eax
ja 0x8be7
movl %ecx, %ebp
leaq 0x2048(%rip), %rcx      # 0xaaf8
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x100000(%rbx), %rax
movsbl %bpl, %edx
notb %bpl
movsbq %bpl, %rcx
shlq $0x4, %rcx
movups 0x20(%r14), %xmm0
movups %xmm0, (%rax,%rcx)
movq 0x30(%r14), %rsi
movq %rbx, %rdi
jmp 0x8aeb
movsbl %bpl, %edx
movq %rbx, %rdi
movq %r14, %rsi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x8e30
movsbl %bpl, %r15d
movsbl 0x20(%r14), %edx
cmpb %r15b, %dl
jg 0x8c0b
movq 0x100000(%rbx), %rax
movsbq %r15b, %rcx
shlq $0x4, %rcx
negq %rcx
leaq (%rax,%rcx), %rdx
addq $-0x10, %rdx
movq %rbx, %rdi
movl %r15d, %esi
callq *0x28(%r14)
testb %al, %al
js 0x8c23
movzbl %al, %eax
notl %r15d
addl %eax, %r15d
movslq %r15d, %rax
shlq $0x4, %rax
addq %rax, 0x100000(%rbx)
movb $0x1, %bpl
jmp 0x8bfa
movq 0x100000(%rbx), %r13
movsbl %bpl, %r15d
movl %r15d, %eax
notl %eax
movslq %eax, %r12
shlq $0x4, %r12
movq %rbx, %rdi
movq %r14, %rsi
callq 0x6510
movl $0x3, (%r13,%r12)
movq %rax, 0x8(%r13,%r12)
leaq 0x30(%r14), %rsi
movq 0x101870(%rbx), %rdx
leaq 0x8(%rsp), %rcx
movq %rbx, %rdi
callq 0x707c
testb %al, %al
je 0x8bc3
movl 0x8(%rsp), %esi
movq 0x10(%rsp), %rdx
movq %rbx, %rdi
movl %r15d, %ecx
callq 0x8a7d
testb %al, %al
jne 0x8bc8
xorl %ebp, %ebp
jmp 0x8bfa
testb %bpl, %bpl
jne 0x8c2c
movq 0x50(%r14), %rax
movb $0x1, %bpl
testq %rax, %rax
je 0x8bfa
movq 0x100000(%rbx), %rcx
movq 0x8(%rcx,%r12), %rsi
movq %rbx, %rdi
callq *%rax
jmp 0x8bfa
leaq 0x1f32(%rip), %rsi      # 0xab20
xorl %ebp, %ebp
movq %rbx, %rdi
xorl %eax, %eax
callq 0x2348
movl %ebp, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x1f54(%rip), %rsi      # 0xab66
xorl %ebp, %ebp
movq %rbx, %rdi
movl %r15d, %ecx
xorl %eax, %eax
callq 0x2348
jmp 0x8bfa
leaq 0x1f5e(%rip), %rsi      # 0xab88
jmp 0x8bee
leaq 0x1f12(%rip), %rsi      # 0xab45
xorl %ebp, %ebp
movq %rbx, %rdi
movl %r15d, %edx
xorl %eax, %eax
callq 0x2348
jmp 0x8bfa