Affix
view release on metacpan or search on metacpan
infix/src/jit/trampoline.c view on Meta::CPAN
* @param[in] return_type The `infix_type` for the function's return value.
* @param[in] arg_types An array of `infix_type*` for the function's arguments.
* @param[in] num_args The number of arguments.
* @param[in] num_fixed_args The number of non-variadic arguments.
* @return `INFIX_SUCCESS` on success.
*/
INFIX_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) {
_infix_clear_error();
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;
}
( run in 2.278 seconds using v1.01-cache-2.11-cpan-cdf2f3d4e48 )