infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
trampoline.c File Reference

The core JIT engine for generating forward and reverse trampolines. More...

#include "common/infix_internals.h"
#include "common/utility.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
Include dependency graph for trampoline.c:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  visited_node_t
 

Typedefs

typedef struct visited_node_t visited_node_t
 

Functions

static infix_status _infix_reverse_create_internal (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, void *user_data, bool is_callback)
 
const infix_forward_abi_specget_current_forward_abi_spec ()
 Gets the ABI v-table for forward calls for the current platform.
 
const infix_reverse_abi_specget_current_reverse_abi_spec ()
 Gets the ABI v-table for reverse calls for the current platform.
 
const infix_direct_forward_abi_specget_current_direct_forward_abi_spec ()
 Gets the ABI v-table for direct marshalling forward 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.
 
static bool _is_type_graph_resolved_recursive (const infix_type *type, visited_node_t *visited_head)
 
static bool _is_type_graph_resolved (const infix_type *type)
 
static size_t _estimate_metadata_size (infix_arena_t *temp_arena, infix_type *return_type, infix_type **arg_types, size_t num_args)
 
c23_nodiscard infix_unbound_cif_func infix_forward_get_unbound_code (infix_forward_t *trampoline)
 Gets the callable function pointer from an unbound forward trampoline.
 
c23_nodiscard infix_cif_func infix_forward_get_code (infix_forward_t *trampoline)
 Gets the callable function pointer from a bound forward trampoline.
 
c23_nodiscard infix_direct_cif_func infix_forward_get_direct_code (infix_forward_t *trampoline)
 Gets the callable function pointer from a direct marshalling trampoline.
 
c23_nodiscard infix_status _infix_forward_create_impl (infix_forward_t **out_trampoline, infix_arena_t *target_arena, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, void *target_fn)
 
c23_nodiscard infix_status _infix_forward_create_direct_impl (infix_forward_t **out_trampoline, infix_type *return_type, infix_type **arg_types, size_t num_args, void *target_fn, infix_direct_arg_handler_t *handlers)
 
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)
 Creates a bound forward trampoline from infix_type objects (Manual API).
 
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 trampoline from infix_type objects (Manual API).
 
void infix_forward_destroy (infix_forward_t *trampoline)
 Destroys a forward trampoline and frees all associated memory.
 
static size_t get_page_size ()
 
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)
 Creates a type-safe reverse trampoline (callback) from infix_type objects (Manual API).
 
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)
 Creates a generic reverse trampoline (closure) from infix_type objects (Manual API).
 
void infix_reverse_destroy (infix_reverse_t *reverse_trampoline)
 Destroys a reverse trampoline and frees all associated memory.
 
c23_nodiscard void * infix_reverse_get_code (const infix_reverse_t *reverse_trampoline)
 Gets the native, callable C function pointer from a reverse trampoline.
 
c23_nodiscard void * infix_reverse_get_user_data (const infix_reverse_t *reverse_trampoline)
 Gets the user-provided data pointer from a closure context.
 
c23_nodiscard infix_status infix_forward_create_in_arena (infix_forward_t **out_trampoline, infix_arena_t *target_arena, const char *signature, void *target_function, infix_registry_t *registry)
 Creates a "bound" forward trampoline within a user-provided arena.
 
c23_nodiscard infix_status infix_forward_create (infix_forward_t **out_trampoline, const char *signature, void *target_function, infix_registry_t *registry)
 Creates a "bound" forward trampoline from a signature string.
 
c23_nodiscard infix_status infix_forward_create_unbound (infix_forward_t **out_trampoline, const char *signature, infix_registry_t *registry)
 Creates an "unbound" forward trampoline from a signature string.
 
c23_nodiscard infix_status infix_forward_create_direct (infix_forward_t **out_trampoline, const char *signature, void *target_function, infix_direct_arg_handler_t *handlers, infix_registry_t *registry)
 Creates a forward trampoline with direct, JIT-bound marshalling.
 
c23_nodiscard infix_status infix_reverse_create_callback (infix_reverse_t **out_context, const char *signature, void *user_callback_fn, infix_registry_t *registry)
 Creates a type-safe reverse trampoline (callback).
 
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)
 Creates a generic reverse trampoline (closure) for stateful callbacks.
 

Detailed Description

The core JIT engine for generating forward and reverse trampolines.

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 module is the central orchestrator of the infix library. It brings together the type system, memory management, and ABI-specific logic to generate executable machine code at runtime.

It implements both the high-level Signature API (e.g., infix_forward_create) and the low-level Manual API (e.g., infix_forward_create_manual). The high-level functions are convenient wrappers that use the signature parser to create the necessary infix_type objects before calling the core internal implementation.

The core logic is encapsulated in _infix_forward_create_internal and _infix_reverse_create_internal. These functions follow a clear pipeline:

  1. Prepare: Analyze the function signature with the appropriate ABI-specific prepare_*_call_frame function to create a layout blueprint.
  2. Generate: Use the layout blueprint to call a sequence of ABI-specific generate_* functions, which emit machine code into a temporary code_buffer.
  3. Finalize: Allocate executable memory, copy the generated code into it, create the final self-contained trampoline handle (deep-copying all type metadata), and make the code executable.

Typedef Documentation

◆ visited_node_t

Function Documentation

◆ _estimate_metadata_size()

static size_t _estimate_metadata_size ( infix_arena_t temp_arena,
infix_type return_type,
infix_type **  arg_types,
size_t  num_args 
)
static

◆ _infix_forward_create_direct_impl()

c23_nodiscard infix_status _infix_forward_create_direct_impl ( infix_forward_t **  out_trampoline,
infix_type return_type,
infix_type **  arg_types,
size_t  num_args,
void *  target_fn,
infix_direct_arg_handler_t handlers 
)

◆ _infix_forward_create_impl()

c23_nodiscard infix_status _infix_forward_create_impl ( infix_forward_t **  out_trampoline,
infix_arena_t target_arena,
infix_type return_type,
infix_type **  arg_types,
size_t  num_args,
size_t  num_fixed_args,
void *  target_fn 
)

◆ _infix_reverse_create_internal()

static infix_status _infix_reverse_create_internal ( 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,
void *  user_data,
bool  is_callback 
)
static

◆ _is_type_graph_resolved()

static bool _is_type_graph_resolved ( const infix_type type)
static

◆ _is_type_graph_resolved_recursive()

static bool _is_type_graph_resolved_recursive ( const infix_type type,
visited_node_t visited_head 
)
static

◆ code_buffer_append()

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.

Parameters
[in,out]bufThe code buffer to append to.
[in]dataA pointer to the bytes to append.
[in]lenThe number of bytes to append.

◆ code_buffer_init()

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.

Parameters
[out]bufA pointer to the code_buffer to initialize.
[in]arenaThe temporary arena to use for the buffer's memory.

◆ emit_byte()

void emit_byte ( code_buffer buf,
uint8_t  byte 
)

A convenience wrapper to append a single byte to a code buffer.

Parameters
[in,out]bufThe code buffer.
[in]byteThe byte to append.

◆ emit_int32()

void emit_int32 ( code_buffer buf,
int32_t  value 
)

A convenience wrapper to append a 32-bit integer (little-endian) to a code buffer.

Parameters
[in,out]bufThe code buffer.
[in]valueThe 32-bit integer to append.

◆ emit_int64()

void emit_int64 ( code_buffer buf,
int64_t  value 
)

A convenience wrapper to append a 64-bit integer (little-endian) to a code buffer.

Parameters
[in,out]bufThe code buffer.
[in]valueThe 64-bit integer to append.

◆ get_current_direct_forward_abi_spec()

const infix_direct_forward_abi_spec * get_current_direct_forward_abi_spec ( void  )

Gets the ABI v-table for direct marshalling forward calls for the current platform.

Returns
A pointer to the active infix_direct_forward_abi_spec.

◆ get_current_forward_abi_spec()

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.

Returns
A pointer to the active infix_forward_abi_spec.

◆ get_current_reverse_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.

Returns
A pointer to the active infix_reverse_abi_spec.

◆ get_page_size()

static size_t get_page_size ( )
static