Affix
view release on metacpan or search on metacpan
infix/src/jit/trampoline.c view on Meta::CPAN
return nullptr;
#endif
}
/**
* @internal
* @brief Retrieves a pointer to the ABI specification v-table for reverse calls.
* @return A pointer to the active `infix_reverse_abi_spec`, or `nullptr` if the
* platform is unsupported.
*/
const infix_reverse_abi_spec * get_current_reverse_abi_spec() {
#if defined(INFIX_ABI_WINDOWS_X64)
return &g_win_x64_reverse_spec;
#elif defined(INFIX_ABI_SYSV_X64)
return &g_sysv_x64_reverse_spec;
#elif defined(INFIX_ABI_AAPCS64)
return &g_arm64_reverse_spec;
#else
return nullptr;
#endif
}
/**
* @internal
* @brief Retrieves a pointer to the ABI v-table for direct marshalling forward calls.
* @return A pointer to the active `infix_direct_forward_abi_spec`, or `nullptr`.
*/
const infix_direct_forward_abi_spec * get_current_direct_forward_abi_spec() {
#if defined(INFIX_ABI_WINDOWS_X64)
return &g_win_x64_direct_forward_spec;
#elif defined(INFIX_ABI_SYSV_X64)
return &g_sysv_x64_direct_forward_spec;
#elif defined(INFIX_ABI_AAPCS64)
return &g_arm64_direct_forward_spec;
#else
return nullptr;
#endif
}
// Code Buffer Implementation
/**
* @internal
* @brief Initializes a `code_buffer` for JIT code generation.
* @param buf A pointer to the `code_buffer` to initialize.
* @param arena The temporary arena to use for the buffer's memory.
*/
void code_buffer_init(code_buffer * buf, infix_arena_t * arena) {
buf->capacity = 64; // Start with a small initial capacity.
buf->arena = arena;
buf->code = infix_arena_alloc(arena, buf->capacity, 16);
buf->size = 0;
buf->error = (buf->code == nullptr);
}
/**
* @internal
* @brief Appends data to a `code_buffer`, reallocating from its arena if necessary.
*
* @details If the buffer runs out of space, it doubles its capacity until the new data
* fits. All allocations happen within the temporary arena, so no manual `free` or
* `realloc` calls are needed; cleanup is automatic when the arena is destroyed.
*
* @param buf The code buffer.
* @param data A pointer to the data to append.
* @param len The length of the data in bytes.
*/
void code_buffer_append(code_buffer * buf, const void * data, size_t len) {
if (buf->error)
return;
if (len > SIZE_MAX - buf->size) { // Overflow check
buf->error = true;
_infix_set_error(INFIX_CATEGORY_ALLOCATION, INFIX_CODE_INTEGER_OVERFLOW, 0);
return;
}
if (buf->size + len > buf->capacity) {
size_t new_capacity = buf->capacity;
while (new_capacity < buf->size + len) {
if (new_capacity > SIZE_MAX / 2) { // Overflow check
buf->error = true;
_infix_set_error(INFIX_CATEGORY_ALLOCATION, INFIX_CODE_INTEGER_OVERFLOW, 0);
return;
}
new_capacity *= 2;
}
void * new_code = infix_arena_alloc(buf->arena, new_capacity, 16);
if (new_code == nullptr) {
buf->error = true;
// infix_arena_alloc already sets INFIX_CODE_OUT_OF_MEMORY, so we don't need to override it here
return;
}
infix_memcpy(new_code, buf->code, buf->size);
buf->code = new_code;
buf->capacity = new_capacity;
}
infix_memcpy(buf->code + buf->size, data, len);
buf->size += len;
}
/** @internal @brief Appends a single byte to the code buffer. */
void emit_byte(code_buffer * buf, uint8_t byte) { code_buffer_append(buf, &byte, 1); }
/** @internal @brief Appends a 32-bit integer (little-endian) to the code buffer. */
void emit_int32(code_buffer * buf, int32_t value) { code_buffer_append(buf, &value, 4); }
/** @internal @brief Appends a 64-bit integer (little-endian) to the code buffer. */
void emit_int64(code_buffer * buf, int64_t value) { code_buffer_append(buf, &value, 8); }
// Type Graph Validation
/** @internal A node for a visited list to detect cycles in `_is_type_graph_resolved_recursive`. */
typedef struct visited_node_t {
const infix_type * type;
struct visited_node_t * next;
} visited_node_t;
/**
* @internal
* @brief Recursively checks if a type graph is fully resolved (contains no named references).
*
* This is a critical pre-flight check before passing a type graph to the ABI
* classification layer, which expects all types to have concrete size and
* alignment information. An unresolved `@Name` node would cause it to fail.
*
* @param type The type to check.
* @param visited_head A list to track visited nodes and prevent infinite recursion on cycles.
* @return `true` if the graph is fully resolved, `false` otherwise.
*/
static bool _is_type_graph_resolved_recursive(const infix_type * type, visited_node_t * visited_head) {
if (!type)
return true;
if (type->is_incomplete)
( run in 0.614 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )