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#endif
85#if defined(INFIX_ABI_WINDOWS_X64)
87#elif defined(INFIX_ABI_SYSV_X64)
89#elif defined(INFIX_ABI_AAPCS64)
91#else
92 return nullptr;
93#endif
94}
102#if defined(INFIX_ABI_WINDOWS_X64)
104#elif defined(INFIX_ABI_SYSV_X64)
106#elif defined(INFIX_ABI_AAPCS64)
107 return &g_arm64_reverse_spec;
108#else
109 return nullptr;
110#endif
111}
118#if defined(INFIX_ABI_WINDOWS_X64)
120#elif defined(INFIX_ABI_SYSV_X64)
122#elif defined(INFIX_ABI_AAPCS64)
124#else
125 return nullptr;
126#endif
127}
128// Code Buffer Implementation
136 buf->capacity = 64; // Start with a small initial capacity.
137 buf->arena = arena;
138 buf->code = infix_arena_alloc(arena, buf->capacity, 16);
139 buf->size = 0;
140 buf->error = (buf->code == nullptr);
141}
154void code_buffer_append(code_buffer * buf, const void * data, size_t len) {
155 if (buf->error)
156 return;
157 if (len > SIZE_MAX - buf->size) { // Overflow check
158 buf->error = true;
160 return;
161 }
162 if (buf->size + len > buf->capacity) {
163 size_t new_capacity = buf->capacity;
164 while (new_capacity < buf->size + len) {
165 if (new_capacity > SIZE_MAX / 2) { // Overflow check
166 buf->error = true;
168 return;
169 }
170 new_capacity *= 2;
171 }
172 void * new_code = infix_arena_alloc(buf->arena, new_capacity, 16);
173 if (new_code == nullptr) {
174 buf->error = true;
175 // infix_arena_alloc already sets INFIX_CODE_OUT_OF_MEMORY, so we don't need to override it here
176 return;
177 }
178 infix_memcpy(new_code, buf->code, buf->size);
179 buf->code = new_code;
180 buf->capacity = new_capacity;
181 }
182 infix_memcpy(buf->code + buf->size, data, len);
183 buf->size += len;
184}
186void emit_byte(code_buffer * buf, uint8_t byte) { code_buffer_append(buf, &byte, 1); }
188void emit_int32(code_buffer * buf, int32_t value) { code_buffer_append(buf, &value, 4); }
190void emit_int64(code_buffer * buf, int64_t value) { code_buffer_append(buf, &value, 8); }
191// Type Graph Validation
210 if (!type)
211 return true;
212 if (type->is_incomplete)
213 return false;
214 // Cycle detection: if we've seen this node before, we can assume it's resolved
215 // for the purpose of this check, as we'll validate it on the first visit.
216 for (visited_node_t * v = visited_head; v != NULL; v = v->next)
217 if (v->type == type)
218 return true;
219 visited_node_t current_visited_node = {.type = type, .next = visited_head};
220 switch (type->category) {
222 return false; // Base case: an unresolved reference.
225 case INFIX_TYPE_ARRAY:
226 return _is_type_graph_resolved_recursive(type->meta.array_info.element_type, &current_visited_node);
228 case INFIX_TYPE_UNION:
229 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i)
230 if (!_is_type_graph_resolved_recursive(type->meta.aggregate_info.members[i].type, &current_visited_node))
231 return false;
232 return true;
235 return false;
236 for (size_t i = 0; i < type->meta.func_ptr_info.num_args; ++i)
237 if (!_is_type_graph_resolved_recursive(type->meta.func_ptr_info.args[i].type, &current_visited_node))
238 return false;
239 return true;
240 default:
241 return true; // Primitives, void, etc., are always resolved.
242 }
243}
263static size_t _estimate_metadata_size(infix_arena_t * temp_arena,
266 size_t num_args) {
267 size_t total_size = 0;
268 total_size += _infix_estimate_graph_size(temp_arena, return_type);
269 if (arg_types != nullptr) {
270 // Add space for the arg_types pointer array itself.
271 total_size += sizeof(infix_type *) * num_args;
272 for (size_t i = 0; i < num_args; ++i)
273 total_size += _infix_estimate_graph_size(temp_arena, arg_types[i]);
274 }
275 return total_size;
276}
277// Forward Trampoline API Implementation
279 if (trampoline == nullptr || trampoline->is_direct_trampoline || trampoline->target_fn != nullptr)
280 return nullptr;
281 return (infix_unbound_cif_func)trampoline->exec.rx_ptr;
282}
284 if (trampoline == nullptr || trampoline->is_direct_trampoline || trampoline->target_fn == nullptr)
285 return nullptr;
286 return (infix_cif_func)trampoline->exec.rx_ptr;
287}
289 if (trampoline == nullptr || !trampoline->is_direct_trampoline)
290 return nullptr;
291 return (infix_direct_cif_func)trampoline->exec.rx_ptr;
292}
317 infix_arena_t * target_arena,
320 size_t num_args,
321 size_t num_fixed_args,
322 void * target_fn,
323 bool is_safe) {
324 if (out_trampoline == nullptr || return_type == nullptr || (arg_types == nullptr && num_args > 0)) {
327 }
328 // Pre-flight check: ensure all types are resolved before passing to ABI layer.
332 }
333 for (size_t i = 0; i < num_args; ++i) {
334 if (arg_types[i] == nullptr || !_is_type_graph_resolved(arg_types[i])) {
337 }
338 }
339
341 infix_call_frame_layout * layout = nullptr;
342 infix_forward_t * handle = nullptr;
343
344 // Use a temporary arena for all intermediate allocations during code generation.
345 infix_arena_t * temp_arena = infix_arena_create(65536);
346 if (!temp_arena) {
349 }
350
351 // --- Cache Lookup Stage ---
352 // Generate a canonical signature for deduplication.
353 char canonical_sig[8192];
354 infix_status sig_status = INFIX_SUCCESS;
355 {
356 // Construct a temporary argument array for the printer.
357 infix_function_argument * tmp_args = nullptr;
358 if (num_args > 0) {
359 tmp_args =
360 infix_arena_alloc(temp_arena, sizeof(infix_function_argument) * num_args, _Alignof(infix_type *));
361 if (!tmp_args) {
363 goto cleanup;
364 }
365 for (size_t i = 0; i < num_args; ++i) {
366 tmp_args[i].type = arg_types[i];
367 tmp_args[i].name = nullptr;
368 }
369 }
370 sig_status = infix_function_print(canonical_sig,
371 sizeof(canonical_sig),
372 "func",
374 tmp_args,
375 num_args,
376 num_fixed_args,
378 }
379
380 if (sig_status == INFIX_SUCCESS) {
381 infix_forward_t * cached = _infix_cache_lookup(canonical_sig, target_fn, is_safe);
382 if (cached) {
383 *out_trampoline = cached;
385 goto cleanup;
386 }
387 }
388
390 if (spec == nullptr) {
393 goto cleanup;
394 }
395
396 code_buffer buf;
397 code_buffer_init(&buf, temp_arena);
398 // JIT Compilation Pipeline
399 // Prepare: Classify arguments and create the layout blueprint.
401 temp_arena, &layout, return_type, arg_types, num_args, num_fixed_args, target_fn);
402 if (status != INFIX_SUCCESS)
403 goto cleanup;
404 // 2. Generate: Emit machine code based on the layout.
405 status = spec->generate_forward_prologue(&buf, layout);
406 if (status != INFIX_SUCCESS)
407 goto cleanup;
408 status = spec->generate_forward_argument_moves(&buf, layout, arg_types, num_args, num_fixed_args);
409 if (status != INFIX_SUCCESS)
410 goto cleanup;
411 status = spec->generate_forward_call_instruction(&buf, layout);
412 if (status != INFIX_SUCCESS)
413 goto cleanup;
414 status = spec->generate_forward_epilogue(&buf, layout, return_type);
415 if (status != INFIX_SUCCESS)
416 goto cleanup;
417 if (buf.error || temp_arena->error) {
419 goto cleanup;
420 }
421 // Finalize Handle
422 handle = infix_calloc(1, sizeof(infix_forward_t));
423 if (handle == nullptr) {
425 goto cleanup;
426 }
427 // "Estimate" stage: Calculate the exact size needed for the handle's private arena.
428 size_t required_metadata_size = _estimate_metadata_size(temp_arena, return_type, arg_types, num_args);
429 if (target_arena) {
430 handle->arena = target_arena;
431 handle->is_external_arena = true;
432 }
433 else {
434 handle->arena = infix_arena_create(required_metadata_size + INFIX_TRAMPOLINE_HEADROOM);
435 handle->is_external_arena = false;
436 }
437 if (handle->arena == nullptr) {
439 goto cleanup;
440 }
441 // "Copy" stage: Deep copy all type info into the handle's private arena.
443 if (num_args > 0) {
444 handle->arg_types = infix_arena_alloc(handle->arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
445 if (handle->arg_types == nullptr) {
447 goto cleanup;
448 }
449 for (size_t i = 0; i < num_args; ++i) {
450 handle->arg_types[i] = _copy_type_graph_to_arena(handle->arena, arg_types[i]);
451 // Check for allocation failure during copy
452 if (arg_types[i] != nullptr && handle->arg_types[i] == nullptr && !handle->arena->error) {
454 goto cleanup;
455 }
456 }
457 }
458 handle->num_args = num_args;
459 handle->num_fixed_args = num_fixed_args;
460 handle->target_fn = target_fn;
461 handle->is_safe = is_safe;
462 handle->ref_count = 1;
463
464 // Save the canonical signature for the cache key.
465 if (sig_status == INFIX_SUCCESS) {
466 size_t sig_len = strlen(canonical_sig) + 1;
467 handle->signature = infix_arena_alloc(handle->arena, sig_len, 1);
468 if (handle->signature)
469 infix_memcpy(handle->signature, canonical_sig, sig_len);
470 }
471
472 // Allocate and finalize executable memory.
473 handle->exec = infix_executable_alloc(buf.size);
474 if (handle->exec.rw_ptr == nullptr) {
476 goto cleanup;
477 }
478 infix_memcpy(handle->exec.rw_ptr, buf.code, buf.size);
481 layout->prologue_size,
482 layout->epilogue_offset)) {
484 goto cleanup;
485 }
486 infix_dump_hex(handle->exec.rx_ptr, handle->exec.size, "Forward Trampoline Machine Code");
487 *out_trampoline = handle;
488
489 // Cache the newly created trampoline.
490 // We ONLY cache if we own the arena. If the user provided an external arena,
491 // they control the lifetime, and we can't guarantee the signature string
492 // (which is in that arena) will remain valid as long as the cache entry exists.
493 if (handle->signature && !handle->is_external_arena)
494 _infix_cache_insert(handle);
495
496cleanup:
497 // If any step failed, ensure the partially created handle is fully destroyed.
498 if (status != INFIX_SUCCESS && handle != nullptr)
499 infix_forward_destroy(handle);
500 // The temporary arena is always destroyed.
501 infix_arena_destroy(temp_arena);
502 return status;
503}
532 size_t num_args,
533 void * target_fn,
535 // Validation and Setup
536 if (!out_trampoline || !return_type || (!arg_types && num_args > 0) || !target_fn || !handlers) {
539 }
540
542 if (spec == nullptr) {
545 }
546
548 infix_direct_call_frame_layout * layout = nullptr;
549 infix_forward_t * handle = nullptr;
550 infix_arena_t * temp_arena = infix_arena_create(65536);
551 if (!temp_arena) {
554 }
555 code_buffer buf;
556 code_buffer_init(&buf, temp_arena);
557
558 // 2. JIT Compilation Pipeline
560 temp_arena, &layout, return_type, arg_types, num_args, handlers, target_fn);
561 if (status != INFIX_SUCCESS)
562 goto cleanup;
563
564 status = spec->generate_direct_forward_prologue(&buf, layout);
565 if (status != INFIX_SUCCESS)
566 goto cleanup;
567
569 if (status != INFIX_SUCCESS)
570 goto cleanup;
571
573 if (status != INFIX_SUCCESS)
574 goto cleanup;
575
577 if (status != INFIX_SUCCESS)
578 goto cleanup;
579
580 if (buf.error || temp_arena->error) {
582 goto cleanup;
583 }
584
585 // 3. Finalize Handle
586 handle = infix_calloc(1, sizeof(infix_forward_t));
587 if (handle == nullptr) {
589 goto cleanup;
590 }
591
592 handle->is_direct_trampoline = true; // Mark this as a direct marshalling trampoline.
593
594 size_t required_metadata_size = _estimate_metadata_size(temp_arena, return_type, arg_types, num_args);
595 handle->arena = infix_arena_create(required_metadata_size + INFIX_TRAMPOLINE_HEADROOM);
596 handle->is_external_arena = false;
597 if (handle->arena == nullptr) {
599 goto cleanup;
600 }
601
603 if (num_args > 0) {
604 handle->arg_types = infix_arena_alloc(handle->arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
605 if (!handle->arg_types) {
607 goto cleanup;
608 }
609 for (size_t i = 0; i < num_args; ++i) {
610 handle->arg_types[i] = _copy_type_graph_to_arena(handle->arena, arg_types[i]);
611 if (arg_types[i] && !handle->arg_types[i] && !handle->arena->error) {
613 goto cleanup;
614 }
615 }
616 }
617 handle->num_args = num_args;
618 handle->num_fixed_args = num_args; // Direct trampolines are always fixed-arity.
619 handle->target_fn = target_fn;
620 handle->ref_count = 1;
621
622 // 4. Allocate and Finalize Executable Memory
623 handle->exec = infix_executable_alloc(buf.size);
624 if (handle->exec.rw_ptr == nullptr) {
626 goto cleanup;
627 }
628 infix_memcpy(handle->exec.rw_ptr, buf.code, buf.size);
630 &handle->exec, INFIX_EXECUTABLE_DIRECT, layout->prologue_size, layout->epilogue_offset)) {
632 goto cleanup;
633 }
634
635 infix_dump_hex(handle->exec.rx_ptr, handle->exec.size, "Direct-Marshalling Forward Trampoline Machine Code");
636 *out_trampoline = handle;
637
638cleanup:
639 if (status != INFIX_SUCCESS && handle != nullptr)
640 infix_forward_destroy(handle);
641 infix_arena_destroy(temp_arena);
642 return status;
643}
665 size_t num_args,
666 size_t num_fixed_args,
667 void * target_function) {
668 // This is part of the "Manual API". It calls the internal implementation directly
669 // without involving the signature parser. `source_arena` is null because the
670 // types are assumed to be managed by the user.
673 out_trampoline, nullptr, return_type, arg_types, num_args, num_fixed_args, target_function, false);
674}
691 size_t num_args,
692 size_t num_fixed_args) {
695 out_trampoline, nullptr, return_type, arg_types, num_args, num_fixed_args, nullptr, false);
696}
702 if (trampoline == nullptr)
703 return;
704 // Destroying the private arena frees all deep-copied type metadata and the signature string.
705 if (trampoline->arena && !trampoline->is_external_arena)
706 infix_arena_destroy(trampoline->arena);
707 // Free the JIT-compiled executable code.
708 infix_executable_free(trampoline->exec);
709 // Free the handle struct itself.
710 infix_free(trampoline);
711}
712
721// Reverse Trampoline API Implementation
727static size_t get_page_size() {
728#if defined(INFIX_OS_WINDOWS)
729 SYSTEM_INFO sysInfo;
730 GetSystemInfo(&sysInfo);
731 return sysInfo.dwPageSize;
732#else
733 // sysconf is the standard POSIX way to get system configuration values.
734 return sysconf(_SC_PAGESIZE);
735#endif
736}
763 size_t num_args,
764 size_t num_fixed_args,
765 void * user_callback_fn,
766 void * user_data,
767 bool is_callback) {
768 if (out_context == nullptr || return_type == nullptr || num_fixed_args > num_args) {
771 }
772 // Pre-flight check: ensure all types are fully resolved.
776 }
777 if (arg_types == nullptr && num_args > 0) {
780 }
781 for (size_t i = 0; i < num_args; ++i) {
782 if (arg_types[i] == nullptr || !_is_type_graph_resolved(arg_types[i])) {
785 }
786 }
788 if (spec == nullptr) {
791 }
793 infix_reverse_call_frame_layout * layout = nullptr;
794 infix_reverse_t * context = nullptr;
795 infix_arena_t * temp_arena = nullptr;
796 infix_protected_t prot = {.rw_ptr = nullptr, .size = 0};
797 code_buffer buf;
798 temp_arena = infix_arena_create(65536);
799 if (!temp_arena) {
802 }
803 code_buffer_init(&buf, temp_arena);
804 // Security Hardening: Allocate the context struct itself in special, page-aligned
805 // memory that can be made read-only after initialization.
806 size_t page_size = get_page_size();
807 size_t context_alloc_size = (sizeof(infix_reverse_t) + page_size - 1) & ~(page_size - 1);
808 prot = infix_protected_alloc(context_alloc_size);
809 if (prot.rw_ptr == nullptr) {
811 goto cleanup;
812 }
813 context = (infix_reverse_t *)prot.rw_ptr;
814 infix_memset(context, 0, context_alloc_size);
815 // "Estimate" stage: Calculate the exact size needed for the context's private arena.
816 size_t required_metadata_size = _estimate_metadata_size(temp_arena, return_type, arg_types, num_args);
817 // Create the context's private arena with the calculated size plus some headroom for safety.
818 context->arena = infix_arena_create(required_metadata_size + INFIX_TRAMPOLINE_HEADROOM);
819 if (context->arena == nullptr) {
821 goto cleanup;
822 }
823 // Populate the context fields.
824 context->protected_ctx = prot;
825 context->num_args = num_args;
826 context->num_fixed_args = num_fixed_args;
827 context->is_variadic = (num_fixed_args < num_args);
828 context->user_callback_fn = user_callback_fn;
829 context->user_data = user_data;
831 context->cached_forward_trampoline = nullptr;
832 // "Copy" stage: deep copy all types into the context's private arena.
834 if (num_args > 0) {
835 context->arg_types = infix_arena_alloc(context->arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
836 if (context->arg_types == nullptr) {
838 goto cleanup;
839 }
840 for (size_t i = 0; i < num_args; ++i) {
841 context->arg_types[i] = _copy_type_graph_to_arena(context->arena, arg_types[i]);
842 if (arg_types[i] != nullptr && context->arg_types[i] == nullptr) {
844 goto cleanup;
845 }
846 }
847 }
848 // Special step for type-safe callbacks: generate and cache a forward trampoline
849 // that will be used to call the user's type-safe C handler.
850 if (is_callback) {
852 context->return_type,
853 context->arg_types,
854 context->num_args,
855 context->num_fixed_args,
856 user_callback_fn);
857 if (status != INFIX_SUCCESS)
858 goto cleanup;
859 }
860 // JIT Compilation Pipeline for Reverse Stub
861 status = spec->prepare_reverse_call_frame(temp_arena, &layout, context);
862 if (status != INFIX_SUCCESS)
863 goto cleanup;
864 status = spec->generate_reverse_prologue(&buf, layout);
865 if (status != INFIX_SUCCESS)
866 goto cleanup;
867 status = spec->generate_reverse_argument_marshalling(&buf, layout, context);
868 if (status != INFIX_SUCCESS)
869 goto cleanup;
870 status = spec->generate_reverse_dispatcher_call(&buf, layout, context);
871 if (status != INFIX_SUCCESS)
872 goto cleanup;
873 status = spec->generate_reverse_epilogue(&buf, layout, context);
874 if (status != INFIX_SUCCESS)
875 goto cleanup;
876 // End of Pipeline
877 if (buf.error || temp_arena->error) {
879 goto cleanup;
880 }
881 context->exec = infix_executable_alloc(buf.size);
882 if (context->exec.rw_ptr == nullptr) {
884 goto cleanup;
885 }
886 infix_memcpy(context->exec.rw_ptr, buf.code, buf.size);
889 goto cleanup;
890 }
891 // Security Hardening: Make the context memory read-only to prevent runtime corruption.
894 goto cleanup;
895 }
896 infix_dump_hex(context->exec.rx_ptr, buf.size, "Reverse Trampoline Machine Code");
897 *out_context = context;
898cleanup:
899 if (status != INFIX_SUCCESS) {
900 // If allocation of the context itself failed, prot.rw_ptr will be null.
901 if (prot.rw_ptr != nullptr)
902 infix_reverse_destroy(context);
903 }
904 infix_arena_destroy(temp_arena);
905 return status;
906}
920 size_t num_args,
921 size_t num_fixed_args,
922 void * user_callback_fn) {
923
926 out_context, return_type, arg_types, num_args, num_fixed_args, user_callback_fn, nullptr, true);
927}
942 size_t num_args,
943 size_t num_fixed_args,
944 infix_closure_handler_fn user_callback_fn,
945 void * user_data) {
946
949 out_context, return_type, arg_types, num_args, num_fixed_args, (void *)user_callback_fn, user_data, false);
950}
959 if (reverse_trampoline == nullptr)
960 return;
961 // The cached trampoline (if it exists) must also be destroyed.
962 if (reverse_trampoline->cached_forward_trampoline)
964 if (reverse_trampoline->arena)
965 infix_arena_destroy(reverse_trampoline->arena);
966 infix_executable_free(reverse_trampoline->exec);
967 // Free the special read-only memory region for the context struct.
968 infix_protected_free(reverse_trampoline->protected_ctx);
969}
977 if (reverse_trampoline == nullptr)
978 return nullptr;
979 return reverse_trampoline->exec.rx_ptr;
980}
987 if (reverse_trampoline == nullptr)
988 return nullptr;
989 return reverse_trampoline->user_data;
990}
991// High-Level Signature API Wrappers
993 infix_arena_t * target_arena,
994 const char * signature,
995 void * target_function,
998 if (!signature) {
1001 }
1002 infix_arena_t * arena = nullptr;
1003 infix_type * ret_type = nullptr;
1004 infix_function_argument * args = nullptr;
1005 size_t num_args = 0, num_fixed = 0;
1006 infix_type ** arg_types = nullptr;
1008 if (signature[0] == '@') {
1009 if (registry == nullptr) {
1011 INFIX_CATEGORY_GENERAL, INFIX_CODE_MISSING_REGISTRY, 0); // Using @Name requires a registry
1013 }
1014 const infix_type * func_type = infix_registry_lookup_type(registry, &signature[1]);
1015 if (func_type == NULL) {
1018 }
1019 if (func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE) {
1020 // The user provided a name for a non-function type (e.g., "@Point")
1023 }
1024 // We have a valid function type from the registry. Now, unpack its components.
1026 num_args = func_type->meta.func_ptr_info.num_args;
1027 num_fixed = func_type->meta.func_ptr_info.num_fixed_args;
1028 args = func_type->meta.func_ptr_info.args;
1029 // The Manual API needs a temporary arena to hold the arg_types array.
1030 infix_arena_t * temp_arena = infix_arena_create(sizeof(infix_type *) * num_args + 128);
1031 if (!temp_arena) {
1034 }
1035 if (num_args > 0) {
1036 arg_types = infix_arena_alloc(temp_arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
1037 if (!arg_types) {
1038 infix_arena_destroy(temp_arena);
1041 }
1042 for (size_t i = 0; i < num_args; ++i)
1043 arg_types[i] = args[i].type;
1044 }
1045 arena = temp_arena;
1046 }
1047 else {
1048 // This is a high-level wrapper. It uses the parser to build the type info first.
1049 status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1050 if (status != INFIX_SUCCESS) {
1052 return status;
1053 }
1054 // Extract the `infix_type*` array from the parsed `infix_function_argument` array.
1055 arg_types = (num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *))
1056 : nullptr;
1057 if (num_args > 0 && !arg_types) {
1061 }
1062 for (size_t i = 0; i < num_args; ++i)
1063 arg_types[i] = args[i].type;
1064 }
1065 // Call the core internal implementation with the parsed types.
1067 out_trampoline, target_arena, ret_type, arg_types, num_args, num_fixed, target_function, false);
1069 return status;
1070}
1072 const char * signature,
1073 void * target_function,
1076 if (!signature || !target_function) {
1079 }
1080 infix_arena_t * arena = nullptr;
1081 infix_type * ret_type = nullptr;
1082 infix_function_argument * args = nullptr;
1083 size_t num_args = 0, num_fixed = 0;
1084 infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1085 if (status != INFIX_SUCCESS) {
1087 return status;
1088 }
1090 (num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *)) : nullptr;
1091 if (num_args > 0 && !arg_types) {
1095 }
1096 for (size_t i = 0; i < num_args; ++i)
1097 arg_types[i] = args[i].type;
1098
1100 out_trampoline, NULL, ret_type, arg_types, num_args, num_fixed, target_function, true);
1102 return status;
1103}
1105 const char * signature,
1106 void * target_function,
1108 return infix_forward_create_in_arena(out_trampoline, NULL, signature, target_function, registry);
1109}
1111 const char * signature,
1113 return infix_forward_create_in_arena(out_trampoline, NULL, signature, NULL, registry);
1114}
1116 const char * signature,
1117 void * target_function,
1121 if (!signature || !target_function || !handlers) {
1124 }
1125
1126 infix_arena_t * arena = nullptr;
1127 infix_type * ret_type = nullptr;
1128 infix_function_argument * args = nullptr;
1129 size_t num_args = 0, num_fixed = 0;
1130 infix_type ** arg_types = nullptr;
1131
1132 // Parse the signature to get the type graph.
1133 infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1134 if (status != INFIX_SUCCESS) {
1136 return status;
1137 }
1138
1139 // Convert the parsed `infix_function_argument*` array to an `infix_type**` array.
1140 if (num_args > 0) {
1141 arg_types = infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *));
1142 if (!arg_types) {
1146 }
1147 for (size_t i = 0; i < num_args; ++i)
1148 arg_types[i] = args[i].type;
1149 }
1150
1151 // Call the core internal implementation with the parsed types and provided handlers.
1152 status =
1153 _infix_forward_create_direct_impl(out_trampoline, ret_type, arg_types, num_args, target_function, handlers);
1154
1155 // Clean up the temporary arena used by the parser.
1157 return status;
1158}
1160 const char * signature,
1161 void * user_callback_fn,
1163 infix_arena_t * arena = nullptr;
1164 infix_type * ret_type = nullptr;
1165 infix_function_argument * args = nullptr;
1166 size_t num_args = 0, num_fixed = 0;
1167 infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1168 if (status != INFIX_SUCCESS) {
1170 return status;
1171 }
1173 (num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *)) : nullptr;
1174 if (num_args > 0 && !arg_types) {
1178 }
1179 for (size_t i = 0; i < num_args; ++i)
1180 arg_types[i] = args[i].type;
1181 // Call the manual API with the parsed types.
1182 status =
1183 infix_reverse_create_callback_manual(out_context, ret_type, arg_types, num_args, num_fixed, user_callback_fn);
1185 return status;
1186}
1188 const char * signature,
1189 infix_closure_handler_fn user_callback_fn,
1190 void * user_data,
1192 infix_arena_t * arena = nullptr;
1193 infix_type * ret_type = nullptr;
1194 infix_function_argument * args = nullptr;
1195 size_t num_args = 0, num_fixed = 0;
1196 infix_status status = infix_signature_parse(signature, &arena, &ret_type, &args, &num_args, &num_fixed, registry);
1197 if (status != INFIX_SUCCESS) {
1199 return status;
1200 }
1202 (num_args > 0) ? infix_arena_alloc(arena, sizeof(infix_type *) * num_args, _Alignof(infix_type *)) : nullptr;
1203 if (num_args > 0 && !arg_types) {
1207 }
1208 for (size_t i = 0; i < num_args; ++i)
1209 arg_types[i] = args[i].type;
1211 out_context, ret_type, arg_types, num_args, num_fixed, user_callback_fn, user_data);
1213 return status;
1214}
1215// ============================================================================
1216// UNITY BUILD INCLUDES
1217// This section includes the actual ABI implementations at the end of the file.
1218// Because `trampoline.c` is the central translation unit, including the
1219// correct ABI-specific .c file here makes its functions (`g_win_x64_spec`, etc.)
1220// available without needing to add platform-specific logic to the build system.
1221// The `infix_config.h` header ensures only one of these #if blocks is active.
1222// ============================================================================
1223#if defined(INFIX_ABI_WINDOWS_X64)
1224#include "../arch/x64/abi_win_x64.c"
1225#include "../arch/x64/abi_x64_emitters.c"
1226#elif defined(INFIX_ABI_SYSV_X64)
1227#include "../arch/x64/abi_sysv_x64.c"
1228#include "../arch/x64/abi_x64_emitters.c"
1229#elif defined(INFIX_ABI_AAPCS64)
1230#include "../arch/aarch64/abi_arm64.c"
1231#include "../arch/aarch64/abi_arm64_emitters.c"
1232#else
1233#error "No supported ABI was selected for the unity build in trampoline.c."
1234#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_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:1437
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:288
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:1115
@ INFIX_CODE_MISSING_REGISTRY
Definition infix.h:1365
@ INFIX_CODE_UNRESOLVED_NAMED_TYPE
Definition infix.h:1387
@ INFIX_CODE_INTEGER_OVERFLOW
Definition infix.h:1379
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1375
@ INFIX_CODE_UNSUPPORTED_ABI
Definition infix.h:1385
@ INFIX_CODE_NULL_POINTER
Definition infix.h:1364
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1369
@ INFIX_CATEGORY_ABI
Definition infix.h:1355
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1353
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1352
@ INFIX_CATEGORY_PARSER
Definition infix.h:1354
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:280
infix_type * type
Definition infix.h:348
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:1085
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:418
void(* infix_unbound_cif_func)(void *, void *, void **)
A function pointer type for an unbound forward trampoline.
Definition infix.h:409
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:1159
infix_struct_member * members
Definition infix.h:293
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:1071
infix_function_argument * args
Definition infix.h:306
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:1187
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:434
const char * name
Definition infix.h:347
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:992
infix_type_category category
Definition infix.h:276
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:289
infix_type * type
Definition infix.h:336
struct infix_type_t * element_type
Definition infix.h:299
struct infix_type_t * return_type
Definition infix.h:305
size_t num_members
Definition infix.h:294
size_t num_fixed_args
Definition infix.h:308
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:1110
void(* infix_closure_handler_fn)(infix_context_t *, void *, void **)
A function pointer type for a generic closure handler.
Definition infix.h:430
size_t num_args
Definition infix.h:307
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:1104
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:436
@ INFIX_ERROR_PROTECTION_FAILED
Definition infix.h:440
@ INFIX_ERROR_UNSUPPORTED_ABI
Definition infix.h:438
@ INFIX_SUCCESS
Definition infix.h:435
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:437
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:2009
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:976
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:278
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:283
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:986
@ INFIX_DIALECT_SIGNATURE
Definition infix.h:1176
INFIX_API void infix_reverse_destroy(infix_reverse_t *reverse_trampoline)
Destroys a reverse trampoline and frees all associated memory.
Definition trampoline.c:958
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:662
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:688
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:939
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:917
INFIX_API void infix_forward_destroy(infix_forward_t *trampoline)
Destroys a forward trampoline and frees all associated memory.
Definition trampoline.c:720
#define infix_free
A macro that can be defined to override the default free function.
Definition infix.h:383
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_memcpy
A macro that can be defined to override the default memcpy function.
Definition infix.h:387
#define infix_calloc
A macro that can be defined to override the default calloc function.
Definition infix.h:375
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:391
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:231
@ INFIX_TYPE_ARRAY
Definition infix.h:232
@ INFIX_TYPE_POINTER
Definition infix.h:229
@ INFIX_TYPE_NAMED_REFERENCE
Definition infix.h:237
@ INFIX_TYPE_REVERSE_TRAMPOLINE
Definition infix.h:233
@ INFIX_TYPE_STRUCT
Definition infix.h:230
#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:201
Internal data structures, function prototypes, and constants.
@ INFIX_EXECUTABLE_REVERSE
Definition infix_internals.h:701
@ INFIX_EXECUTABLE_SAFE_FORWARD
Definition infix_internals.h:700
@ INFIX_EXECUTABLE_DIRECT
Definition infix_internals.h:702
@ INFIX_EXECUTABLE_FORWARD
Definition infix_internals.h:699
INFIX_INTERNAL void _infix_cache_insert(infix_forward_t *trampoline)
Definition cache.c:78
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:1045
INFIX_INTERNAL void infix_protected_free(infix_protected_t prot)
Frees a block of protected memory.
Definition executor.c:1079
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:1112
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:1217
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:1099
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:166
INFIX_INTERNAL infix_forward_t * _infix_cache_lookup(const char *signature, void *target_fn, bool is_safe)
Definition cache.c:57
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:1138
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:299
uint32_t epilogue_offset
Definition infix_internals.h:315
uint32_t prologue_size
Definition infix_internals.h:314
A struct containing all the necessary handlers for a single function argument.
Definition infix.h:1500
A complete layout blueprint for a direct marshalling forward call frame.
Definition infix_internals.h:487
uint32_t epilogue_offset
Offset from the start of the JIT block to the epilogue.
Definition infix_internals.h:494
uint32_t prologue_size
Size of the generated prologue in bytes.
Definition infix_internals.h:493
Defines the ABI-specific implementation interface for direct marshalling forward trampolines.
Definition infix_internals.h:503
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:517
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:515
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:505
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:520
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:513
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:348
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:377
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:387
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:398
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:364
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:406
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:346
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:417
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:442
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:425
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:434
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:452
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:462
A complete layout blueprint for a reverse call frame.
Definition infix_internals.h:324
uint32_t prologue_size
Definition infix_internals.h:332
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:274
Definition trampoline.c:193
const infix_type * type
Definition trampoline.c:194
struct visited_node_t * next
Definition trampoline.c:195
void emit_byte(code_buffer *buf, uint8_t byte)
A convenience wrapper to append a single byte to a code buffer.
Definition trampoline.c:186
static bool _is_type_graph_resolved_recursive(const infix_type *type, visited_node_t *visited_head)
Definition trampoline.c:209
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:84
void code_buffer_init(code_buffer *buf, infix_arena_t *arena)
Initializes a code buffer for JIT code generation.
Definition trampoline.c:135
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:316
static bool _is_type_graph_resolved(const infix_type *type)
Definition trampoline.c:248
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:190
void _infix_forward_destroy_internal(infix_forward_t *trampoline)
Definition trampoline.c:701
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:154
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:529
static size_t get_page_size()
Definition trampoline.c:727
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:188
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:263
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:117
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:760
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:101
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