2026-05-29 20:20:19 +01:00
|
|
|
#include <fx/type.h>
|
|
|
|
|
#include <fx/value-type.h>
|
2026-05-04 19:23:10 +01:00
|
|
|
#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
|
|
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
void callvm_reset(struct callvm *vm, unsigned int max_fixed_args)
|
2026-05-04 19:23:10 +01:00
|
|
|
{
|
2026-05-29 20:20:19 +01:00
|
|
|
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;
|
|
|
|
|
vm->vm_double_excess_count = 0;
|
2026-05-04 19:23:10 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
static void expand_excess(struct callvm *vm)
|
2026-05-04 19:23:10 +01:00
|
|
|
{
|
2026-05-29 20:20:19 +01:00
|
|
|
size_t new_capacity = vm->vm_arg_excess_max * 2;
|
|
|
|
|
if (!new_capacity) {
|
|
|
|
|
new_capacity = 4;
|
|
|
|
|
}
|
2026-05-04 19:23:10 +01:00
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
void *buf = realloc(
|
|
|
|
|
vm->vm_arg_excess,
|
|
|
|
|
new_capacity * sizeof *vm->vm_arg_excess);
|
2026-05-04 19:23:10 +01:00
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
if (!buf) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-05-04 19:23:10 +01:00
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
vm->vm_arg_excess = buf;
|
|
|
|
|
vm->vm_arg_excess_max = new_capacity;
|
2026-05-04 19:23:10 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
static void push_excess(struct callvm *vm, uintptr_t value)
|
2026-05-04 19:23:10 +01:00
|
|
|
{
|
2026-05-29 20:20:19 +01:00
|
|
|
if (vm->vm_arg_excess_count + 1 > vm->vm_arg_excess_max) {
|
|
|
|
|
expand_excess(vm);
|
|
|
|
|
}
|
2026-05-04 19:23:10 +01:00
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
vm->vm_arg_excess[vm->vm_arg_excess_count++] = value;
|
|
|
|
|
vm->vm_arg_count++;
|
2026-05-04 19:23:10 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
static void push_int(struct callvm *vm, uintptr_t value)
|
2026-05-04 19:23:10 +01:00
|
|
|
{
|
2026-05-29 20:20:19 +01:00
|
|
|
if (vm->vm_arg_int_count >= MAX_INT_ARGS) {
|
|
|
|
|
push_excess(vm, value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-05-04 19:23:10 +01:00
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
vm->vm_arg_int[vm->vm_arg_int_count++] = value;
|
|
|
|
|
vm->vm_arg_count++;
|
2026-05-04 19:23:10 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
static void push_double(struct callvm *vm, double value)
|
2026-05-04 19:23:10 +01:00
|
|
|
{
|
2026-05-29 20:20:19 +01:00
|
|
|
if (vm->vm_arg_double_count >= MAX_DOUBLE_ARGS) {
|
|
|
|
|
push_excess(vm, *(uintptr_t *)&value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-05-04 19:23:10 +01:00
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
vm->vm_arg_double[vm->vm_arg_double_count++] = value;
|
|
|
|
|
vm->vm_arg_count++;
|
2026-05-04 19:23:10 +01:00
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
if (vm->vm_arg_count > vm->vm_arg_fixed) {
|
|
|
|
|
vm->vm_double_excess_count++;
|
|
|
|
|
}
|
2026-05-04 19:23:10 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
void callvm_push(struct callvm *vm, const fx_value *value)
|
2026-05-04 19:23:10 +01:00
|
|
|
{
|
2026-05-29 20:20:19 +01:00
|
|
|
if (!fx_type_is_value_type(value->v_type)) {
|
|
|
|
|
push_int(vm, (uintptr_t)value->v_object);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int value_type = __fx_type_get_value_type(value->v_type);
|
|
|
|
|
|
|
|
|
|
switch (value_type) {
|
|
|
|
|
case __FX_VALUE_TYPE_BOOL:
|
|
|
|
|
push_int(vm, value->v_bool);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_I16:
|
|
|
|
|
push_int(vm, value->v_i16);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_U16:
|
|
|
|
|
push_int(vm, value->v_u16);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_I32:
|
|
|
|
|
push_int(vm, value->v_i32);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_U32:
|
|
|
|
|
push_int(vm, value->v_u32);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_I64:
|
|
|
|
|
push_int(vm, value->v_i64);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_U64:
|
|
|
|
|
push_int(vm, value->v_u64);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_IPTR:
|
|
|
|
|
push_int(vm, value->v_iptr);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_UPTR:
|
|
|
|
|
push_int(vm, value->v_uptr);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_SBYTE:
|
|
|
|
|
push_int(vm, value->v_sbyte);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_BYTE:
|
|
|
|
|
push_int(vm, value->v_byte);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_SHORT:
|
|
|
|
|
push_int(vm, value->v_short);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_USHORT:
|
|
|
|
|
push_int(vm, value->v_ushort);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_INT:
|
|
|
|
|
push_int(vm, value->v_int);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_UINT:
|
|
|
|
|
push_int(vm, value->v_uint);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_LONG:
|
|
|
|
|
push_int(vm, value->v_long);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_ULONG:
|
|
|
|
|
push_int(vm, value->v_ulong);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_LONGLONG:
|
|
|
|
|
push_int(vm, value->v_longlong);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_ULONGLONG:
|
|
|
|
|
push_int(vm, value->v_ulonglong);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_SIZE:
|
|
|
|
|
push_int(vm, value->v_size);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_FLOAT:
|
|
|
|
|
push_double(vm, value->v_float);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_DOUBLE:
|
|
|
|
|
push_double(vm, value->v_double);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_CSTR:
|
|
|
|
|
push_int(vm, (uintptr_t)value->v_cstr);
|
|
|
|
|
break;
|
|
|
|
|
case __FX_VALUE_TYPE_POINTER:
|
|
|
|
|
push_int(vm, (uintptr_t)value->v_pointer);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-05-04 19:23:10 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-29 20:20:19 +01:00
|
|
|
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);
|
2026-05-04 19:23:10 +01:00
|
|
|
|
|
|
|
|
fx_value callvm_invoke(
|
2026-05-29 20:20:19 +01:00
|
|
|
struct callvm *vm,
|
|
|
|
|
fx_function_impl impl,
|
|
|
|
|
fx_type_id return_type)
|
2026-05-04 19:23:10 +01:00
|
|
|
{
|
2026-05-29 20:20:19 +01:00
|
|
|
if (!fx_type_is_value_type(return_type)) {
|
|
|
|
|
uintptr_t v = callvm_invoke_i(impl, vm);
|
|
|
|
|
fx_value result = {
|
|
|
|
|
.v_type = return_type,
|
|
|
|
|
.v_object = (fx_object *)v,
|
|
|
|
|
};
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int value_type = __fx_type_get_value_type(return_type);
|
|
|
|
|
|
|
|
|
|
switch (value_type) {
|
|
|
|
|
case __FX_VALUE_TYPE_BOOL:
|
|
|
|
|
return FX_BOOL(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_I16:
|
|
|
|
|
return FX_I16(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_U16:
|
|
|
|
|
return FX_U16(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_I32:
|
|
|
|
|
return FX_I32(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_U32:
|
|
|
|
|
return FX_U32(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_I64:
|
|
|
|
|
return FX_I64(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_U64:
|
|
|
|
|
return FX_U64(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_IPTR:
|
|
|
|
|
return FX_IPTR(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_UPTR:
|
|
|
|
|
return FX_UPTR(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_SBYTE:
|
|
|
|
|
return FX_SBYTE(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_BYTE:
|
|
|
|
|
return FX_BYTE(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_SHORT:
|
|
|
|
|
return FX_SHORT(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_USHORT:
|
|
|
|
|
return FX_USHORT(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_INT:
|
|
|
|
|
return FX_INT(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_UINT:
|
|
|
|
|
return FX_UINT(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_LONG:
|
|
|
|
|
return FX_LONG(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_ULONG:
|
|
|
|
|
return FX_ULONG(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_LONGLONG:
|
|
|
|
|
return FX_LONGLONG(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_ULONGLONG:
|
|
|
|
|
return FX_ULONGLONG(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_SIZE:
|
|
|
|
|
return FX_SIZE(callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_FLOAT:
|
|
|
|
|
return FX_FLOAT(callvm_invoke_d(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_DOUBLE:
|
|
|
|
|
return FX_DOUBLE(callvm_invoke_d(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_CSTR:
|
|
|
|
|
return FX_CSTR((const char *)callvm_invoke_i(impl, vm));
|
|
|
|
|
case __FX_VALUE_TYPE_POINTER:
|
|
|
|
|
return FX_POINTER((void *)callvm_invoke_i(impl, vm));
|
|
|
|
|
default:
|
|
|
|
|
return FX_VALUE_EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FX_VALUE_EMPTY;
|
2026-05-04 19:23:10 +01:00
|
|
|
}
|