Affix
view release on metacpan or search on metacpan
infix/src/jit/trampoline.c view on Meta::CPAN
return _infix_forward_create_impl(
out_trampoline, nullptr, return_type, arg_types, num_args, num_fixed_args, nullptr, false);
}
/**
* @internal
* @brief Internal implementation of forward trampoline destruction.
*/
void _infix_forward_destroy_internal(infix_forward_t * trampoline) {
if (trampoline == nullptr)
return;
// Destroying the private arena frees all deep-copied type metadata and the signature string.
if (trampoline->arena && !trampoline->is_external_arena)
infix_arena_destroy(trampoline->arena);
// Free the JIT-compiled executable code.
infix_executable_free(trampoline->exec);
// Free the handle struct itself.
infix_free(trampoline);
}
/**
* @brief Destroys a forward trampoline and frees all associated memory.
* @details This function safely releases all resources owned by the trampoline,
* including its JIT-compiled executable code and its private memory arena which
* stores the deep-copied type information.
* @param[in] trampoline The trampoline to destroy. Safe to call with `nullptr`.
*/
INFIX_API void infix_forward_destroy(infix_forward_t * trampoline) { _infix_cache_release(trampoline); }
// Reverse Trampoline API Implementation
/**
* @internal
* @brief Gets the system's memory page size in a portable way.
* @return The page size in bytes.
*/
static size_t get_page_size() {
#if defined(INFIX_OS_WINDOWS)
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
return sysInfo.dwPageSize;
#else
// sysconf is the standard POSIX way to get system configuration values.
return sysconf(_SC_PAGESIZE);
#endif
}
/**
* @internal
* @brief The core implementation for creating a reverse trampoline (callback or closure).
*
* @details This function orchestrates the JIT compilation pipeline for reverse calls.
* It has a special `is_callback` flag that distinguishes between the two reverse
* trampoline models:
*
* - **Type-safe Callback (`is_callback = true`):** In this model, the user provides a
* standard C function pointer with a matching signature. This function internally
* creates a *forward* trampoline (`cached_forward_trampoline`) that is used by the
* universal C dispatcher to call the user's handler in a type-safe way.
*
* - **Generic Closure (`is_callback = false`):** The user provides a generic handler of
* type `infix_closure_handler_fn`. The universal dispatcher calls this handler
* directly, without needing a cached forward trampoline.
*
* For security, the entire `infix_reverse_t` context struct is allocated in a
* special page-aligned memory region that is made read-only after initialization.
*
* @param is_callback `true` to create a type-safe callback, `false` for a generic closure.
* @return `INFIX_SUCCESS` on success.
*/
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) {
if (out_context == nullptr || return_type == nullptr || num_fixed_args > num_args) {
_infix_set_error(INFIX_CATEGORY_GENERAL, INFIX_CODE_NULL_POINTER, 0);
return INFIX_ERROR_INVALID_ARGUMENT;
}
// Pre-flight check: ensure all types are fully resolved.
if (!_is_type_graph_resolved(return_type)) {
_infix_set_error(INFIX_CATEGORY_ABI, INFIX_CODE_UNRESOLVED_NAMED_TYPE, 0);
return INFIX_ERROR_INVALID_ARGUMENT;
}
if (arg_types == nullptr && num_args > 0) {
_infix_set_error(INFIX_CATEGORY_ABI, INFIX_CODE_UNRESOLVED_NAMED_TYPE, 0);
return INFIX_ERROR_INVALID_ARGUMENT;
}
for (size_t i = 0; i < num_args; ++i) {
if (arg_types[i] == nullptr || !_is_type_graph_resolved(arg_types[i])) {
_infix_set_error(INFIX_CATEGORY_ABI, INFIX_CODE_UNRESOLVED_NAMED_TYPE, 0);
return INFIX_ERROR_INVALID_ARGUMENT;
}
}
const infix_reverse_abi_spec * spec = get_current_reverse_abi_spec();
if (spec == nullptr) {
_infix_set_error(INFIX_CATEGORY_ABI, INFIX_CODE_UNSUPPORTED_ABI, 0);
return INFIX_ERROR_UNSUPPORTED_ABI;
}
infix_status status = INFIX_SUCCESS;
infix_reverse_call_frame_layout * layout = nullptr;
infix_reverse_t * context = nullptr;
infix_arena_t * temp_arena = nullptr;
infix_protected_t prot = {.rw_ptr = nullptr, .size = 0};
code_buffer buf;
temp_arena = infix_arena_create(65536);
if (!temp_arena) {
_infix_set_error(INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, 0);
return INFIX_ERROR_ALLOCATION_FAILED;
}
code_buffer_init(&buf, temp_arena);
// Security Hardening: Allocate the context struct itself in special, page-aligned
// memory that can be made read-only after initialization.
size_t page_size = get_page_size();
size_t context_alloc_size = (sizeof(infix_reverse_t) + page_size - 1) & ~(page_size - 1);
prot = infix_protected_alloc(context_alloc_size);
if (prot.rw_ptr == nullptr) {
status = INFIX_ERROR_ALLOCATION_FAILED;
goto cleanup;
}
context = (infix_reverse_t *)prot.rw_ptr;
infix_memset(context, 0, context_alloc_size);
infix/src/jit/trampoline.c view on Meta::CPAN
return status;
}
INFIX_API c23_nodiscard infix_status infix_reverse_create_callback(infix_reverse_t ** out_context,
const char * signature,
void * user_callback_fn,
infix_registry_t * registry) {
infix_arena_t * arena = nullptr;
infix_type * ret_type = nullptr;
infix_function_argument * args = nullptr;
size_t num_args = 0, num_fixed = 0;
infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
if (status != INFIX_SUCCESS) {
infix_arena_destroy(arena);
return status;
}
infix_type ** arg_types =
(num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *)) : nullptr;
if (num_args > 0 && !arg_types) {
infix_arena_destroy(arena);
_infix_set_error(INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, 0);
return INFIX_ERROR_ALLOCATION_FAILED;
}
for (size_t i = 0; i < num_args; ++i)
arg_types[i] = args[i].type;
// Call the manual API with the parsed types.
status =
infix_reverse_create_callback_manual(out_context, ret_type, arg_types, num_args, num_fixed, user_callback_fn);
infix_arena_destroy(arena);
return status;
}
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) {
infix_arena_t * arena = nullptr;
infix_type * ret_type = nullptr;
infix_function_argument * args = nullptr;
size_t num_args = 0, num_fixed = 0;
infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
if (status != INFIX_SUCCESS) {
infix_arena_destroy(arena);
return status;
}
infix_type ** arg_types =
(num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *)) : nullptr;
if (num_args > 0 && !arg_types) {
infix_arena_destroy(arena);
_infix_set_error(INFIX_CATEGORY_ALLOCATION, INFIX_CODE_OUT_OF_MEMORY, 0);
return INFIX_ERROR_ALLOCATION_FAILED;
}
for (size_t i = 0; i < num_args; ++i)
arg_types[i] = args[i].type;
status = infix_reverse_create_closure_manual(
out_context, ret_type, arg_types, num_args, num_fixed, user_callback_fn, user_data);
infix_arena_destroy(arena);
return status;
}
// ============================================================================
// UNITY BUILD INCLUDES
// This section includes the actual ABI implementations at the end of the file.
// Because `trampoline.c` is the central translation unit, including the
// correct ABI-specific .c file here makes its functions (`g_win_x64_spec`, etc.)
// available without needing to add platform-specific logic to the build system.
// The `infix_config.h` header ensures only one of these #if blocks is active.
// ============================================================================
#if defined(INFIX_ABI_WINDOWS_X64)
#include "../arch/x64/abi_win_x64.c"
#include "../arch/x64/abi_x64_emitters.c"
#elif defined(INFIX_ABI_SYSV_X64)
#include "../arch/x64/abi_sysv_x64.c"
#include "../arch/x64/abi_x64_emitters.c"
#elif defined(INFIX_ABI_AAPCS64)
#include "../arch/aarch64/abi_arm64.c"
#include "../arch/aarch64/abi_arm64_emitters.c"
#else
#error "No supported ABI was selected for the unity build in trampoline.c."
#endif
( run in 1.783 second using v1.01-cache-2.11-cpan-39bf76dae61 )