|
infix
A JIT-Powered FFI Library for C
|
Internal data structures, function prototypes, and constants. More...
Go to the source code of this file.
Classes | |
| struct | infix_executable_t |
| Internal representation of an executable memory block for JIT code. More... | |
| struct | infix_protected_t |
| Internal representation of a memory block that will be made read-only. More... | |
| struct | infix_forward_t |
| Internal definition of a forward trampoline handle. More... | |
| struct | infix_reverse_t |
| Internal definition of a reverse trampoline (callback/closure) handle. More... | |
| struct | infix_arena_t |
| Internal definition of a memory arena. More... | |
| struct | _infix_registry_entry_t |
| A single entry in the registry's hash table. More... | |
| struct | infix_registry_t |
| Internal definition of a named type registry. More... | |
| struct | infix_registry_iterator_t |
| Internal definition of a registry iterator. More... | |
| struct | code_buffer |
| A dynamic buffer for staged machine code generation. More... | |
| struct | infix_library_t |
| Internal definition of a dynamic library handle. More... | |
| struct | infix_arg_location |
| Detailed location information for a single function argument. More... | |
| struct | infix_call_frame_layout |
| A complete layout blueprint for a forward call frame. More... | |
| struct | infix_reverse_call_frame_layout |
| A complete layout blueprint for a reverse call frame. More... | |
| struct | infix_forward_abi_spec |
| Defines the ABI-specific implementation interface for forward trampolines. More... | |
| struct | infix_reverse_abi_spec |
| Defines the ABI-specific implementation interface for reverse trampolines. More... | |
Macros | |
| #define | INFIX_MAX_STACK_ALLOC (1024 * 1024 * 4) |
| A safety limit (4MB) for the total stack space a trampoline can allocate. This prevents stack exhaustion from malformed or malicious type layouts. | |
| #define | INFIX_MAX_ARG_SIZE (1024 * 64) |
| A safety limit (64KB) for the size of a single argument. | |
| #define | EMIT_BYTES(buf, ...) |
| Appends a sequence of bytes (e.g., an instruction opcode) to a code buffer. | |
Typedefs | |
| typedef void(* | infix_internal_dispatch_callback_fn) (infix_reverse_t *, void *, void **) |
| A function pointer to the universal C dispatcher for reverse calls. | |
| typedef struct _infix_registry_entry_t | _infix_registry_entry_t |
Enumerations | |
| enum | infix_arg_location_type { ARG_LOCATION_GPR , ARG_LOCATION_XMM , ARG_LOCATION_GPR_PAIR , ARG_LOCATION_SSE_SSE_PAIR , ARG_LOCATION_INTEGER_SSE_PAIR , ARG_LOCATION_SSE_INTEGER_PAIR , ARG_LOCATION_STACK } |
| Describes the physical location where a function argument is passed according to the ABI. More... | |
Functions | |
| void | _infix_set_error (infix_error_category_t category, infix_error_code_t code, size_t position) |
| Sets the thread-local error state with detailed information. | |
| void | _infix_set_system_error (infix_error_category_t category, infix_error_code_t code, long system_code, const char *msg) |
| Sets the thread-local error state for a system-level error. | |
| void | _infix_clear_error (void) |
| Clears the thread-local error state. | |
| void | _infix_type_recalculate_layout (infix_type *type) |
| Recalculates the layout of a fully resolved type graph. | |
| c23_nodiscard infix_status | _infix_resolve_type_graph_inplace (infix_type **type_ptr, infix_registry_t *registry) |
| Resolves all named type references in a type graph in-place. | |
| c23_nodiscard infix_status | _infix_parse_type_internal (infix_type **, infix_arena_t **, const char *) |
| The internal core of the signature parser. | |
| c23_nodiscard infix_status | _infix_type_print_body_only (char *, size_t, const infix_type *, infix_print_dialect_t) |
| An internal-only function to serialize a type's body without its registered name. | |
| infix_type * | _copy_type_graph_to_arena (infix_arena_t *, const infix_type *) |
| Performs a deep copy of a type graph into a destination arena. | |
| size_t | _infix_estimate_graph_size (infix_arena_t *temp_arena, const infix_type *type) |
| Estimates the total memory required to deep-copy a complete type graph. | |
| const infix_forward_abi_spec * | get_current_forward_abi_spec (void) |
| Gets the ABI v-table for forward calls for the current platform. | |
| const infix_reverse_abi_spec * | get_current_reverse_abi_spec (void) |
| Gets the ABI v-table for reverse calls for the current platform. | |
| void | code_buffer_init (code_buffer *buf, infix_arena_t *arena) |
| Initializes a code buffer for JIT code generation. | |
| void | code_buffer_append (code_buffer *buf, const void *data, size_t len) |
| Appends raw bytes to a code buffer, reallocating within its arena if necessary. | |
| void | emit_byte (code_buffer *buf, uint8_t byte) |
| A convenience wrapper to append a single byte to a code buffer. | |
| void | emit_int32 (code_buffer *buf, int32_t value) |
| A convenience wrapper to append a 32-bit integer (little-endian) to a code buffer. | |
| void | emit_int64 (code_buffer *buf, int64_t value) |
| A convenience wrapper to append a 64-bit integer (little-endian) to a code buffer. | |
| c23_nodiscard infix_status | _infix_forward_create_internal (infix_forward_t **, infix_type *, infix_type **, size_t, size_t, void *) |
| The core implementation for creating all forward trampolines. | |
| c23_nodiscard infix_executable_t | infix_executable_alloc (size_t size) |
| Allocates a block of executable memory using the platform's W^X strategy. | |
| void | infix_executable_free (infix_executable_t exec) |
| Frees a block of executable memory and applies guard pages to prevent use-after-free. | |
| c23_nodiscard bool | infix_executable_make_executable (infix_executable_t exec) |
| Makes a block of JIT memory executable, completing the W^X process. | |
| c23_nodiscard infix_protected_t | infix_protected_alloc (size_t size) |
| Allocates a block of standard memory for later protection. | |
| void | infix_protected_free (infix_protected_t prot) |
| Frees a block of protected memory. | |
| c23_nodiscard bool | infix_protected_make_readonly (infix_protected_t prot) |
| Makes a block of memory read-only for security hardening. | |
| void | infix_internal_dispatch_callback_fn_impl (infix_reverse_t *context, void *return_value_ptr, void **args_array) |
| The universal C entry point for all reverse call trampolines. | |
| static size_t | _infix_align_up (size_t value, size_t alignment) |
| Aligns a value up to the next multiple of a power-of-two alignment. | |
| static bool | is_float (const infix_type *type) |
A fast inline check to determine if an infix_type is a float. | |
| static bool | is_double (const infix_type *type) |
A fast inline check to determine if an infix_type is a double. | |
| static bool | is_long_double (const infix_type *type) |
A fast inline check to determine if an infix_type is a long double. | |
Internal data structures, function prototypes, and constants.
Copyright (c) 2025 Sanko Robinson
This source code is dual-licensed under the Artistic License 2.0 or the MIT License. You may choose to use this code under the terms of either license.
SPDX-License-Identifier: (Artistic-2.0 OR MIT)
The documentation blocks within this file are licensed under the Creative Commons Attribution 4.0 International License (CC BY 4.0).
SPDX-License-Identifier: CC-BY-4.0
This is the primary internal header for the infix library. It defines the complete layout of all opaque public structs (like infix_forward_t) and declares internal-only functions (_infix_*) that are shared between modules.
Its most important role is to define the core ABI abstraction layer through v-tables (infix_forward_abi_spec, infix_reverse_abi_spec). These structures form the contract between the platform-agnostic JIT engine (trampoline.c) and the platform-specific ABI implementations (arch/...), making them key to the library's portability and architectural design.
This header also brings together all other internal type definitions, creating a single source of truth for the library's internal data model.
| #define EMIT_BYTES | ( | buf, | |
| ... | |||
| ) |
Appends a sequence of bytes (e.g., an instruction opcode) to a code buffer.
| #define INFIX_MAX_ARG_SIZE (1024 * 64) |
A safety limit (64KB) for the size of a single argument.
| #define INFIX_MAX_STACK_ALLOC (1024 * 1024 * 4) |
A safety limit (4MB) for the total stack space a trampoline can allocate. This prevents stack exhaustion from malformed or malicious type layouts.
| typedef struct _infix_registry_entry_t _infix_registry_entry_t |
| typedef void(* infix_internal_dispatch_callback_fn) (infix_reverse_t *, void *, void **) |
A function pointer to the universal C dispatcher for reverse calls.
This is the C function that the JIT-compiled reverse trampoline stub calls after marshalling all arguments into a standard C format.
Describes the physical location where a function argument is passed according to the ABI.
This enumeration abstracts away the differences in how various ABIs use registers and the stack to pass data. It is the primary output of the ABI classification process.
| infix_type * _copy_type_graph_to_arena | ( | infix_arena_t * | dest_arena, |
| const infix_type * | src_type | ||
| ) |
Performs a deep copy of a type graph into a destination arena.
Located in src/core/types.c. This is the "Copy" stage of the data pipeline, crucial for creating self-contained trampoline objects and ensuring memory safety. It uses memoization to correctly handle cycles and shared type objects.
| [in] | dest_arena | The destination arena for the new type graph. |
| [in] | src_type | The source type graph to copy. |
dest_arena, or nullptr on failure.
|
inlinestatic |
Aligns a value up to the next multiple of a power-of-two alignment.
| value | The value to align. |
| alignment | The alignment boundary (must be a power of two). |
| void _infix_clear_error | ( | void | ) |
Clears the thread-local error state.
Located in src/core/error.c. This is called at the beginning of every public API function to ensure that a prior error from an unrelated call is not accidentally returned.
| size_t _infix_estimate_graph_size | ( | infix_arena_t * | temp_arena, |
| const infix_type * | type | ||
| ) |
Estimates the total memory required to deep-copy a complete type graph.
Located in src/core/types.c. This function recursively walks the entire type graph, including all nested aggregates and function arguments, to calculate the exact size needed for an arena that will hold a deep copy.
| [in] | temp_arena | A temporary arena used for the estimator's own bookkeeping (e.g., cycle detection). |
| [in] | type | The root of the type graph to estimate. |
| c23_nodiscard infix_status _infix_forward_create_internal | ( | infix_forward_t ** | , |
| infix_type * | , | ||
| infix_type ** | , | ||
| size_t | , | ||
| size_t | , | ||
| void * | |||
| ) |
The core implementation for creating all forward trampolines.
Located in src/jit/trampoline.c, this function orchestrates the entire JIT pipeline for forward calls, from ABI classification to code generation and final handle creation.
INFIX_SUCCESS on success. | c23_nodiscard infix_status _infix_parse_type_internal | ( | infix_type ** | out_type, |
| infix_arena_t ** | out_arena, | ||
| const char * | signature | ||
| ) |
The internal core of the signature parser.
Located in src/core/signature.c. This is the "Parse" stage of the data pipeline. It takes a signature string and produces a raw, unresolved infix_type graph in a new, temporary arena. It does not perform any copying, resolution, or layout calculation.
| [out] | out_type | On success, receives the parsed type graph. |
| [out] | out_arena | On success, receives the temporary arena holding the graph. |
| [in] | signature | The signature string to parse. |
INFIX_SUCCESS on success. | c23_nodiscard infix_status _infix_resolve_type_graph_inplace | ( | infix_type ** | type_ptr, |
| infix_registry_t * | registry | ||
| ) |
Resolves all named type references in a type graph in-place.
Located in src/core/type_registry.c. This is the "Resolve" stage of the data pipeline. It traverses a type graph and replaces all INFIX_TYPE_NAMED_REFERENCE nodes (@Name) with direct pointers to the canonical infix_type objects from the registry.
| [in,out] | type_ptr | A pointer to the root of the type graph to resolve. The pointer may be changed. |
| [in] | registry | The registry to use for lookups. |
INFIX_SUCCESS on success, or an error if a name cannot be resolved. | void _infix_set_error | ( | infix_error_category_t | category, |
| infix_error_code_t | code, | ||
| size_t | position | ||
| ) |
Sets the thread-local error state with detailed information.
Located in src/core/error.c, this function is the primary mechanism for reporting errors from within the library. It populates the thread-local g_infix_last_error struct. For parser errors, it generates a rich diagnostic message with a code snippet.
| category | The general category of the error. |
| code | The specific error code. |
| position | For parser errors, the byte offset into the signature string where the error occurred. |
| void _infix_set_system_error | ( | infix_error_category_t | category, |
| infix_error_code_t | code, | ||
| long | system_code, | ||
| const char * | msg | ||
| ) |
Sets the thread-local error state for a system-level error.
Located in src/core/error.c, this is used for errors originating from the operating system, such as dlopen or mmap failures.
| category | The general category of the error. |
| code | The infix error code that corresponds to the failure. |
| system_code | The OS-specific error code (e.g., from errno or GetLastError). |
| msg | An optional custom message from the OS (e.g., from dlerror). |
| c23_nodiscard infix_status _infix_type_print_body_only | ( | char * | buffer, |
| size_t | buffer_size, | ||
| const infix_type * | type, | ||
| infix_print_dialect_t | dialect | ||
| ) |
An internal-only function to serialize a type's body without its registered name.
Located in src/core/signature.c. Unlike infix_type_print, which will print @Name for a named struct, this function will always print the full {...} body. This is essential for infix_registry_print to function correctly.
| [out] | buffer | The output buffer. |
| [in] | buffer_size | The size of the buffer. |
| [in] | type | The type to print. |
| [in] | dialect | The output format dialect. |
INFIX_SUCCESS on success. | void _infix_type_recalculate_layout | ( | infix_type * | type | ) |
Recalculates the layout of a fully resolved type graph.
Located in src/core/types.c. This is the "Layout" stage of the data pipeline. It recursively walks a type graph and computes the final size, alignment, and member offset fields for all aggregate types. It must only be called on a fully resolved graph.
| [in,out] | type | The root of the type graph to recalculate. The graph is modified in-place. |
| void code_buffer_append | ( | code_buffer * | buf, |
| const void * | data, | ||
| size_t | len | ||
| ) |
Appends raw bytes to a code buffer, reallocating within its arena if necessary.
See src/jit/trampoline.c. This is the fundamental operation for building the machine code. If the buffer runs out of space, it is grown exponentially.
| [in,out] | buf | The code buffer to append to. |
| [in] | data | A pointer to the bytes to append. |
| [in] | len | The number of bytes to append. |
| void code_buffer_init | ( | code_buffer * | buf, |
| infix_arena_t * | arena | ||
| ) |
Initializes a code buffer for JIT code generation.
See src/jit/trampoline.c. Associates the buffer with a temporary arena and sets its initial capacity.
| [out] | buf | A pointer to the code_buffer to initialize. |
| [in] | arena | The temporary arena to use for the buffer's memory. |
| void emit_byte | ( | code_buffer * | buf, |
| uint8_t | byte | ||
| ) |
A convenience wrapper to append a single byte to a code buffer.
| [in,out] | buf | The code buffer. |
| [in] | byte | The byte to append. |
| void emit_int32 | ( | code_buffer * | buf, |
| int32_t | value | ||
| ) |
A convenience wrapper to append a 32-bit integer (little-endian) to a code buffer.
| [in,out] | buf | The code buffer. |
| [in] | value | The 32-bit integer to append. |
| void emit_int64 | ( | code_buffer * | buf, |
| int64_t | value | ||
| ) |
A convenience wrapper to append a 64-bit integer (little-endian) to a code buffer.
| [in,out] | buf | The code buffer. |
| [in] | value | The 64-bit integer to append. |
| const infix_forward_abi_spec * get_current_forward_abi_spec | ( | void | ) |
Gets the ABI v-table for forward calls for the current platform.
See src/jit/trampoline.c. This function is the entry point to the ABI abstraction layer, returning the correct set of function pointers based on the compile-time ABI detection.
infix_forward_abi_spec. | const infix_reverse_abi_spec * get_current_reverse_abi_spec | ( | void | ) |
Gets the ABI v-table for reverse calls for the current platform.
See src/jit/trampoline.c. This function mirrors get_current_forward_abi_spec for reverse call trampolines.
infix_reverse_abi_spec. | c23_nodiscard infix_executable_t infix_executable_alloc | ( | size_t | size | ) |
Allocates a block of executable memory using the platform's W^X strategy.
Located in src/jit/executor.c. This is a platform-specific function that abstracts VirtualAlloc, mmap with MAP_JIT, or shm_open with dual-mapping.
| size | The number of bytes to allocate. |
infix_executable_t handle containing pointers to the allocated memory. | void infix_executable_free | ( | infix_executable_t | exec | ) |
Frees a block of executable memory and applies guard pages to prevent use-after-free.
Located in src/jit/executor.c. Before freeing, it attempts to change the memory's protection to be inaccessible, causing an immediate crash on a UAF.
| exec | The handle to the memory block to free. |
| c23_nodiscard bool infix_executable_make_executable | ( | infix_executable_t | exec | ) |
Makes a block of JIT memory executable, completing the W^X process.
Located in src/jit/executor.c. For single-map platforms, this calls VirtualProtect or mprotect. For dual-map platforms, this is a no-op. It also handles instruction cache flushing on relevant architectures like AArch64.
| exec | The handle to the memory block to make executable. |
true on success, false on failure. | void infix_internal_dispatch_callback_fn_impl | ( | infix_reverse_t * | context, |
| void * | return_value_ptr, | ||
| void ** | args_array | ||
| ) |
The universal C entry point for all reverse call trampolines.
Located in src/jit/executor.c, this function is called by the JIT-compiled stub. It receives the marshalled arguments and dispatches the call to either the type-safe callback (via a cached forward trampoline) or the generic closure handler.
| [in] | context | The infix_reverse_t context for this call. |
| [out] | return_value_ptr | A pointer to the stack buffer for the return value. |
| [in] | args_array | A pointer to the void** array of argument pointers. |
| c23_nodiscard infix_protected_t infix_protected_alloc | ( | size_t | size | ) |
Allocates a block of standard memory for later protection.
Located in src/jit/executor.c. This is used to allocate the memory for an infix_reverse_t context before it is made read-only.
| size | The number of bytes to allocate. |
infix_protected_t handle. | void infix_protected_free | ( | infix_protected_t | prot | ) |
Frees a block of protected memory.
Located in src/jit/executor.c.
| prot | The memory block to free. |
| c23_nodiscard bool infix_protected_make_readonly | ( | infix_protected_t | prot | ) |
Makes a block of memory read-only for security hardening.
Located in src/jit/executor.c. This is called on the infix_reverse_t context after it has been fully initialized.
| prot | The memory block to make read-only. |
true on success, false on failure.
|
inlinestatic |
A fast inline check to determine if an infix_type is a double.
| type | The type to check. |
true if the type is a double primitive.
|
inlinestatic |
A fast inline check to determine if an infix_type is a float.
| type | The type to check. |
true if the type is a float primitive.
|
inlinestatic |
A fast inline check to determine if an infix_type is a long double.
| type | The type to check. |
true if the type is a long double primitive.