41#if defined(INFIX_OS_MACOS)
45#if defined(INFIX_OS_WINDOWS)
62#if defined(INFIX_ABI_WINDOWS_X64)
65#elif defined(INFIX_ABI_SYSV_X64)
68#elif defined(INFIX_ABI_AAPCS64)
81#if defined(INFIX_ABI_WINDOWS_X64)
83#elif defined(INFIX_ABI_SYSV_X64)
85#elif defined(INFIX_ABI_AAPCS64)
98#if defined(INFIX_ABI_WINDOWS_X64)
100#elif defined(INFIX_ABI_SYSV_X64)
102#elif defined(INFIX_ABI_AAPCS64)
132 if (len > SIZE_MAX - buf->
size) {
138 size_t new_capacity = buf->
capacity;
139 while (new_capacity < buf->size + len) {
140 if (new_capacity > SIZE_MAX / 2) {
148 if (new_code ==
nullptr) {
153 buf->
code = new_code;
218 if (trampoline ==
nullptr || trampoline->
target_fn !=
nullptr)
228 if (trampoline ==
nullptr || trampoline->
target_fn ==
nullptr)
255 size_t num_fixed_args,
258 if (out_trampoline ==
nullptr || (
arg_types ==
nullptr && num_args > 0))
266 for (
size_t i = 0; i < num_args; ++i) {
313 if (handle ==
nullptr) {
319 size_t required_size = source_arena ? source_arena->
current_offset : 8192;
321 if (handle->
arena ==
nullptr) {
333 for (
size_t i = 0; i < num_args; ++i) {
358 *out_trampoline = handle;
374 size_t num_fixed_args,
375 void * target_function) {
396 size_t num_fixed_args) {
407 if (trampoline ==
nullptr)
409 if (trampoline->
arena)
421#if defined(INFIX_OS_WINDOWS)
423 GetSystemInfo(&sysInfo);
424 return sysInfo.dwPageSize;
426 return sysconf(_SC_PAGESIZE);
447 size_t num_fixed_args,
448 void * user_callback_fn,
451 if (out_context ==
nullptr || num_fixed_args > num_args)
457 if (
arg_types ==
nullptr && num_args > 0)
459 for (
size_t i = 0; i < num_args; ++i) {
483 size_t context_alloc_size = (
sizeof(
infix_reverse_t) + page_size - 1) & ~(page_size - 1);
485 if (prot.
rw_ptr ==
nullptr) {
494 if (context->
arena ==
nullptr) {
503 context->
is_variadic = (num_fixed_args < num_args);
513 (num_args > 0 && context->
arg_types ==
nullptr)) {
517 for (
size_t i = 0; i < num_args; ++i) {
581 *out_context = context;
597 size_t num_fixed_args,
598 void * user_callback_fn) {
601 out_context,
return_type,
arg_types, num_args, num_fixed_args, user_callback_fn,
nullptr,
true);
611 size_t num_fixed_args,
616 out_context,
return_type,
arg_types, num_args, num_fixed_args, (
void *)user_callback_fn, user_data,
false);
623 if (reverse_trampoline ==
nullptr)
627 if (reverse_trampoline->
arena)
637 if (reverse_trampoline ==
nullptr)
646 if (reverse_trampoline ==
nullptr)
657 const char * signature,
658 void * target_function,
664 size_t num_args = 0, num_fixed = 0;
675 for (
size_t i = 0; i < num_args; ++i)
688 const char * signature,
697 const char * signature,
698 void * user_callback_fn,
704 size_t num_args = 0, num_fixed = 0;
715 for (
size_t i = 0; i < num_args; ++i)
727 const char * signature,
735 size_t num_args = 0, num_fixed = 0;
746 for (
size_t i = 0; i < num_args; ++i)
749 out_context,
ret_type,
arg_types, num_args, num_fixed, user_callback_fn, user_data);
761#if defined(INFIX_ABI_WINDOWS_X64)
762#include "../arch/x64/abi_win_x64.c"
763#include "../arch/x64/abi_x64_emitters.c"
764#elif defined(INFIX_ABI_SYSV_X64)
765#include "../arch/x64/abi_sysv_x64.c"
766#include "../arch/x64/abi_x64_emitters.c"
767#elif defined(INFIX_ABI_AAPCS64)
768#include "../arch/aarch64/abi_arm64.c"
769#include "../arch/aarch64/abi_arm64_emitters.c"
771#error "No supported ABI was selected for the unity build in trampoline.c."
infix_arena_t * arena
Definition 005_layouts.c:57
infix_status status
Definition 103_unions.c:74
void * args[]
Definition 202_in_structs.c:75
infix_type * return_type
Definition 202_in_structs.c:71
infix_type * arg_types[]
Definition 901_call_overhead.c:76
infix_type * ret_type
Definition 901_call_overhead.c:75
const infix_reverse_abi_spec g_arm64_reverse_spec
Definition abi_arm64.c:114
const infix_forward_abi_spec g_arm64_forward_spec
Definition abi_arm64.c:107
const infix_reverse_abi_spec g_sysv_x64_reverse_spec
Definition abi_sysv_x64.c:117
const infix_forward_abi_spec g_sysv_x64_forward_spec
Definition abi_sysv_x64.c:110
const infix_reverse_abi_spec g_win_x64_reverse_spec
The v-table of Windows x64 functions for generating reverse trampolines.
Definition abi_win_x64.c:107
const infix_forward_abi_spec g_win_x64_forward_spec
The v-table of Windows x64 functions for generating forward trampolines.
Definition abi_win_x64.c:99
#define c23_nodiscard
Definition compat_c23.h:93
@ INFIX_CODE_UNRESOLVED_NAMED_TYPE
The type graph that contains an unresolved named reference.
Definition infix.h:1078
@ INFIX_CODE_OUT_OF_MEMORY
Failure to allocate memory. Likely due to lack of system resources.
Definition infix.h:1061
@ INFIX_CATEGORY_ABI
An error related to ABI classification or JIT generation.
Definition infix.h:1044
@ INFIX_CATEGORY_ALLOCATION
An error related to memory allocation.
Definition infix.h:1042
c23_nodiscard infix_status infix_reverse_create_callback(infix_reverse_t **out_context, const char *signature, void *user_callback_fn, infix_registry_t *registry)
Implementation of the public infix_reverse_create_callback API function.
Definition trampoline.c:696
c23_nodiscard infix_status infix_forward_create_unbound(infix_forward_t **out_trampoline, const char *signature, infix_registry_t *registry)
Implementation of the public infix_forward_create_unbound API function.
Definition trampoline.c:687
c23_nodiscard infix_status infix_forward_create(infix_forward_t **out_trampoline, const char *signature, void *target_function, infix_registry_t *registry)
Implementation of the public infix_forward_create API function.
Definition trampoline.c:656
c23_nodiscard infix_status infix_reverse_create_closure(infix_reverse_t **out_context, const char *signature, infix_closure_handler_fn user_callback_fn, void *user_data, infix_registry_t *registry)
Implementation of the public infix_reverse_create_closure API function.
Definition trampoline.c:726
c23_nodiscard infix_status infix_signature_parse(const char *, infix_arena_t **, infix_type **, infix_function_argument **, size_t *, size_t *, infix_registry_t *)
Parses a full function signature string into its constituent infix_type parts.
Definition signature.c:1123
c23_nodiscard infix_cif_func infix_forward_get_code(infix_forward_t *trampoline)
Retrieves the executable code pointer from a bound forward trampoline.
Definition trampoline.c:227
c23_nodiscard void * infix_reverse_get_code(const infix_reverse_t *reverse_trampoline)
Retrieves the executable code pointer from a reverse trampoline.
Definition trampoline.c:636
c23_nodiscard infix_unbound_cif_func infix_forward_get_unbound_code(infix_forward_t *trampoline)
Retrieves the executable code pointer from an unbound forward trampoline.
Definition trampoline.c:217
c23_nodiscard void * infix_reverse_get_user_data(const infix_reverse_t *reverse_trampoline)
Retrieves the user_data stored with a reverse trampoline.
Definition trampoline.c:645
void infix_reverse_destroy(infix_reverse_t *reverse_trampoline)
Frees a reverse trampoline, its JIT-compiled stub, and its context.
Definition trampoline.c:622
c23_nodiscard infix_status infix_forward_create_manual(infix_forward_t **out_trampoline, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, void *target_function)
Generates a bound forward-call trampoline for a given function signature.
Definition trampoline.c:370
c23_nodiscard infix_status infix_reverse_create_callback_manual(infix_reverse_t **out_context, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, void *user_callback_fn)
Generates a type-safe reverse-call trampoline (callback) from infix_type objects.
Definition trampoline.c:593
c23_nodiscard infix_status infix_reverse_create_closure_manual(infix_reverse_t **out_context, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, infix_closure_handler_fn user_callback_fn, void *user_data)
Generates a generic reverse-call trampoline (closure) from infix_type objects.
Definition trampoline.c:607
c23_nodiscard infix_status infix_forward_create_unbound_manual(infix_forward_t **out_trampoline, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args)
Creates an "unbound" forward-call trampoline for a given function signature.
Definition trampoline.c:392
void infix_forward_destroy(infix_forward_t *trampoline)
Frees a forward trampoline and its associated executable memory.
Definition trampoline.c:406
#define infix_free
A macro for the memory deallocation function.
Definition infix.h:280
void infix_arena_destroy(infix_arena_t *)
Frees an entire memory arena and all objects allocated within it.
Definition arena.c:68
#define infix_memcpy
A macro for copying memory from a source to a destination pointer.
Definition infix.h:290
#define infix_calloc
A macro for the zero-initializing memory allocation function.
Definition infix.h:260
c23_nodiscard void * infix_arena_alloc(infix_arena_t *, size_t, size_t)
Allocates a block of memory from the arena with a specific alignment.
Definition arena.c:86
#define infix_memset
A macro for setting a block of memory to a specific value.
Definition infix.h:300
c23_nodiscard infix_arena_t * infix_arena_create(size_t)
Creates and initializes a new memory arena.
Definition arena.c:41
void(* infix_closure_handler_fn)(infix_context_t *context, void *return_value, void **args)
The signature for a generic "closure" handler.
Definition infix.h:346
void(* infix_cif_func)(void *, void **)
The signature for a "bound" forward-call trampoline.
Definition infix.h:335
void(* infix_unbound_cif_func)(void *, void *, void **)
The signature for a generic "unbound" forward-call trampoline.
Definition infix.h:315
infix_status
An enumeration of all possible success or failure codes from the public API.
Definition infix.h:351
@ INFIX_ERROR_ALLOCATION_FAILED
A memory allocation request failed.
Definition infix.h:353
@ INFIX_ERROR_PROTECTION_FAILED
Failed to change memory permissions (e.g., mprotect or VirtualProtect).
Definition infix.h:357
@ INFIX_ERROR_UNSUPPORTED_ABI
The current platform/ABI is not supported.
Definition infix.h:355
@ INFIX_SUCCESS
The operation completed successfully.
Definition infix.h:352
@ INFIX_ERROR_INVALID_ARGUMENT
An invalid argument was provided to a function.
Definition infix.h:354
@ INFIX_TYPE_UNION
A user-defined union (union).
Definition infix.h:118
@ INFIX_TYPE_ARRAY
A fixed-size array.
Definition infix.h:119
@ INFIX_TYPE_POINTER
A generic void* pointer type.
Definition infix.h:116
@ INFIX_TYPE_NAMED_REFERENCE
A reference to a named type (e.g., struct<Node>).
Definition infix.h:124
@ INFIX_TYPE_REVERSE_TRAMPOLINE
A callback wrapper.
Definition infix.h:120
@ INFIX_TYPE_STRUCT
A user-defined structure (struct).
Definition infix.h:117
#define INFIX_TRAMPOLINE_HEADROOM
Definition infix_config.h:200
Declarations for internal-only functions, types, and constants.
void infix_executable_free(infix_executable_t)
Frees executable memory, creating a guard page to prevent use-after-free.
Definition executor.c:388
c23_nodiscard bool infix_executable_make_executable(infix_executable_t)
Makes a JIT memory region readable and executable (and non-writable).
Definition executor.c:453
void _infix_set_error(infix_error_category_t, infix_error_code_t, size_t)
Sets the thread-local error details for a library-internal error.
Definition error.c:44
c23_nodiscard infix_executable_t infix_executable_alloc(size_t)
Allocates a page-aligned block of W^X-compliant executable memory.
Definition executor.c:286
infix_type * _copy_type_graph_to_arena(infix_arena_t *, const infix_type *)
Performs a deep copy of a type graph from one arena to another.
Definition types.c:610
c23_nodiscard infix_protected_t infix_protected_alloc(size_t)
Allocates a page-aligned block of data memory.
Definition executor.c:507
void _infix_clear_error(void)
Resets the thread-local error state. Called at the start of every public API function.
Definition error.c:76
void infix_protected_free(infix_protected_t)
Frees a block of protected data memory.
Definition executor.c:546
void infix_internal_dispatch_callback_fn_impl(infix_reverse_t *, void *, void **)
The high-level C dispatcher function called by reverse trampoline stubs.
Definition executor.c:610
c23_nodiscard bool infix_protected_make_readonly(infix_protected_t)
Hardens a block of protected data memory to be read-only.
Definition executor.c:577
Definition infix_internals.h:169
uint8_t * code
The buffer holding the machine code.
Definition infix_internals.h:170
bool error
A flag that is set if a memory allocation fails.
Definition infix_internals.h:173
size_t size
The current number of bytes written to the buffer.
Definition infix_internals.h:172
size_t capacity
The allocated capacity of the buffer.
Definition infix_internals.h:171
infix_arena_t * arena
The arena to use for allocations.
Definition infix_internals.h:174
Definition infix_internals.h:130
bool error
A sticky flag that is set if any allocation from this arena fails.
Definition infix_internals.h:134
size_t current_offset
The high-water mark; the offset of the next free byte.
Definition infix_internals.h:133
Definition infix_internals.h:234
size_t size
The total size of the allocated memory region in bytes.
Definition infix_internals.h:50
void * rw_ptr
Pointer with Read+Write permissions (where code is written).
Definition infix_internals.h:49
void * rx_ptr
Pointer with Read+Execute permissions (the callable address).
Definition infix_internals.h:48
Definition infix_internals.h:272
infix_status(* prepare_forward_call_frame)(infix_arena_t *, infix_call_frame_layout **, infix_type *, infix_type **, size_t, size_t, void *)
Analyzes a signature and produces a complete call frame layout.
Definition infix_internals.h:274
infix_status(* generate_forward_call_instruction)(code_buffer *, infix_call_frame_layout *)
Generates the call instruction (e.g., call rax).
Definition infix_internals.h:283
infix_status(* generate_forward_epilogue)(code_buffer *, infix_call_frame_layout *, infix_type *)
Generates the function epilogue, handling the return value and restoring the stack.
Definition infix_internals.h:285
infix_status(* generate_forward_prologue)(code_buffer *, infix_call_frame_layout *)
Generates the function prologue, including stack setup and saving registers.
Definition infix_internals.h:277
infix_status(* generate_forward_argument_moves)(code_buffer *, infix_call_frame_layout *, infix_type **, size_t, size_t)
Generates the instructions to move arguments from the generic void** array to their native locations.
Definition infix_internals.h:280
Definition infix_internals.h:72
infix_executable_t exec
Handle to the executable JIT-compiled stub.
Definition infix_internals.h:74
void * target_fn
If non-NULL, the hardcoded target function for a "bound" trampoline.
Definition infix_internals.h:79
size_t num_args
The total number of arguments.
Definition infix_internals.h:77
size_t num_fixed_args
The number of non-variadic arguments.
Definition infix_internals.h:78
infix_type ** arg_types
An array of infix_type pointers for each argument.
Definition infix_internals.h:76
infix_type * return_type
The infix_type of the trampoline's return value.
Definition infix_internals.h:75
infix_arena_t * arena
The arena that owns all the type metadata for this trampoline.
Definition infix_internals.h:73
Describes a single argument to a function, pairing an optional name with its type.
Definition infix.h:229
infix_type * type
An infix_type describing the argument's type.
Definition infix.h:231
Definition infix_internals.h:60
void * rw_ptr
A pointer to the read-write data memory.
Definition infix_internals.h:61
Definition infix_internals.h:158
Definition infix_internals.h:292
infix_status(* generate_reverse_argument_marshalling)(code_buffer *, infix_reverse_call_frame_layout *, infix_reverse_t *)
Generates instructions to save incoming arguments from registers/stack into a normalized format.
Definition infix_internals.h:298
infix_status(* prepare_reverse_call_frame)(infix_arena_t *, infix_reverse_call_frame_layout **, infix_reverse_t *)
Analyzes a callback signature and produces a stack layout for the JIT stub.
Definition infix_internals.h:294
infix_status(* generate_reverse_dispatcher_call)(code_buffer *, infix_reverse_call_frame_layout *, infix_reverse_t *)
Generates the call to the high-level C dispatcher function.
Definition infix_internals.h:302
infix_status(* generate_reverse_prologue)(code_buffer *, infix_reverse_call_frame_layout *)
Generates the stub's function prologue.
Definition infix_internals.h:296
infix_status(* generate_reverse_epilogue)(code_buffer *, infix_reverse_call_frame_layout *, infix_reverse_t *)
Generates the stub's epilogue, handling the return value and restoring the stack.
Definition infix_internals.h:306
Definition infix_internals.h:256
Definition infix_internals.h:102
infix_type * return_type
The infix_type of the callback's return value.
Definition infix_internals.h:106
void * user_data
Arbitrary user-data pointer associated with this callback.
Definition infix_internals.h:112
void * user_callback_fn
Pointer to the user's actual C callback handler function.
Definition infix_internals.h:111
infix_executable_t exec
Handle to the executable JIT-compiled entry stub.
Definition infix_internals.h:104
infix_internal_dispatch_callback_fn internal_dispatcher
Pointer to the C function that bridges from assembly.
Definition infix_internals.h:113
size_t num_args
The total number of arguments.
Definition infix_internals.h:108
size_t num_fixed_args
The number of non-variadic arguments.
Definition infix_internals.h:109
infix_protected_t protected_ctx
Handle to the memory where this very context struct resides.
Definition infix_internals.h:105
bool is_variadic
True if the function signature is variadic.
Definition infix_internals.h:110
infix_forward_t * cached_forward_trampoline
A pre-compiled forward trampoline for calling a type-safe user C callback.
Definition infix_internals.h:123
infix_arena_t * arena
The arena that owns all type metadata for this callback.
Definition infix_internals.h:103
infix_type ** arg_types
An array of infix_type pointers for each argument.
Definition infix_internals.h:107
infix_type * type
An infix_type describing the member's type.
Definition infix.h:221
The central structure for describing any data type in the FFI system.
Definition infix.h:161
struct infix_type_t::@0::@1 pointer_info
For INFIX_TYPE_POINTER.
union infix_type_t::@0 meta
Type-specific metadata.
struct infix_type_t::@0::@4 func_ptr_info
For INFIX_TYPE_REVERSE_TRAMPOLINE.
infix_struct_member * members
Array of members for the aggregate.
Definition infix.h:177
infix_function_argument * args
Array of function arguments (name and type).
Definition infix.h:188
infix_type_category category
The fundamental category of the type.
Definition infix.h:162
struct infix_type_t::@0::@2 aggregate_info
For INFIX_TYPE_STRUCT and INFIX_TYPE_UNION.
struct infix_type_t::@0::@3 array_info
For INFIX_TYPE_ARRAY.
struct infix_type_t * pointee_type
The type this pointer points to.
Definition infix.h:172
struct infix_type_t * element_type
The type of elements in the array.
Definition infix.h:182
struct infix_type_t * return_type
Reverse trampoline return value.
Definition infix.h:187
size_t num_members
Number of members in the aggregate.
Definition infix.h:178
size_t num_args
The total number of fixed and variadic arguments.
Definition infix.h:189
void emit_byte(code_buffer *buf, uint8_t byte)
Appends a single byte to a code buffer.
Definition trampoline.c:161
c23_nodiscard infix_status _infix_forward_create_internal(infix_forward_t **out_trampoline, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, infix_arena_t *source_arena, void *target_fn)
The internal core logic for creating a forward trampoline.
Definition trampoline.c:251
const infix_forward_abi_spec * get_current_forward_abi_spec()
Gets the ABI v-table for the current target platform (forward calls).
Definition trampoline.c:80
void code_buffer_init(code_buffer *buf, infix_arena_t *arena)
Initializes a code buffer for JIT code generation.
Definition trampoline.c:114
static bool _is_type_graph_resolved(infix_type *type)
Definition trampoline.c:184
void emit_int64(code_buffer *buf, int64_t value)
Appends a 64-bit integer to a code buffer.
Definition trampoline.c:171
static infix_status _infix_reverse_create_internal(infix_reverse_t **, infix_type *, infix_type **, size_t, size_t, void *, void *, bool)
Definition trampoline.c:443
void code_buffer_append(code_buffer *buf, const void *data, size_t len)
Appends raw bytes to a code buffer, reallocating if necessary.
Definition trampoline.c:128
static size_t get_page_size()
Definition trampoline.c:420
void emit_int32(code_buffer *buf, int32_t value)
Appends a 32-bit integer to a code buffer.
Definition trampoline.c:166
const infix_reverse_abi_spec * get_current_reverse_abi_spec()
Gets the ABI v-table for the current target platform (reverse calls).
Definition trampoline.c:97
A header for conditionally compiled debugging utilities.
static void infix_dump_hex(c23_maybe_unused const void *data, c23_maybe_unused size_t size, c23_maybe_unused const char *title)
Definition utility.h:115