We have nearly reached the end of the current roadmap. infix is fast, secure, and portable. But optimization is an addiction, and I am already looking at the next bottleneck. The new direct marshalling API wins the benchmark races because it removes the intermediate step of packing C values into a buffer. Double indirection is slower than pulling them straight from the source SV*s.

But what if we start with raw C values? What if we pretend we aren't wrapping a scripting language, but building a high-performance event system or a hot-reloadable game engine?

Currently, you have to do this:

int a = 10;
double b = 20.0;
void* args[] = { &a, &b }; // <--- Indirection #1: The Array
// Inside the JIT:
// 1. Read args[0]  -> get pointer to 'a'
// 2. Read *pointer -> get value 10

This is the libffi model. It's flexible, but it is cache-unfriendly. The args array is in one place, a is on the stack, b might be on the heap. The CPU has to gather scattered memory from a wide range of locations.

I am plotting the implementation of a something that has been on my TODO list almost from the start: packed trampolines. Now that we have a functioning type graph and introspection system, this should be possible.

The Concept: Arguments as a Struct

Instead of passing an array of pointers, what if we passed a single pointer to a block of memory where the arguments are laid out contiguously?

// Concept: The Packed Buffer
struct PackedArgs {
    int a;
    // 4 bytes padding for alignment
    double b;
};

struct PackedArgs args = { 10, 20.0 };
infix_packed_cif(&args);

This changes the JIT's job from "gather" to "offset".

The JIT Transformation

Let's look at the assembly difference on x86-64 (ARM always take a back seat...) for loading the second argument (double b).

Current Approach:

; R14 points to void** args
MOV R15, [R14 + 8] ; Load the pointer to 'b' into scratch reg
MOVSD XMM0, [R15]  ; Dereference to get the value

We have two memory loads. If [R14 + 8] and [R15] are far apart, we might stall on two cache misses.

Proposed Approach:

; R14 points to the packed buffer
MOVSD XMM0, [R14 + 8] ; Load value directly from offset 8

One instruction. One memory load. Perfect spatial locality and that translates into speed.

Implementation Challenges

Implementing infix_forward_create_packed requires a new kind of logic in the ABI layer: layout computation.

The JIT doesn't just need to know that Arg 1 is a double; it needs to know exactly where that double sits in the packed buffer relative to Arg 0.

This implies a pre-calculation phase that mimics our struct layout logic:

// Hypothetical layout logic
size_t current_offset = 0;
for (int i=0; i < num_args; ++i) {
    infix_type* type = arg_types[i];
    // Align the current offset
    size_t align = infix_type_get_alignment(type);
    current_offset = (current_offset + align - 1) & ~(align - 1);
    
    // Store this offset for the JIT emitter
    layout->arg_offsets[i] = current_offset;
    
    current_offset += infix_type_get_size(type);
}

The JIT emitter then uses these pre-calculated offsets to generate the MOV instructions.

Why bother?

For general application logic, saving one MOV instruction is negligible. But for data-oriented design, this is a game changer.

Imagine a system where you have a buffer of network packets or a file loaded from disk. The data is already packed.

This enables Zero-Copy FFI!

If infix supports this, it becomes more than just a function caller; it becomes a bridge that can map binary data directly to function invocations without deserialization overhead.

The Roadmap

This feature is currently in the design phase. It requires:

  1. Extending the infix_call_frame_layout to support explicit byte offsets for sources.
  2. Adding a infix_packed_layout_create API to helper users build the input buffers correctly.
  3. Updating the architecture emitters to support "Base + Offset" loading (which they mostly do already).

It’s the logical conclusion of the project: moving from "calling functions dynamically" to "executing data."

This is not a top priority but stay tuned.