#include #include #include #include #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; vm->vm_double_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++; if (vm->vm_arg_count > vm->vm_arg_fixed) { vm->vm_double_excess_count++; } } void callvm_push(struct callvm *vm, const fx_value *value) { 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; } } 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_type_id return_type) { 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)); #if FX_ENABLE_FLOATING_POINT 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)); #endif 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; }