infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
trampoline.c
Go to the documentation of this file.
1
39#include "common/utility.h"
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#if defined(INFIX_OS_MACOS)
44#include <pthread.h>
45#endif
46#if defined(INFIX_OS_WINDOWS)
47#include <windows.h>
48#else
49#include <sys/mman.h>
50#include <unistd.h>
51#endif
52// Forward Declaration for Internal Creation Function
56 size_t num_args,
57 size_t num_fixed_args,
58 void * user_callback_fn,
59 void * user_data,
60 bool is_callback);
61// ABI Specification V-Table Declarations (extern to link to the specific implementations)
62#if defined(INFIX_ABI_WINDOWS_X64)
66#elif defined(INFIX_ABI_SYSV_X64)
70#elif defined(INFIX_ABI_AAPCS64)
74#elif defined(INFIX_ABI_RISCV64)
78#endif
89#if defined(INFIX_ABI_WINDOWS_X64)
91#elif defined(INFIX_ABI_SYSV_X64)
93#elif defined(INFIX_ABI_AAPCS64)
95#elif defined(INFIX_ABI_RISCV64)
97#else
98 return nullptr;
99#endif
100}
108#if defined(INFIX_ABI_WINDOWS_X64)
110#elif defined(INFIX_ABI_SYSV_X64)
112#elif defined(INFIX_ABI_AAPCS64)
113 return &g_arm64_reverse_spec;
114#elif defined(INFIX_ABI_RISCV64)
116#else
117 return nullptr;
118#endif
119}
126#if defined(INFIX_ABI_WINDOWS_X64)
128#elif defined(INFIX_ABI_SYSV_X64)
130#elif defined(INFIX_ABI_AAPCS64)
132#elif defined(INFIX_ABI_RISCV64)
134#else
135 return nullptr;
136#endif
137}
138// Code Buffer Implementation
146 buf->capacity = 64; // Start with a small initial capacity.
147 buf->arena = arena;
148 buf->code = infix_arena_alloc(arena, buf->capacity, 16);
149 buf->size = 0;
150 buf->error = (buf->code == nullptr);
151}
164void code_buffer_append(code_buffer * buf, const void * data, size_t len) {
165 if (buf->error)
166 return;
167 if (len > SIZE_MAX - buf->size) { // Overflow check
168 buf->error = true;
170 return;
171 }
172 if (buf->size + len > buf->capacity) {
173 size_t new_capacity = buf->capacity;
174 while (new_capacity < buf->size + len) {
175 if (new_capacity > SIZE_MAX / 2) { // Overflow check
176 buf->error = true;
178 return;
179 }
180 new_capacity *= 2;
181 }
182 void * new_code = infix_arena_alloc(buf->arena, new_capacity, 16);
183 if (new_code == nullptr) {
184 buf->error = true;
185 // infix_arena_alloc already sets INFIX_CODE_OUT_OF_MEMORY, so we don't need to override it here
186 return;
187 }
188 infix_memcpy(new_code, buf->code, buf->size);
189 buf->code = new_code;
190 buf->capacity = new_capacity;
191 }
192 infix_memcpy(buf->code + buf->size, data, len);
193 buf->size += len;
194}
196void emit_byte(code_buffer * buf, uint8_t byte) { code_buffer_append(buf, &byte, 1); }
198void emit_int32(code_buffer * buf, int32_t value) { code_buffer_append(buf, &value, 4); }
200void emit_int64(code_buffer * buf, int64_t value) { code_buffer_append(buf, &value, 8); }
201// Type Graph Validation
220 if (!type)
221 return true;
222 if (type->is_incomplete)
223 return false;
224 // Cycle detection: if we've seen this node before, we can assume it's resolved
225 // for the purpose of this check, as we'll validate it on the first visit.
226 for (visited_node_t * v = visited_head; v != NULL; v = v->next)
227 if (v->type == type)
228 return true;
229 visited_node_t current_visited_node = {.type = type, .next = visited_head};
230 switch (type->category) {
232 return false; // Base case: an unresolved reference.
235 case INFIX_TYPE_ARRAY:
236 return _is_type_graph_resolved_recursive(type->meta.array_info.element_type, &current_visited_node);
238 case INFIX_TYPE_UNION:
239 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i)
240 if (!_is_type_graph_resolved_recursive(type->meta.aggregate_info.members[i].type, &current_visited_node))
241 return false;
242 return true;
245 return false;
246 for (size_t i = 0; i < type->meta.func_ptr_info.num_args; ++i)
247 if (!_is_type_graph_resolved_recursive(type->meta.func_ptr_info.args[i].type, &current_visited_node))
248 return false;
249 return true;
250 default:
251 return true; // Primitives, void, etc., are always resolved.
252 }
253}
273static size_t _estimate_metadata_size(infix_arena_t * temp_arena,
276 size_t num_args) {
277 size_t total_size = 0;
278 total_size += _infix_estimate_graph_size(temp_arena, return_type);
279 if (arg_types != nullptr) {
280 // Add space for the arg_types pointer array itself.
281 total_size += sizeof(infix_type *) * num_args;
282 for (size_t i = 0; i < num_args; ++i)
283 total_size += _infix_estimate_graph_size(temp_arena, arg_types[i]);
284 }
285 return total_size;
286}
287// Forward Trampoline API Implementation
289 if (trampoline == nullptr || trampoline->is_direct_trampoline || trampoline->target_fn != nullptr)
290 return nullptr;
291 return (infix_unbound_cif_func)trampoline->exec.rx_ptr;
292}
294 if (trampoline == nullptr || trampoline->is_direct_trampoline || trampoline->target_fn == nullptr)
295 return nullptr;
296 return (infix_cif_func)trampoline->exec.rx_ptr;
297}
299 if (trampoline == nullptr || !trampoline->is_direct_trampoline)
300 return nullptr;
301 return (infix_direct_cif_func)trampoline->exec.rx_ptr;
302}
327 infix_arena_t * target_arena,
330 size_t num_args,
331 size_t num_fixed_args,
332 void * target_fn,
333 bool is_safe) {
334 if (out_trampoline == nullptr || return_type == nullptr || (arg_types == nullptr && num_args > 0)) {
337 }
338 // Pre-flight check: ensure all types are resolved before passing to ABI layer.
342 }
343 for (size_t i = 0; i < num_args; ++i) {
344 if (arg_types[i] == nullptr || !_is_type_graph_resolved(arg_types[i])) {
347 }
348 }
349
351 infix_call_frame_layout * layout = nullptr;
352 infix_forward_t * handle = nullptr;
353
354 // Use a temporary arena for all intermediate allocations during code generation.
355 infix_arena_t * temp_arena = infix_arena_create(65536);
356 if (!temp_arena) {
359 }
360
361 // --- Cache Lookup Stage ---
362 // Generate a canonical signature for deduplication.
363 char canonical_sig[8192];
364 infix_status sig_status = INFIX_SUCCESS;
365 {
366 // Construct a temporary argument array for the printer.
367 infix_function_argument * tmp_args = nullptr;
368 if (num_args > 0) {
369 tmp_args =
370 infix_arena_alloc(temp_arena, sizeof(infix_function_argument) * num_args, _Alignof(infix_type *));
371 if (!tmp_args) {
373 goto cleanup;
374 }
375 for (size_t i = 0; i < num_args; ++i) {
376 tmp_args[i].type = arg_types[i];
377 tmp_args[i].name = nullptr;
378 }
379 }
380 sig_status = infix_function_print(canonical_sig,
381 sizeof(canonical_sig),
382 "func",
384 tmp_args,
385 num_args,
386 num_fixed_args,
388 }
389
390 if (sig_status == INFIX_SUCCESS) {
391 infix_forward_t * cached = _infix_cache_lookup(canonical_sig, target_fn, is_safe);
392 if (cached) {
393 *out_trampoline = cached;
395 goto cleanup;
396 }
397 }
398
400 if (spec == nullptr) {
403 goto cleanup;
404 }
405
406 code_buffer buf;
407 code_buffer_init(&buf, temp_arena);
408 // JIT Compilation Pipeline
409 // Prepare: Classify arguments and create the layout blueprint.
411 temp_arena, &layout, return_type, arg_types, num_args, num_fixed_args, target_fn);
412 if (status != INFIX_SUCCESS)
413 goto cleanup;
414 // 2. Generate: Emit machine code based on the layout.
415 status = spec->generate_forward_prologue(&buf, layout);
416 if (status != INFIX_SUCCESS)
417 goto cleanup;
418 status = spec->generate_forward_argument_moves(&buf, layout, arg_types, num_args, num_fixed_args);
419 if (status != INFIX_SUCCESS)
420 goto cleanup;
421 status = spec->generate_forward_call_instruction(&buf, layout);
422 if (status != INFIX_SUCCESS)
423 goto cleanup;
424 status = spec->generate_forward_epilogue(&buf, layout, return_type);
425 if (status != INFIX_SUCCESS)
426 goto cleanup;
427 if (buf.error || temp_arena->error) {
429 goto cleanup;
430 }
431 // Finalize Handle
432 handle = infix_calloc(1, sizeof(infix_forward_t));
433 if (handle == nullptr) {
435 goto cleanup;
436 }
437 // "Estimate" stage: Calculate the exact size needed for the handle's private arena.
438 size_t required_metadata_size = _estimate_metadata_size(temp_arena, return_type, arg_types, num_args);
439 if (target_arena) {
440 handle->arena = target_arena;
441 handle->is_external_arena = true;
442 }
443 else {
444 handle->arena = infix_arena_create(required_metadata_size + INFIX_TRAMPOLINE_HEADROOM);
445 handle->is_external_arena = false;
446 }
447 if (handle->arena == nullptr) {
449 goto cleanup;
450 }
451 // "Copy" stage: Deep copy all type info into the handle's private arena.
453 if (num_args > 0) {
454 handle->arg_types = infix_arena_alloc(handle->arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
455 if (handle->arg_types == nullptr) {
457 goto cleanup;
458 }
459 for (size_t i = 0; i < num_args; ++i) {
460 handle->arg_types[i] = _copy_type_graph_to_arena(handle->arena, arg_types[i]);
461 // Check for allocation failure during copy
462 if (arg_types[i] != nullptr && handle->arg_types[i] == nullptr && !handle->arena->error) {
464 goto cleanup;
465 }
466 }
467 }
468 handle->num_args = num_args;
469 handle->num_fixed_args = num_fixed_args;
470 handle->target_fn = target_fn;
471 handle->is_safe = is_safe;
472 handle->ref_count = 1;
473
474 // Save the canonical signature for the cache key.
475 if (sig_status == INFIX_SUCCESS) {
476 size_t sig_len = strlen(canonical_sig) + 1;
477 handle->signature = infix_arena_alloc(handle->arena, sig_len, 1);
478 if (handle->signature)
479 infix_memcpy(handle->signature, canonical_sig, sig_len);
480 }
481
482 // Allocate and finalize executable memory.
483 handle->exec = infix_executable_alloc(buf.size);
484 if (handle->exec.rw_ptr == nullptr) {
486 goto cleanup;
487 }
488 infix_memcpy(handle->exec.rw_ptr, buf.code, buf.size);
491 layout->prologue_size,
492 layout->epilogue_offset)) {
494 goto cleanup;
495 }
496 infix_dump_hex(handle->exec.rx_ptr, handle->exec.size, "Forward Trampoline Machine Code");
497 *out_trampoline = handle;
498
499 // Cache the newly created trampoline.
500 // We ONLY cache if we own the arena. If the user provided an external arena,
501 // they control the lifetime, and we can't guarantee the signature string
502 // (which is in that arena) will remain valid as long as the cache entry exists.
503 if (handle->signature && !handle->is_external_arena)
504 _infix_cache_insert(handle);
505
506cleanup:
507 // If any step failed, ensure the partially created handle is fully destroyed.
508 if (status != INFIX_SUCCESS && handle != nullptr)
509 infix_forward_destroy(handle);
510 // The temporary arena is always destroyed.
511 infix_arena_destroy(temp_arena);
512 return status;
513}
542 size_t num_args,
543 void * target_fn,
545 // Validation and Setup
546 if (!out_trampoline || !return_type || (!arg_types && num_args > 0) || !target_fn || !handlers) {
549 }
550
552 if (spec == nullptr) {
555 }
556
558 infix_direct_call_frame_layout * layout = nullptr;
559 infix_forward_t * handle = nullptr;
560 infix_arena_t * temp_arena = infix_arena_create(65536);
561 if (!temp_arena) {
564 }
565 code_buffer buf;
566 code_buffer_init(&buf, temp_arena);
567
568 // Finalize the handle before code generation
569 handle = infix_calloc(1, sizeof(infix_forward_t));
570 if (handle == nullptr) {
572 goto cleanup;
573 }
574
575 handle->is_direct_trampoline = true; // Mark this as a direct marshalling trampoline.
576
577 size_t required_metadata_size = _estimate_metadata_size(temp_arena, return_type, arg_types, num_args);
578 handle->arena = infix_arena_create(required_metadata_size + INFIX_TRAMPOLINE_HEADROOM);
579 handle->is_external_arena = false;
580 if (handle->arena == nullptr) {
582 goto cleanup;
583 }
584
586 if (num_args > 0) {
587 handle->arg_types = infix_arena_alloc(handle->arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
588 if (!handle->arg_types) {
590 goto cleanup;
591 }
592 for (size_t i = 0; i < num_args; ++i) {
593 handle->arg_types[i] = _copy_type_graph_to_arena(handle->arena, arg_types[i]);
594 if (arg_types[i] && !handle->arg_types[i] && !handle->arena->error) {
596 goto cleanup;
597 }
598 }
599 }
600 handle->num_args = num_args;
601 handle->num_fixed_args = num_args; // Direct trampolines are always fixed-arity.
602 handle->target_fn = target_fn;
603 handle->ref_count = 1;
604
605 // Pass the stable type metadata so the machine code embeds pointers
606 // that live as long as the trampoline itself
608 temp_arena, &layout, handle->return_type, handle->arg_types, num_args, handlers, target_fn);
609 if (status != INFIX_SUCCESS)
610 goto cleanup;
611
612 status = spec->generate_direct_forward_prologue(&buf, layout);
613 if (status != INFIX_SUCCESS)
614 goto cleanup;
615
617 if (status != INFIX_SUCCESS)
618 goto cleanup;
619
621 if (status != INFIX_SUCCESS)
622 goto cleanup;
623
624 status = spec->generate_direct_forward_epilogue(&buf, layout, handle->return_type);
625 if (status != INFIX_SUCCESS)
626 goto cleanup;
627
628 if (buf.error || temp_arena->error) {
630 goto cleanup;
631 }
632
633 // Allocate and Finalize Executable Memory
634 handle->exec = infix_executable_alloc(buf.size);
635 if (handle->exec.rw_ptr == nullptr) {
637 goto cleanup;
638 }
639 infix_memcpy(handle->exec.rw_ptr, buf.code, buf.size);
641 &handle->exec, INFIX_EXECUTABLE_DIRECT, layout->prologue_size, layout->epilogue_offset)) {
643 goto cleanup;
644 }
645
646 infix_dump_hex(handle->exec.rx_ptr, handle->exec.size, "Direct-Marshalling Forward Trampoline Machine Code");
647 *out_trampoline = handle;
648
649cleanup:
650 if (status != INFIX_SUCCESS && handle != nullptr)
651 infix_forward_destroy(handle);
652 infix_arena_destroy(temp_arena);
653 return status;
654}
676 size_t num_args,
677 size_t num_fixed_args,
678 void * target_function) {
679 // This is part of the "Manual API". It calls the internal implementation directly
680 // without involving the signature parser. `source_arena` is null because the
681 // types are assumed to be managed by the user.
684 out_trampoline, nullptr, return_type, arg_types, num_args, num_fixed_args, target_function, false);
685}
702 size_t num_args,
703 size_t num_fixed_args) {
706 out_trampoline, nullptr, return_type, arg_types, num_args, num_fixed_args, nullptr, false);
707}
713 if (trampoline == nullptr)
714 return;
715 // Destroying the private arena frees all deep-copied type metadata and the signature string.
716 if (trampoline->arena && !trampoline->is_external_arena)
717 infix_arena_destroy(trampoline->arena);
718 // Free the JIT-compiled executable code.
719 infix_executable_free(trampoline->exec);
720 // Free the handle struct itself.
721 infix_free(trampoline);
722}
723
732// Reverse Trampoline API Implementation
738static size_t get_page_size() {
739#if defined(INFIX_OS_WINDOWS)
740 SYSTEM_INFO sysInfo;
741 GetSystemInfo(&sysInfo);
742 return sysInfo.dwPageSize;
743#else
744 // sysconf is the standard POSIX way to get system configuration values.
745 return sysconf(_SC_PAGESIZE);
746#endif
747}
774 size_t num_args,
775 size_t num_fixed_args,
776 void * user_callback_fn,
777 void * user_data,
778 bool is_callback) {
779 if (out_context == nullptr || return_type == nullptr || num_fixed_args > num_args) {
782 }
783 // Pre-flight check: ensure all types are fully resolved.
787 }
788 if (arg_types == nullptr && num_args > 0) {
791 }
792 for (size_t i = 0; i < num_args; ++i) {
793 if (arg_types[i] == nullptr || !_is_type_graph_resolved(arg_types[i])) {
796 }
797 }
799 if (spec == nullptr) {
802 }
804 infix_reverse_call_frame_layout * layout = nullptr;
805 infix_reverse_t * context = nullptr;
806 infix_arena_t * temp_arena = nullptr;
807 infix_protected_t prot = {.rw_ptr = nullptr, .size = 0};
808 code_buffer buf;
809 temp_arena = infix_arena_create(65536);
810 if (!temp_arena) {
813 }
814 code_buffer_init(&buf, temp_arena);
815 // Security Hardening: Allocate the context struct itself in special, page-aligned
816 // memory that can be made read-only after initialization.
817 size_t page_size = get_page_size();
818 size_t context_alloc_size = (sizeof(infix_reverse_t) + page_size - 1) & ~(page_size - 1);
819 prot = infix_protected_alloc(context_alloc_size);
820 if (prot.rw_ptr == nullptr) {
822 goto cleanup;
823 }
824 context = (infix_reverse_t *)prot.rw_ptr;
825 infix_memset(context, 0, context_alloc_size);
826 // "Estimate" stage: Calculate the exact size needed for the context's private arena.
827 size_t required_metadata_size = _estimate_metadata_size(temp_arena, return_type, arg_types, num_args);
828 // Create the context's private arena with the calculated size plus some headroom for safety.
829 context->arena = infix_arena_create(required_metadata_size + INFIX_TRAMPOLINE_HEADROOM);
830 if (context->arena == nullptr) {
832 goto cleanup;
833 }
834 // Populate the context fields.
835 context->protected_ctx = prot;
836 context->num_args = num_args;
837 context->num_fixed_args = num_fixed_args;
838 context->is_variadic = (num_fixed_args < num_args);
839 context->user_callback_fn = user_callback_fn;
840 context->user_data = user_data;
842 context->cached_forward_trampoline = nullptr;
843 // "Copy" stage: deep copy all types into the context's private arena.
845 if (num_args > 0) {
846 context->arg_types = infix_arena_alloc(context->arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
847 if (context->arg_types == nullptr) {
849 goto cleanup;
850 }
851 for (size_t i = 0; i < num_args; ++i) {
852 context->arg_types[i] = _copy_type_graph_to_arena(context->arena, arg_types[i]);
853 if (arg_types[i] != nullptr && context->arg_types[i] == nullptr) {
855 goto cleanup;
856 }
857 }
858 }
859 // Special step for type-safe callbacks: generate and cache a forward trampoline
860 // that will be used to call the user's type-safe C handler.
861 if (is_callback) {
863 context->return_type,
864 context->arg_types,
865 context->num_args,
866 context->num_fixed_args,
867 user_callback_fn);
868 if (status != INFIX_SUCCESS)
869 goto cleanup;
870 }
871 // JIT Compilation Pipeline for Reverse Stub
872 status = spec->prepare_reverse_call_frame(temp_arena, &layout, context);
873 if (status != INFIX_SUCCESS)
874 goto cleanup;
875 status = spec->generate_reverse_prologue(&buf, layout);
876 if (status != INFIX_SUCCESS)
877 goto cleanup;
878 status = spec->generate_reverse_argument_marshalling(&buf, layout, context);
879 if (status != INFIX_SUCCESS)
880 goto cleanup;
881 status = spec->generate_reverse_dispatcher_call(&buf, layout, context);
882 if (status != INFIX_SUCCESS)
883 goto cleanup;
884 status = spec->generate_reverse_epilogue(&buf, layout, context);
885 if (status != INFIX_SUCCESS)
886 goto cleanup;
887 // End of Pipeline
888 if (buf.error || temp_arena->error) {
890 goto cleanup;
891 }
892 context->exec = infix_executable_alloc(buf.size);
893 if (context->exec.rw_ptr == nullptr) {
895 goto cleanup;
896 }
897 infix_memcpy(context->exec.rw_ptr, buf.code, buf.size);
900 goto cleanup;
901 }
902 // Security Hardening: Make the context memory read-only to prevent runtime corruption.
905 goto cleanup;
906 }
907 infix_dump_hex(context->exec.rx_ptr, buf.size, "Reverse Trampoline Machine Code");
908 *out_context = context;
909cleanup:
910 if (status != INFIX_SUCCESS) {
911 // If allocation of the context itself failed, prot.rw_ptr will be null.
912 if (prot.rw_ptr != nullptr)
913 infix_reverse_destroy(context);
914 }
915 infix_arena_destroy(temp_arena);
916 return status;
917}
931 size_t num_args,
932 size_t num_fixed_args,
933 void * user_callback_fn) {
934
937 out_context, return_type, arg_types, num_args, num_fixed_args, user_callback_fn, nullptr, true);
938}
953 size_t num_args,
954 size_t num_fixed_args,
955 infix_closure_handler_fn user_callback_fn,
956 void * user_data) {
957
960 out_context, return_type, arg_types, num_args, num_fixed_args, (void *)user_callback_fn, user_data, false);
961}
970 if (reverse_trampoline == nullptr)
971 return;
972 // The cached trampoline (if it exists) must also be destroyed.
973 if (reverse_trampoline->cached_forward_trampoline)
975 if (reverse_trampoline->arena)
976 infix_arena_destroy(reverse_trampoline->arena);
977 infix_executable_free(reverse_trampoline->exec);
978 // Free the special read-only memory region for the context struct.
979 infix_protected_free(reverse_trampoline->protected_ctx);
980}
988 if (reverse_trampoline == nullptr)
989 return nullptr;
990 return reverse_trampoline->exec.rx_ptr;
991}
998 if (reverse_trampoline == nullptr)
999 return nullptr;
1000 return reverse_trampoline->user_data;
1001}
1002// High-Level Signature API Wrappers
1004 infix_arena_t * target_arena,
1005 const char * signature,
1006 void * target_function,
1009 if (!signature) {
1012 }
1013 infix_arena_t * arena = nullptr;
1014 infix_type * ret_type = nullptr;
1015 infix_function_argument * args = nullptr;
1016 size_t num_args = 0, num_fixed = 0;
1017 infix_type ** arg_types = nullptr;
1019 if (signature[0] == '@') {
1020 if (registry == nullptr) {
1022 INFIX_CATEGORY_GENERAL, INFIX_CODE_MISSING_REGISTRY, 0); // Using @Name requires a registry
1024 }
1025 const infix_type * func_type = infix_registry_lookup_type(registry, &signature[1]);
1026 if (func_type == NULL) {
1029 }
1030 if (func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE) {
1031 // The user provided a name for a non-function type (e.g., "@Point")
1034 }
1035 // We have a valid function type from the registry. Now, unpack its components.
1037 num_args = func_type->meta.func_ptr_info.num_args;
1038 num_fixed = func_type->meta.func_ptr_info.num_fixed_args;
1039 args = func_type->meta.func_ptr_info.args;
1040 // The Manual API needs a temporary arena to hold the arg_types array.
1041 infix_arena_t * temp_arena = infix_arena_create(sizeof(infix_type *) * num_args + 128);
1042 if (!temp_arena) {
1045 }
1046 if (num_args > 0) {
1047 arg_types = infix_arena_alloc(temp_arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
1048 if (!arg_types) {
1049 infix_arena_destroy(temp_arena);
1052 }
1053 for (size_t i = 0; i < num_args; ++i)
1054 arg_types[i] = args[i].type;
1055 }
1056 arena = temp_arena;
1057 }
1058 else {
1059 // This is a high-level wrapper. It uses the parser to build the type info first.
1060 status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1061 if (status != INFIX_SUCCESS) {
1063 return status;
1064 }
1065 // Extract the `infix_type*` array from the parsed `infix_function_argument` array.
1066 arg_types = (num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *))
1067 : nullptr;
1068 if (num_args > 0 && !arg_types) {
1072 }
1073 for (size_t i = 0; i < num_args; ++i)
1074 arg_types[i] = args[i].type;
1075 }
1076 // Call the core internal implementation with the parsed types.
1078 out_trampoline, target_arena, ret_type, arg_types, num_args, num_fixed, target_function, false);
1080 return status;
1081}
1083 const char * signature,
1084 void * target_function,
1087 if (!signature || !target_function) {
1090 }
1091 infix_arena_t * arena = nullptr;
1092 infix_type * ret_type = nullptr;
1093 infix_function_argument * args = nullptr;
1094 size_t num_args = 0, num_fixed = 0;
1095 infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1096 if (status != INFIX_SUCCESS) {
1098 return status;
1099 }
1101 (num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *)) : nullptr;
1102 if (num_args > 0 && !arg_types) {
1106 }
1107 for (size_t i = 0; i < num_args; ++i)
1108 arg_types[i] = args[i].type;
1109
1111 out_trampoline, NULL, ret_type, arg_types, num_args, num_fixed, target_function, true);
1113 return status;
1114}
1116 const char * signature,
1117 void * target_function,
1119 return infix_forward_create_in_arena(out_trampoline, NULL, signature, target_function, registry);
1120}
1122 const char * signature,
1124 return infix_forward_create_in_arena(out_trampoline, NULL, signature, NULL, registry);
1125}
1127 const char * signature,
1128 void * target_function,
1132 if (!signature || !target_function || !handlers) {
1135 }
1136
1137 infix_arena_t * arena = nullptr;
1138 infix_type * ret_type = nullptr;
1139 infix_function_argument * args = nullptr;
1140 size_t num_args = 0, num_fixed = 0;
1141 infix_type ** arg_types = nullptr;
1142
1143 // Parse the signature to get the type graph.
1144 infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1145 if (status != INFIX_SUCCESS) {
1147 return status;
1148 }
1149
1150 // Convert the parsed `infix_function_argument*` array to an `infix_type**` array.
1151 if (num_args > 0) {
1152 arg_types = infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
1153 if (!arg_types) {
1157 }
1158 for (size_t i = 0; i < num_args; ++i)
1159 arg_types[i] = args[i].type;
1160 }
1161
1162 // Call the core internal implementation with the parsed types and provided handlers.
1163 status =
1164 _infix_forward_create_direct_impl(out_trampoline, ret_type, arg_types, num_args, target_function, handlers);
1165
1166 // Clean up the temporary arena used by the parser.
1168 return status;
1169}
1171 const char * signature,
1172 void * user_callback_fn,
1174 infix_arena_t * arena = nullptr;
1175 infix_type * ret_type = nullptr;
1176 infix_function_argument * args = nullptr;
1177 size_t num_args = 0, num_fixed = 0;
1178 infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1179 if (status != INFIX_SUCCESS) {
1181 return status;
1182 }
1184 (num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *)) : nullptr;
1185 if (num_args > 0 && !arg_types) {
1189 }
1190 for (size_t i = 0; i < num_args; ++i)
1191 arg_types[i] = args[i].type;
1192 // Call the manual API with the parsed types.
1193 status =
1194 infix_reverse_create_callback_manual(out_context, ret_type, arg_types, num_args, num_fixed, user_callback_fn);
1196 return status;
1197}
1199 const char * signature,
1200 infix_closure_handler_fn user_callback_fn,
1201 void * user_data,
1203 infix_arena_t * arena = nullptr;
1204 infix_type * ret_type = nullptr;
1205 infix_function_argument * args = nullptr;
1206 size_t num_args = 0, num_fixed = 0;
1207 infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1208 if (status != INFIX_SUCCESS) {
1210 return status;
1211 }
1213 (num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *)) : nullptr;
1214 if (num_args > 0 && !arg_types) {
1218 }
1219 for (size_t i = 0; i < num_args; ++i)
1220 arg_types[i] = args[i].type;
1222 out_context, ret_type, arg_types, num_args, num_fixed, user_callback_fn, user_data);
1224 return status;
1225}
1226// ============================================================================
1227// UNITY BUILD INCLUDES
1228// This section includes the actual ABI implementations at the end of the file.
1229// Because `trampoline.c` is the central translation unit, including the
1230// correct ABI-specific .c file here makes its functions (`g_win_x64_spec`, etc.)
1231// available without needing to add platform-specific logic to the build system.
1232// The `infix_config.h` header ensures only one of these #if blocks is active.
1233// ============================================================================
1234#if defined(INFIX_ABI_WINDOWS_X64)
1235#include "../arch/x64/abi_win_x64.c"
1236#include "../arch/x64/abi_x64_emitters.c"
1237#elif defined(INFIX_ABI_SYSV_X64)
1238#include "../arch/x64/abi_sysv_x64.c"
1239#include "../arch/x64/abi_x64_emitters.c"
1240#elif defined(INFIX_ABI_AAPCS64)
1241#include "../arch/aarch64/abi_arm64.c"
1242#include "../arch/aarch64/abi_arm64_emitters.c"
1243#elif defined(INFIX_ABI_RISCV64)
1244#include "../arch/riscv/abi_riscv64.c"
1245#include "../arch/riscv/abi_riscv64_emitters.c"
1246#else
1247#error "No supported ABI was selected for the unity build in trampoline.c."
1248#endif
infix_arena_t * arena
Definition 005_layouts.c:62
infix_registry_t * registry
Definition 008_registry_introspection.c:33
infix_status status
Definition 103_unions.c:61
void * args[]
Definition 202_in_structs.c:59
infix_type * return_type
Definition 202_in_structs.c:55
infix_type * arg_types[]
Definition 901_call_overhead.c:62
infix_type * ret_type
Definition 901_call_overhead.c:61
infix_direct_arg_handler_t handlers[2]
Definition 901_call_overhead.c:104
const infix_reverse_abi_spec g_arm64_reverse_spec
Definition abi_arm64.c:116
const infix_forward_abi_spec g_arm64_forward_spec
Definition abi_arm64.c:95
const infix_direct_forward_abi_spec g_arm64_direct_forward_spec
Definition abi_arm64.c:139
const infix_forward_abi_spec g_riscv64_forward_spec
Definition abi_riscv64.c:112
const infix_direct_forward_abi_spec g_riscv64_direct_forward_spec
Definition abi_riscv64.c:157
const infix_reverse_abi_spec g_riscv64_reverse_spec
Definition abi_riscv64.c:133
const infix_reverse_abi_spec g_sysv_x64_reverse_spec
Definition abi_sysv_x64.c:113
const infix_direct_forward_abi_spec g_sysv_x64_direct_forward_spec
Definition abi_sysv_x64.c:137
const infix_forward_abi_spec g_sysv_x64_forward_spec
Definition abi_sysv_x64.c:92
const infix_direct_forward_abi_spec g_win_x64_direct_forward_spec
Definition abi_win_x64.c:130
const infix_reverse_abi_spec g_win_x64_reverse_spec
Definition abi_win_x64.c:106
const infix_forward_abi_spec g_win_x64_forward_spec
Definition abi_win_x64.c:86
#define c23_nodiscard
Internal alias for the public INFIX_NODISCARD macro.
Definition compat_c23.h:92
void(* infix_direct_cif_func)(void *, void **)
A function pointer for a direct marshalling forward trampoline.
Definition infix.h:1489
INFIX_API c23_nodiscard infix_direct_cif_func infix_forward_get_direct_code(infix_forward_t *trampoline)
Gets the callable function pointer from a direct marshalling trampoline.
Definition trampoline.c:298
INFIX_API c23_nodiscard infix_status infix_forward_create_direct(infix_forward_t **out_trampoline, const char *signature, void *target_function, infix_direct_arg_handler_t *handlers, infix_registry_t *registry)
Creates a forward trampoline with direct, JIT-bound marshalling.
Definition trampoline.c:1126
@ INFIX_CODE_MISSING_REGISTRY
Definition infix.h:1417
@ INFIX_CODE_UNRESOLVED_NAMED_TYPE
Definition infix.h:1439
@ INFIX_CODE_INTEGER_OVERFLOW
Definition infix.h:1431
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1427
@ INFIX_CODE_UNSUPPORTED_ABI
Definition infix.h:1437
@ INFIX_CODE_NULL_POINTER
Definition infix.h:1416
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1421
@ INFIX_CATEGORY_ABI
Definition infix.h:1407
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1405
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1404
@ INFIX_CATEGORY_PARSER
Definition infix.h:1406
struct infix_type_t::@0::@1 pointer_info
Metadata for INFIX_TYPE_POINTER.
union infix_type_t::@0 meta
A union containing metadata specific to the type's category.
bool is_incomplete
Definition infix.h:282
infix_type * type
Definition infix.h:352
INFIX_API INFIX_NODISCARD infix_status infix_signature_parse(const char *, infix_arena_t **, infix_type **, infix_function_argument **, size_t *, size_t *, infix_registry_t *)
Parses a full function signature string into its constituent parts.
Definition signature.c:1127
struct infix_type_t::@0::@4 func_ptr_info
Metadata for INFIX_TYPE_REVERSE_TRAMPOLINE.
void(* infix_cif_func)(void *, void **)
A function pointer type for a bound forward trampoline.
Definition infix.h:470
void(* infix_unbound_cif_func)(void *, void *, void **)
A function pointer type for an unbound forward trampoline.
Definition infix.h:461
INFIX_API c23_nodiscard infix_status infix_reverse_create_callback(infix_reverse_t **out_context, const char *signature, void *user_callback_fn, infix_registry_t *registry)
Creates a type-safe reverse trampoline (callback).
Definition trampoline.c:1170
infix_struct_member * members
Definition infix.h:295
INFIX_API c23_nodiscard infix_status infix_forward_create_safe(infix_forward_t **out_trampoline, const char *signature, void *target_function, infix_registry_t *registry)
Creates a "safe" bound forward trampoline that catches native exceptions.
Definition trampoline.c:1082
infix_function_argument * args
Definition infix.h:308
c23_nodiscard infix_status infix_reverse_create_closure(infix_reverse_t **out_context, const char *signature, infix_closure_handler_fn user_callback_fn, void *user_data, infix_registry_t *registry)
Creates a generic reverse trampoline (closure) for stateful callbacks.
Definition trampoline.c:1198
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:486
const char * name
Definition infix.h:351
INFIX_API c23_nodiscard infix_status infix_forward_create_in_arena(infix_forward_t **out_trampoline, infix_arena_t *target_arena, const char *signature, void *target_function, infix_registry_t *registry)
Creates a "bound" forward trampoline within a user-provided arena.
Definition trampoline.c:1003
infix_type_category category
Definition infix.h:278
struct infix_type_t::@0::@2 aggregate_info
Metadata for INFIX_TYPE_STRUCT and INFIX_TYPE_UNION.
struct infix_type_t::@0::@3 array_info
Metadata for INFIX_TYPE_ARRAY.
struct infix_type_t * pointee_type
Definition infix.h:291
infix_type * type
Definition infix.h:338
struct infix_type_t * element_type
Definition infix.h:301
struct infix_type_t * return_type
Definition infix.h:307
size_t num_members
Definition infix.h:296
size_t num_fixed_args
Definition infix.h:310
INFIX_API c23_nodiscard infix_status infix_forward_create_unbound(infix_forward_t **out_trampoline, const char *signature, infix_registry_t *registry)
Creates an "unbound" forward trampoline from a signature string.
Definition trampoline.c:1121
void(* infix_closure_handler_fn)(infix_context_t *, void *, void **)
A function pointer type for a generic closure handler.
Definition infix.h:482
size_t num_args
Definition infix.h:309
INFIX_API c23_nodiscard infix_status infix_forward_create(infix_forward_t **out_trampoline, const char *signature, void *target_function, infix_registry_t *registry)
Creates a "bound" forward trampoline from a signature string.
Definition trampoline.c:1115
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:488
@ INFIX_ERROR_PROTECTION_FAILED
Definition infix.h:492
@ INFIX_ERROR_UNSUPPORTED_ABI
Definition infix.h:490
@ INFIX_SUCCESS
Definition infix.h:487
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:489
INFIX_API INFIX_NODISCARD infix_status infix_function_print(char *, size_t, const char *, const infix_type *, const infix_function_argument *, size_t, size_t, infix_print_dialect_t)
Serializes a function signature's components into a string.
Definition signature.c:2084
INFIX_API c23_nodiscard void * infix_reverse_get_code(const infix_reverse_t *reverse_trampoline)
Gets the native, callable C function pointer from a reverse trampoline.
Definition trampoline.c:987
INFIX_API c23_nodiscard infix_unbound_cif_func infix_forward_get_unbound_code(infix_forward_t *trampoline)
Gets the callable function pointer from an unbound forward trampoline.
Definition trampoline.c:288
INFIX_API c23_nodiscard infix_cif_func infix_forward_get_code(infix_forward_t *trampoline)
Gets the callable function pointer from a bound forward trampoline.
Definition trampoline.c:293
INFIX_API c23_nodiscard void * infix_reverse_get_user_data(const infix_reverse_t *reverse_trampoline)
Gets the user-provided data pointer from a closure context.
Definition trampoline.c:997
@ INFIX_DIALECT_SIGNATURE
Definition infix.h:1228
INFIX_API void infix_reverse_destroy(infix_reverse_t *reverse_trampoline)
Destroys a reverse trampoline and frees all associated memory.
Definition trampoline.c:969
INFIX_API c23_nodiscard infix_status infix_forward_create_manual(infix_forward_t **out_trampoline, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, void *target_function)
Creates a bound forward trampoline from infix_type objects (Manual API).
Definition trampoline.c:673
INFIX_API c23_nodiscard infix_status infix_forward_create_unbound_manual(infix_forward_t **out_trampoline, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args)
Creates an unbound forward trampoline from infix_type objects (Manual API).
Definition trampoline.c:699
INFIX_API c23_nodiscard infix_status infix_reverse_create_closure_manual(infix_reverse_t **out_context, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, infix_closure_handler_fn user_callback_fn, void *user_data)
Creates a generic reverse trampoline (closure) from infix_type objects (Manual API).
Definition trampoline.c:950
INFIX_API c23_nodiscard infix_status infix_reverse_create_callback_manual(infix_reverse_t **out_context, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, void *user_callback_fn)
Creates a type-safe reverse trampoline (callback) from infix_type objects (Manual API).
Definition trampoline.c:928
INFIX_API void infix_forward_destroy(infix_forward_t *trampoline)
Destroys a forward trampoline and frees all associated memory.
Definition trampoline.c:731
INFIX_API INFIX_NODISCARD void * infix_arena_alloc(infix_arena_t *, size_t, size_t)
Allocates a block of memory from an arena.
Definition arena.c:117
#define infix_calloc(nelem, size)
A macro that can be defined to override infix's allocator at compile time.
Definition infix.h:427
#define infix_free(ptr)
A macro that can be defined to override infix's allocator at compile time.
Definition infix.h:435
#define infix_memcpy
A macro that can be defined to override the default memcpy function.
Definition infix.h:439
INFIX_API INFIX_NODISCARD infix_arena_t * infix_arena_create(size_t)
Creates a new memory arena.
Definition arena.c:52
#define infix_memset
A macro that can be defined to override the default memset function.
Definition infix.h:443
INFIX_API void infix_arena_destroy(infix_arena_t *)
Destroys an arena and frees all memory allocated from it.
Definition arena.c:83
INFIX_API INFIX_NODISCARD const infix_type * infix_registry_lookup_type(const infix_registry_t *, const char *)
Retrieves the canonical infix_type object for a given name from the registry.
Definition type_registry.c:938
@ INFIX_TYPE_UNION
Definition infix.h:233
@ INFIX_TYPE_ARRAY
Definition infix.h:234
@ INFIX_TYPE_POINTER
Definition infix.h:231
@ INFIX_TYPE_NAMED_REFERENCE
Definition infix.h:239
@ INFIX_TYPE_REVERSE_TRAMPOLINE
Definition infix.h:235
@ INFIX_TYPE_STRUCT
Definition infix.h:232
#define INFIX_API
Symbol visibility macro.
Definition infix.h:114
#define INFIX_TRAMPOLINE_HEADROOM
Extra bytes to allocate in a trampoline's private arena.
Definition infix_config.h:213
Internal data structures, function prototypes, and constants.
@ INFIX_EXECUTABLE_REVERSE
Definition infix_internals.h:709
@ INFIX_EXECUTABLE_SAFE_FORWARD
Definition infix_internals.h:708
@ INFIX_EXECUTABLE_DIRECT
Definition infix_internals.h:710
@ INFIX_EXECUTABLE_FORWARD
Definition infix_internals.h:707
INFIX_INTERNAL void _infix_cache_insert(infix_forward_t *trampoline)
Definition cache.c:136
INFIX_INTERNAL c23_nodiscard bool infix_executable_make_executable(infix_executable_t *exec, infix_executable_category_t category, uint32_t prologue_size, uint32_t epilogue_offset)
Makes a block of JIT memory executable, completing the W^X process.
INFIX_INTERNAL void infix_executable_free(infix_executable_t exec)
Frees a block of executable memory and applies guard pages to prevent use-after-free.
Definition executor.c:863
INFIX_INTERNAL c23_nodiscard infix_protected_t infix_protected_alloc(size_t size)
Allocates a block of standard memory for later protection.
Definition executor.c:1055
INFIX_INTERNAL void infix_protected_free(infix_protected_t prot)
Frees a block of protected memory.
Definition executor.c:1089
INFIX_INTERNAL c23_nodiscard infix_executable_t infix_executable_alloc(size_t size)
Allocates a block of executable memory using the platform's W^X strategy.
Definition executor.c:280
INFIX_INTERNAL infix_type * _copy_type_graph_to_arena(infix_arena_t *, const infix_type *)
Performs a deep copy of a type graph into a destination arena.
Definition types.c:1128
INFIX_INTERNAL size_t _infix_estimate_graph_size(infix_arena_t *temp_arena, const infix_type *type)
Estimates the total memory required to deep-copy a complete type graph.
Definition types.c:1233
INFIX_INTERNAL c23_nodiscard bool infix_protected_make_readonly(infix_protected_t prot)
Makes a block of memory read-only for security hardening.
Definition executor.c:1109
INFIX_INTERNAL void _infix_clear_error(void)
Clears the thread-local error state.
Definition error.c:268
INFIX_INTERNAL void _infix_set_error(infix_error_category_t category, infix_error_code_t code, size_t position)
Sets the thread-local error state with detailed information.
Definition error.c:175
INFIX_INTERNAL void _infix_cache_release(infix_forward_t *trampoline)
Definition cache.c:258
INFIX_INTERNAL infix_forward_t * _infix_cache_lookup(const char *signature, void *target_fn, bool is_safe)
Definition cache.c:103
INFIX_INTERNAL void infix_internal_dispatch_callback_fn_impl(infix_reverse_t *context, void *return_value_ptr, void **args_array)
The universal C entry point for all reverse call trampolines.
Definition executor.c:1148
A dynamic buffer for staged machine code generation.
Definition infix_internals.h:210
uint8_t * code
Definition infix_internals.h:211
bool error
Definition infix_internals.h:214
size_t size
Definition infix_internals.h:213
size_t capacity
Definition infix_internals.h:212
infix_arena_t * arena
Definition infix_internals.h:215
Internal definition of a memory arena.
Definition infix_internals.h:143
bool error
Definition infix_internals.h:147
A complete layout blueprint for a forward call frame.
Definition infix_internals.h:307
uint32_t epilogue_offset
Definition infix_internals.h:323
uint32_t prologue_size
Definition infix_internals.h:322
A struct containing all the necessary handlers for a single function argument.
Definition infix.h:1552
A complete layout blueprint for a direct marshalling forward call frame.
Definition infix_internals.h:495
uint32_t epilogue_offset
Offset from the start of the JIT block to the epilogue.
Definition infix_internals.h:502
uint32_t prologue_size
Size of the generated prologue in bytes.
Definition infix_internals.h:501
Defines the ABI-specific implementation interface for direct marshalling forward trampolines.
Definition infix_internals.h:511
infix_status(* generate_direct_forward_call_instruction)(code_buffer *buf, infix_direct_call_frame_layout *layout)
Generates the call instruction to the target function.
Definition infix_internals.h:525
infix_status(* generate_direct_forward_argument_moves)(code_buffer *buf, infix_direct_call_frame_layout *layout)
Generates code to call marshallers and move arguments into their native locations.
Definition infix_internals.h:523
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)
Analyzes a function signature to create a complete direct call frame layout.
Definition infix_internals.h:513
infix_status(* generate_direct_forward_epilogue)(code_buffer *buf, infix_direct_call_frame_layout *layout, infix_type *ret_type)
Generates the function epilogue (handling return value, calling write-back handlers,...
Definition infix_internals.h:528
infix_status(* generate_direct_forward_prologue)(code_buffer *buf, infix_direct_call_frame_layout *layout)
Generates the function prologue (stack setup, saving registers).
Definition infix_internals.h:521
size_t size
Definition infix_internals.h:66
void * rw_ptr
Definition infix_internals.h:65
void * rx_ptr
Definition infix_internals.h:64
Defines the ABI-specific implementation interface for forward trampolines.
Definition infix_internals.h:356
infix_status(* generate_forward_prologue)(code_buffer *buf, infix_call_frame_layout *layout)
Generates the function prologue (stack setup, saving registers).
Definition infix_internals.h:385
infix_status(* generate_forward_argument_moves)(code_buffer *buf, infix_call_frame_layout *layout, infix_type **arg_types, size_t num_args, size_t num_fixed_args)
Generates code to move arguments from the void** array into registers and/or the stack.
Definition infix_internals.h:395
infix_status(* generate_forward_call_instruction)(code_buffer *buf, infix_call_frame_layout *layout)
Generates the call instruction to the target function.
Definition infix_internals.h:406
infix_status(* prepare_forward_call_frame)(infix_arena_t *arena, infix_call_frame_layout **out_layout, infix_type *ret_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, void *target_fn)
Analyzes a function signature to create a complete call frame layout.
Definition infix_internals.h:372
infix_status(* generate_forward_epilogue)(code_buffer *buf, infix_call_frame_layout *layout, infix_type *ret_type)
Generates the function epilogue (handling return value, restoring stack, returning).
Definition infix_internals.h:414
Internal definition of a forward trampoline handle.
Definition infix_internals.h:90
infix_executable_t exec
Definition infix_internals.h:94
void * target_fn
Definition infix_internals.h:99
size_t num_args
Definition infix_internals.h:97
bool is_external_arena
Definition infix_internals.h:92
size_t num_fixed_args
Definition infix_internals.h:98
infix_type ** arg_types
Definition infix_internals.h:96
infix_type * return_type
Definition infix_internals.h:95
size_t ref_count
Definition infix_internals.h:102
bool is_safe
Definition infix_internals.h:101
infix_arena_t * arena
Definition infix_internals.h:91
char * signature
Definition infix_internals.h:103
bool is_direct_trampoline
Definition infix_internals.h:100
Describes a single argument to a C function.
Definition infix.h:350
Internal representation of a memory block that will be made read-only.
Definition infix_internals.h:77
void * rw_ptr
Definition infix_internals.h:78
Internal definition of a named type registry.
Definition infix_internals.h:188
Defines the ABI-specific implementation interface for reverse trampolines.
Definition infix_internals.h:425
infix_status(* generate_reverse_argument_marshalling)(code_buffer *buf, infix_reverse_call_frame_layout *layout, infix_reverse_t *context)
Generates code to marshal arguments from their native locations (registers/stack) into a void** array...
Definition infix_internals.h:450
infix_status(* prepare_reverse_call_frame)(infix_arena_t *arena, infix_reverse_call_frame_layout **out_layout, infix_reverse_t *context)
Analyzes a function signature to create a layout for the reverse call stub's stack frame.
Definition infix_internals.h:433
infix_status(* generate_reverse_prologue)(code_buffer *buf, infix_reverse_call_frame_layout *layout)
Generates the reverse stub's prologue (stack setup).
Definition infix_internals.h:442
infix_status(* generate_reverse_dispatcher_call)(code_buffer *buf, infix_reverse_call_frame_layout *layout, infix_reverse_t *context)
Generates the call to the universal C dispatcher (infix_internal_dispatch_callback_fn_impl).
Definition infix_internals.h:460
infix_status(* generate_reverse_epilogue)(code_buffer *buf, infix_reverse_call_frame_layout *layout, infix_reverse_t *context)
Generates the reverse stub's epilogue (handling return value, restoring stack, returning).
Definition infix_internals.h:470
A complete layout blueprint for a reverse call frame.
Definition infix_internals.h:332
uint32_t prologue_size
Definition infix_internals.h:340
Internal definition of a reverse trampoline (callback/closure) handle.
Definition infix_internals.h:119
infix_type * return_type
Definition infix_internals.h:123
void * user_data
Definition infix_internals.h:129
void * user_callback_fn
Definition infix_internals.h:128
infix_executable_t exec
Definition infix_internals.h:121
infix_internal_dispatch_callback_fn internal_dispatcher
Definition infix_internals.h:131
size_t num_args
Definition infix_internals.h:125
size_t num_fixed_args
Definition infix_internals.h:126
infix_protected_t protected_ctx
Definition infix_internals.h:122
bool is_variadic
Definition infix_internals.h:127
infix_forward_t * cached_forward_trampoline
Definition infix_internals.h:133
infix_arena_t * arena
Definition infix_internals.h:120
infix_type ** arg_types
Definition infix_internals.h:124
A semi-opaque structure that describes a C type.
Definition infix.h:276
Definition trampoline.c:203
const infix_type * type
Definition trampoline.c:204
struct visited_node_t * next
Definition trampoline.c:205
void emit_byte(code_buffer *buf, uint8_t byte)
A convenience wrapper to append a single byte to a code buffer.
Definition trampoline.c:196
static bool _is_type_graph_resolved_recursive(const infix_type *type, visited_node_t *visited_head)
Definition trampoline.c:219
const infix_forward_abi_spec * get_current_forward_abi_spec()
Gets the ABI v-table for forward calls for the current platform.
Definition trampoline.c:88
void code_buffer_init(code_buffer *buf, infix_arena_t *arena)
Initializes a code buffer for JIT code generation.
Definition trampoline.c:145
static infix_status _infix_forward_create_impl(infix_forward_t **out_trampoline, infix_arena_t *target_arena, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, void *target_fn, bool is_safe)
Definition trampoline.c:326
static bool _is_type_graph_resolved(const infix_type *type)
Definition trampoline.c:258
void emit_int64(code_buffer *buf, int64_t value)
A convenience wrapper to append a 64-bit integer (little-endian) to a code buffer.
Definition trampoline.c:200
void _infix_forward_destroy_internal(infix_forward_t *trampoline)
Definition trampoline.c:712
void code_buffer_append(code_buffer *buf, const void *data, size_t len)
Appends raw bytes to a code buffer, reallocating within its arena if necessary.
Definition trampoline.c:164
static infix_status _infix_forward_create_direct_impl(infix_forward_t **out_trampoline, infix_type *return_type, infix_type **arg_types, size_t num_args, void *target_fn, infix_direct_arg_handler_t *handlers)
Definition trampoline.c:539
static size_t get_page_size()
Definition trampoline.c:738
void emit_int32(code_buffer *buf, int32_t value)
A convenience wrapper to append a 32-bit integer (little-endian) to a code buffer.
Definition trampoline.c:198
static size_t _estimate_metadata_size(infix_arena_t *temp_arena, infix_type *return_type, infix_type **arg_types, size_t num_args)
Definition trampoline.c:273
const infix_direct_forward_abi_spec * get_current_direct_forward_abi_spec()
Gets the ABI v-table for direct marshalling forward calls for the current platform.
Definition trampoline.c:125
static infix_status _infix_reverse_create_internal(infix_reverse_t **out_context, infix_type *return_type, infix_type **arg_types, size_t num_args, size_t num_fixed_args, void *user_callback_fn, void *user_data, bool is_callback)
Definition trampoline.c:771
const infix_reverse_abi_spec * get_current_reverse_abi_spec()
Gets the ABI v-table for reverse calls for the current platform.
Definition trampoline.c:107
A header for conditionally compiled debugging utilities.
static void infix_dump_hex(c23_maybe_unused const void *data, c23_maybe_unused size_t size, c23_maybe_unused const char *title)
Definition utility.h:112