Affix
view release on metacpan or search on metacpan
infix/src/jit/trampoline.c view on Meta::CPAN
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);
// "Estimate" stage: Calculate the exact size needed for the context's private arena.
size_t required_metadata_size = _estimate_metadata_size(temp_arena, return_type, arg_types, num_args);
// Create the context's private arena with the calculated size plus some headroom for safety.
context->arena = infix_arena_create(required_metadata_size + INFIX_TRAMPOLINE_HEADROOM);
if (context->arena == nullptr) {
status = INFIX_ERROR_ALLOCATION_FAILED;
goto cleanup;
}
// Populate the context fields.
context->protected_ctx = prot;
context->num_args = num_args;
context->num_fixed_args = num_fixed_args;
context->is_variadic = (num_fixed_args < num_args);
context->user_callback_fn = user_callback_fn;
context->user_data = user_data;
context->internal_dispatcher = infix_internal_dispatch_callback_fn_impl;
context->cached_forward_trampoline = nullptr;
// "Copy" stage: deep copy all types into the context's private arena.
context->return_type = _copy_type_graph_to_arena(context->arena, return_type);
if (num_args > 0) {
context->arg_types = infix_arena_alloc(context->arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
if (context->arg_types == nullptr) {
status = INFIX_ERROR_ALLOCATION_FAILED;
goto cleanup;
}
for (size_t i = 0; i < num_args; ++i) {
context->arg_types[i] = _copy_type_graph_to_arena(context->arena, arg_types[i]);
if (arg_types[i] != nullptr && context->arg_types[i] == nullptr) {
status = INFIX_ERROR_ALLOCATION_FAILED;
goto cleanup;
}
}
}
// Special step for type-safe callbacks: generate and cache a forward trampoline
// that will be used to call the user's type-safe C handler.
if (is_callback) {
status = infix_forward_create_manual(&context->cached_forward_trampoline,
context->return_type,
context->arg_types,
context->num_args,
context->num_fixed_args,
user_callback_fn);
if (status != INFIX_SUCCESS)
goto cleanup;
}
// JIT Compilation Pipeline for Reverse Stub
status = spec->prepare_reverse_call_frame(temp_arena, &layout, context);
if (status != INFIX_SUCCESS)
goto cleanup;
status = spec->generate_reverse_prologue(&buf, layout);
if (status != INFIX_SUCCESS)
goto cleanup;
status = spec->generate_reverse_argument_marshalling(&buf, layout, context);
if (status != INFIX_SUCCESS)
goto cleanup;
status = spec->generate_reverse_dispatcher_call(&buf, layout, context);
if (status != INFIX_SUCCESS)
goto cleanup;
status = spec->generate_reverse_epilogue(&buf, layout, context);
if (status != INFIX_SUCCESS)
goto cleanup;
// End of Pipeline
if (buf.error || temp_arena->error) {
status = INFIX_ERROR_ALLOCATION_FAILED;
goto cleanup;
}
context->exec = infix_executable_alloc(buf.size);
if (context->exec.rw_ptr == nullptr) {
status = INFIX_ERROR_ALLOCATION_FAILED;
goto cleanup;
}
infix_memcpy(context->exec.rw_ptr, buf.code, buf.size);
if (!infix_executable_make_executable(&context->exec, INFIX_EXECUTABLE_REVERSE, layout->prologue_size, 0)) {
status = INFIX_ERROR_PROTECTION_FAILED;
goto cleanup;
}
// Security Hardening: Make the context memory read-only to prevent runtime corruption.
if (!infix_protected_make_readonly(context->protected_ctx)) {
status = INFIX_ERROR_PROTECTION_FAILED;
goto cleanup;
}
infix_dump_hex(context->exec.rx_ptr, buf.size, "Reverse Trampoline Machine Code");
*out_context = context;
cleanup:
if (status != INFIX_SUCCESS) {
// If allocation of the context itself failed, prot.rw_ptr will be null.
if (prot.rw_ptr != nullptr)
infix_reverse_destroy(context);
}
infix_arena_destroy(temp_arena);
return status;
}
/**
* @brief Creates a type-safe reverse trampoline (callback) from `infix_type` objects (Manual API).
( run in 1.657 second using v1.01-cache-2.11-cpan-39bf76dae61 )