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 )