Affix

 view release on metacpan or  search on metacpan

infix/src/jit/trampoline.c  view on Meta::CPAN

        for (size_t i = 0; i < num_args; ++i) {
            handle->arg_types[i] = _copy_type_graph_to_arena(handle->arena, arg_types[i]);
            // Check for allocation failure during copy
            if (arg_types[i] != nullptr && handle->arg_types[i] == nullptr && !handle->arena->error) {
                status = INFIX_ERROR_ALLOCATION_FAILED;
                goto cleanup;
            }
        }
    }
    handle->num_args = num_args;
    handle->num_fixed_args = num_fixed_args;
    handle->target_fn = target_fn;
    handle->is_safe = is_safe;
    handle->ref_count = 1;

    // Save the canonical signature for the cache key.
    if (sig_status == INFIX_SUCCESS) {
        size_t sig_len = strlen(canonical_sig) + 1;
        handle->signature = infix_arena_alloc(handle->arena, sig_len, 1);
        if (handle->signature)
            infix_memcpy(handle->signature, canonical_sig, sig_len);
    }

    // Allocate and finalize executable memory.
    handle->exec = infix_executable_alloc(buf.size);
    if (handle->exec.rw_ptr == nullptr) {
        status = INFIX_ERROR_ALLOCATION_FAILED;
        goto cleanup;
    }
    infix_memcpy(handle->exec.rw_ptr, buf.code, buf.size);
    if (!infix_executable_make_executable(&handle->exec,
                                          is_safe ? INFIX_EXECUTABLE_SAFE_FORWARD : INFIX_EXECUTABLE_FORWARD,
                                          layout->prologue_size,
                                          layout->epilogue_offset)) {
        status = INFIX_ERROR_PROTECTION_FAILED;
        goto cleanup;
    }
    infix_dump_hex(handle->exec.rx_ptr, handle->exec.size, "Forward Trampoline Machine Code");
    *out_trampoline = handle;

    // Cache the newly created trampoline.
    // We ONLY cache if we own the arena. If the user provided an external arena,
    // they control the lifetime, and we can't guarantee the signature string
    // (which is in that arena) will remain valid as long as the cache entry exists.
    if (handle->signature && !handle->is_external_arena)
        _infix_cache_insert(handle);

cleanup:
    // If any step failed, ensure the partially created handle is fully destroyed.
    if (status != INFIX_SUCCESS && handle != nullptr)
        infix_forward_destroy(handle);
    // The temporary arena is always destroyed.
    infix_arena_destroy(temp_arena);
    return status;
}
/**
 * @internal
 * @brief The core implementation for creating a direct marshalling forward trampoline.
 *
 * This function orchestrates the JIT compilation pipeline for the direct marshalling
 * feature. It is the internal counterpart to the public `infix_forward_create_direct`
 * function and is called after the signature string has been parsed into a type graph.
 *
 * The pipeline is as follows:
 * 1.  Selects the appropriate `infix_direct_forward_abi_spec` v-table for the target platform.
 * 2.  Invokes `prepare_direct_forward_call_frame` to analyze the signature and handlers,
 *     producing a complete layout blueprint.
 * 3.  Calls the `generate_*` functions from the v-table in sequence. This emits machine code
 *     that includes direct calls to the user-provided marshaller and write-back functions.
 * 4.  Finalizes the `infix_forward_t` handle, marking it as a `is_direct_trampoline`.
 * 5.  Allocates executable memory, copies the generated code, and makes it executable.
 *
 * @param[out] out_trampoline Receives the created trampoline handle.
 * @param[in] return_type The fully resolved return type.
 * @param[in] arg_types An array of fully resolved argument types.
 * @param[in] num_args Total number of arguments.
 * @param[in] target_fn The target C function pointer.
 * @param[in] handlers An array of handler structs provided by the user.
 * @return `INFIX_SUCCESS` on success, or an error code on failure.
 */
static 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) {
    // Validation and Setup
    if (!out_trampoline || !return_type || (!arg_types && num_args > 0) || !target_fn || !handlers) {
        _infix_set_error(INFIX_CATEGORY_GENERAL, INFIX_CODE_NULL_POINTER, 0);
        return INFIX_ERROR_INVALID_ARGUMENT;
    }

    const infix_direct_forward_abi_spec * spec = get_current_direct_forward_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_direct_call_frame_layout * layout = nullptr;
    infix_forward_t * handle = nullptr;
    infix_arena_t * 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 buf;
    code_buffer_init(&buf, temp_arena);

    // 2. JIT Compilation Pipeline
    status = spec->prepare_direct_forward_call_frame(
        temp_arena, &layout, return_type, arg_types, num_args, handlers, target_fn);
    if (status != INFIX_SUCCESS)
        goto cleanup;

    status = spec->generate_direct_forward_prologue(&buf, layout);
    if (status != INFIX_SUCCESS)
        goto cleanup;

    status = spec->generate_direct_forward_argument_moves(&buf, layout);
    if (status != INFIX_SUCCESS)



( run in 1.059 second using v1.01-cache-2.11-cpan-437f7b0c052 )