Affix
view release on metacpan or search on metacpan
infix/src/jit/trampoline.c view on Meta::CPAN
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)
return false;
// Cycle detection: if we've seen this node before, we can assume it's resolved
// for the purpose of this check, as we'll validate it on the first visit.
for (visited_node_t * v = visited_head; v != NULL; v = v->next)
if (v->type == type)
return true;
visited_node_t current_visited_node = {.type = type, .next = visited_head};
switch (type->category) {
case INFIX_TYPE_NAMED_REFERENCE:
return false; // Base case: an unresolved reference.
case INFIX_TYPE_POINTER:
return _is_type_graph_resolved_recursive(type->meta.pointer_info.pointee_type, ¤t_visited_node);
case INFIX_TYPE_ARRAY:
return _is_type_graph_resolved_recursive(type->meta.array_info.element_type, ¤t_visited_node);
case INFIX_TYPE_STRUCT:
case INFIX_TYPE_UNION:
for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i)
if (!_is_type_graph_resolved_recursive(type->meta.aggregate_info.members[i].type, ¤t_visited_node))
return false;
return true;
case INFIX_TYPE_REVERSE_TRAMPOLINE:
if (!_is_type_graph_resolved_recursive(type->meta.func_ptr_info.return_type, ¤t_visited_node))
return false;
for (size_t i = 0; i < type->meta.func_ptr_info.num_args; ++i)
if (!_is_type_graph_resolved_recursive(type->meta.func_ptr_info.args[i].type, ¤t_visited_node))
return false;
return true;
default:
return true; // Primitives, void, etc., are always resolved.
}
}
/**
* @internal
* @brief Public-internal wrapper for the recursive resolution check.
*/
static bool _is_type_graph_resolved(const infix_type * type) { return _is_type_graph_resolved_recursive(type, NULL); }
/**
* @internal
* @brief Estimates the memory required to store the type metadata for a function signature.
*
* This function iterates through the return and argument types, using the internal
* _infix_estimate_graph_size utility to sum the required bytes for a deep copy
* of all type information.
*
* @param temp_arena A temporary arena for the estimator's bookkeeping.
* @param return_type The function's return type.
* @param arg_types The array of argument types.
* @param num_args The number of arguments.
* @return The estimated size in bytes.
*/
static size_t _estimate_metadata_size(infix_arena_t * temp_arena,
infix_type * return_type,
infix_type ** arg_types,
size_t num_args) {
size_t total_size = 0;
total_size += _infix_estimate_graph_size(temp_arena, return_type);
if (arg_types != nullptr) {
// Add space for the arg_types pointer array itself.
total_size += sizeof(infix_type *) * num_args;
for (size_t i = 0; i < num_args; ++i)
total_size += _infix_estimate_graph_size(temp_arena, arg_types[i]);
}
return total_size;
( run in 2.361 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )