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 )