Affix

 view release on metacpan or  search on metacpan

infix/src/common/infix_internals.h  view on Meta::CPAN

/**
 * Copyright (c) 2025 Sanko Robinson
 *
 * This source code is dual-licensed under the Artistic License 2.0 or the MIT License.
 * You may choose to use this code under the terms of either license.
 *
 * SPDX-License-Identifier: (Artistic-2.0 OR MIT)
 *
 * The documentation blocks within this file are licensed under the
 * Creative Commons Attribution 4.0 International License (CC BY 4.0).
 *
 * SPDX-License-Identifier: CC-BY-4.0
 */
/**
 * @file infix_internals.h
 * @brief Internal data structures, function prototypes, and constants.
 * @ingroup internal_common
 *
 * @details This is the primary internal header for the `infix` library. It defines the
 * complete layout of all opaque public structs (like `infix_forward_t`) and
 * declares internal-only functions (`_infix_*`) that are shared between modules.
 *
 * Its most important role is to define the core ABI abstraction layer through v-tables
 * (`infix_forward_abi_spec`, `infix_reverse_abi_spec`). These structures form the
 * contract between the platform-agnostic JIT engine (`trampoline.c`) and the
 * platform-specific ABI implementations (`arch/...`), making them key to the
 * library's portability and architectural design.
 *
 * This header also brings together all other internal type definitions, creating a
 * single source of truth for the library's internal data model.
 * @internal
 */
#pragma once
#include "common/infix_config.h"
#include "common/platform.h"
#include <infix/infix.h>
/**
 * @struct infix_executable_t
 * @brief Internal representation of an executable memory block for JIT code.
 *
 * @details This struct encapsulates the platform-specific details of allocating and
 * managing executable memory in a way that is compliant with modern OS security
 * features like W^X (Write XOR Execute). It supports two primary strategies:
 *
 * 1.  **Single-Mapping W^X (Windows/macOS/Android):** A single memory region is
 *     allocated as Read-Write (`rw_ptr`). After the JIT compiler writes the
 *     machine code to this region, its permissions are changed to Read-Execute.
 *     In this model, `rx_ptr` and `rw_ptr` point to the same address.
 *
 * 2.  **Dual-Mapping W^X (Linux/BSD):** A single underlying shared memory object
 *     is mapped into the process's address space twice: once as Read-Write
 *     (`rw_ptr`) and once as Read-Execute (`rx_ptr`). The pointers have different
 *     virtual addresses but point to the same physical memory. This is required
 *     on systems with stricter W^X enforcement.
 */
typedef struct {
#if defined(INFIX_OS_WINDOWS)
    HANDLE handle;           /**< The handle from `VirtualAlloc`, needed for `VirtualFree`. */
    void * seh_registration; /**< (Windows x64) Opaque handle from `RtlAddFunctionTable`. */
#else
    int shm_fd;          /**< The file descriptor for shared memory on dual-mapping POSIX systems. -1 otherwise. */
    void * eh_frame_ptr; /**< (POSIX) Pointer to the registered .eh_frame data. */
#endif
    void * rx_ptr; /**< The read-execute memory address. This is the callable function pointer. */
    void * rw_ptr; /**< The read-write memory address. The JIT compiler writes machine code here. */
    size_t size;   /**< The size of the allocated memory region in bytes. */
} infix_executable_t;
/**
 * @struct infix_protected_t
 * @brief Internal representation of a memory block that will be made read-only.
 *
 * @details This is used to harden the `infix_reverse_t` context against runtime
 * memory corruption. The context is allocated in a standard read-write memory
 * region, fully populated, and then its permissions are changed to read-only
 * using this handle.
 */
typedef struct {
    void * rw_ptr; /**< The read-write pointer before being made read-only. */
    size_t size;   /**< The size of the allocated memory region in bytes. */
} infix_protected_t;

infix/src/common/infix_internals.h  view on Meta::CPAN

    uint32_t prologue_size;          ///< Size of the generated prologue in bytes.
    uint32_t epilogue_offset;        ///< Offset from the start of the JIT block to the epilogue.
} infix_direct_call_frame_layout;

/**
 * @brief Defines the ABI-specific implementation interface for direct marshalling forward trampolines.
 *
 * This v-table defines the contract for generating a high-performance, direct-marshalling
 * trampoline. It is parallel to `infix_forward_abi_spec`.
 */
typedef struct {
    /** @brief Analyzes a function signature to create a complete direct call frame layout.     */
    infix_status (*prepare_direct_forward_call_frame)(infix_arena_t * arena,
                                                      infix_direct_call_frame_layout ** out_layout,
                                                      infix_type * ret_type,
                                                      infix_type ** arg_types,
                                                      size_t num_args,
                                                      infix_direct_arg_handler_t * handlers,
                                                      void * target_fn);
    /** @brief Generates the function prologue (stack setup, saving registers).   */
    infix_status (*generate_direct_forward_prologue)(code_buffer * buf, infix_direct_call_frame_layout * layout);
    /** @brief Generates code to call marshallers and move arguments into their native locations.     */
    infix_status (*generate_direct_forward_argument_moves)(code_buffer * buf, infix_direct_call_frame_layout * layout);
    /** @brief Generates the `call` instruction to the target function. */
    infix_status (*generate_direct_forward_call_instruction)(code_buffer * buf,
                                                             infix_direct_call_frame_layout * layout);
    /** @brief Generates the function epilogue (handling return value, calling write-back handlers, returning).   */
    infix_status (*generate_direct_forward_epilogue)(code_buffer * buf,
                                                     infix_direct_call_frame_layout * layout,
                                                     infix_type * ret_type);

} infix_direct_forward_abi_spec;

// Internal Function Prototypes (Shared across modules)
/**
 * @brief Sets the thread-local error state with detailed information.
 * @details Located in `src/core/error.c`, this function is the primary mechanism
 * for reporting errors from within the library. It populates the thread-local
 * `g_infix_last_error` struct. For parser errors, it generates a rich diagnostic
 * message with a code snippet.
 * @param category The general category of the error.
 * @param code The specific error code.
 * @param position For parser errors, the byte offset into the signature string where the error occurred.
 */
INFIX_INTERNAL void _infix_set_error(infix_error_category_t category, infix_error_code_t code, size_t position);
/**
 * @brief Sets the thread-local error state for a system-level error.
 * @details Located in `src/core/error.c`, this is used for errors originating from
 * the operating system, such as `dlopen` or `mmap` failures.
 * @param category The general category of the error.
 * @param code The `infix` error code that corresponds to the failure.
 * @param system_code The OS-specific error code (e.g., from `errno` or `GetLastError`).
 * @param msg An optional custom message from the OS (e.g., from `dlerror`).
 */
INFIX_INTERNAL void _infix_set_system_error(infix_error_category_t category,
                                            infix_error_code_t code,
                                            long system_code,
                                            const char * msg);
/**
 * @brief Clears the thread-local error state.
 * @details Located in `src/core/error.c`. This is called at the beginning of every public
 * API function to ensure that a prior error from an unrelated call is not accidentally returned.
 */
INFIX_INTERNAL void _infix_clear_error(void);
INFIX_INTERNAL void skip_whitespace(parser_state * state);
INFIX_INTERNAL void _infix_set_parser_error(parser_state * state, infix_error_code_t code);
INFIX_INTERNAL infix_type * parse_type(parser_state * state);
INFIX_INTERNAL infix_type * parse_primitive(parser_state * state);

/**
 * @brief Recalculates the layout of a fully resolved type graph.
 * @details Located in `src/core/types.c`. This is the "Layout" stage of the data pipeline.
 * It recursively walks a type graph and computes the final `size`, `alignment`, and
 * member `offset` fields for all aggregate types. It must only be called on a fully
 * resolved graph.
 * @param[in,out] type The root of the type graph to recalculate. The graph is modified in-place.
 */
INFIX_INTERNAL void _infix_type_recalculate_layout(infix_type * type);
/**
 * @brief Resolves all named type references in a type graph in-place.
 * @details Located in `src/core/type_registry.c`. This is the "Resolve" stage of the
 * data pipeline. It traverses a type graph and replaces all `INFIX_TYPE_NAMED_REFERENCE`
 * nodes (`@Name`) with direct pointers to the canonical `infix_type` objects from the registry.
 * @param[in,out] type_ptr A pointer to the root of the type graph to resolve. The pointer may be changed.
 * @param[in] registry The registry to use for lookups.
 * @return `INFIX_SUCCESS` on success, or an error if a name cannot be resolved.
 */
INFIX_INTERNAL c23_nodiscard infix_status _infix_resolve_type_graph_inplace(infix_type ** type_ptr,
                                                                            infix_registry_t * registry);
/**
 * @brief The internal core of the signature parser.
 * @details Located in `src/core/signature.c`. This is the "Parse" stage of the data pipeline.
 * It takes a signature string and produces a raw, unresolved `infix_type` graph in a new,
 * temporary arena. It does not perform any copying, resolution, or layout calculation.
 * @param[out] out_type On success, receives the parsed type graph.
 * @param[out] out_arena On success, receives the temporary arena holding the graph.
 * @param[in] signature The signature string to parse.
 * @return `INFIX_SUCCESS` on success.
 */
INFIX_INTERNAL c23_nodiscard infix_status _infix_parse_type_internal(infix_type **, infix_arena_t **, const char *);
/**
 * @brief An internal-only function to serialize a type's body without its registered name.
 * @details Located in `src/core/signature.c`. Unlike `infix_type_print`, which will
 * print `@Name` for a named struct, this function will always print the full `{...}`
 * body. This is essential for `infix_registry_print` to function correctly.
 * @param[out] buffer The output buffer.
 * @param[in] buffer_size The size of the buffer.
 * @param[in] type The type to print.
 * @param[in] dialect The output format dialect.
 * @return `INFIX_SUCCESS` on success.
 */
INFIX_INTERNAL c23_nodiscard infix_status _infix_type_print_body_only(char *,
                                                                      size_t,
                                                                      const infix_type *,
                                                                      infix_print_dialect_t);
/**
 * @brief Performs a deep copy of a type graph into a destination arena.
 * @details Located in `src/core/types.c`. This is the "Copy" stage of the data pipeline,
 * crucial for creating self-contained trampoline objects and ensuring memory safety. It uses
 * memoization to correctly handle cycles and shared type objects.
 * @param[in] dest_arena The destination arena for the new type graph.



( run in 2.219 seconds using v1.01-cache-2.11-cpan-437f7b0c052 )