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 )