111 lines
2.3 KiB
C
111 lines
2.3 KiB
C
|
|
#include <platform/callvm.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
|
||
|
|
#if 0
|
||
|
|
switch (arg->v_type.t_primitive) {
|
||
|
|
case FX_VALUE_TYPE_DOUBLE:
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
callvm_push_int(&vm, (uintptr_t)arg->v_pointer);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
void callvm_reset(struct callvm *vm, unsigned int max_fixed_args)
|
||
|
|
{
|
||
|
|
vm->vm_arg_int_count = 0;
|
||
|
|
vm->vm_arg_double_count = 0;
|
||
|
|
vm->vm_arg_fixed = max_fixed_args;
|
||
|
|
vm->vm_arg_excess_count = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void expand_excess(struct callvm *vm)
|
||
|
|
{
|
||
|
|
size_t new_capacity = vm->vm_arg_excess_max * 2;
|
||
|
|
if (!new_capacity) {
|
||
|
|
new_capacity = 4;
|
||
|
|
}
|
||
|
|
|
||
|
|
void *buf = realloc(
|
||
|
|
vm->vm_arg_excess,
|
||
|
|
new_capacity * sizeof *vm->vm_arg_excess);
|
||
|
|
|
||
|
|
if (!buf) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
vm->vm_arg_excess = buf;
|
||
|
|
vm->vm_arg_excess_max = new_capacity;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void push_excess(struct callvm *vm, uintptr_t value)
|
||
|
|
{
|
||
|
|
if (vm->vm_arg_excess_count + 1 > vm->vm_arg_excess_max) {
|
||
|
|
expand_excess(vm);
|
||
|
|
}
|
||
|
|
|
||
|
|
vm->vm_arg_excess[vm->vm_arg_excess_count++] = value;
|
||
|
|
vm->vm_arg_count++;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void push_int(struct callvm *vm, uintptr_t value)
|
||
|
|
{
|
||
|
|
if (vm->vm_arg_int_count >= MAX_INT_ARGS) {
|
||
|
|
push_excess(vm, value);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
vm->vm_arg_int[vm->vm_arg_int_count++] = value;
|
||
|
|
vm->vm_arg_count++;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void push_double(struct callvm *vm, double value)
|
||
|
|
{
|
||
|
|
if (vm->vm_arg_double_count >= MAX_DOUBLE_ARGS) {
|
||
|
|
push_excess(vm, *(uintptr_t *)&value);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
vm->vm_arg_double[vm->vm_arg_double_count++] = value;
|
||
|
|
vm->vm_arg_count++;
|
||
|
|
}
|
||
|
|
|
||
|
|
void callvm_push(struct callvm *vm, const fx_value *value)
|
||
|
|
{
|
||
|
|
if (vm->vm_arg_count >= vm->vm_arg_fixed) {
|
||
|
|
push_excess(vm, (uintptr_t)value->v_pointer);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (value->v_type.t_primitive) {
|
||
|
|
case FX_VALUE_TYPE_DOUBLE:
|
||
|
|
push_double(vm, value->v_double);
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
push_int(vm, (uintptr_t)value->v_pointer);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
extern uintptr_t callvm_invoke_i(fx_function_impl impl, struct callvm *vm);
|
||
|
|
extern double callvm_invoke_d(fx_function_impl impl, struct callvm *vm);
|
||
|
|
extern void callvm_invoke_v(fx_function_impl impl, struct callvm *vm);
|
||
|
|
|
||
|
|
fx_value callvm_invoke(
|
||
|
|
struct callvm *vm,
|
||
|
|
fx_function_impl impl,
|
||
|
|
fx_value_type return_type)
|
||
|
|
{
|
||
|
|
switch (return_type) {
|
||
|
|
case FX_VALUE_TYPE_NONE:
|
||
|
|
callvm_invoke_v(impl, vm);
|
||
|
|
break;
|
||
|
|
case FX_VALUE_TYPE_DOUBLE:
|
||
|
|
return FX_VALUE_DOUBLE(callvm_invoke_d(impl, vm));
|
||
|
|
default:
|
||
|
|
return FX_VALUE_INT(callvm_invoke_i(impl, vm));
|
||
|
|
}
|
||
|
|
|
||
|
|
return FX_VALUE_EMPTY;
|
||
|
|
}
|