Preserving function signature of internal function

The following code:

fn a(arg1: u64, arg2: u64, arg3: u64) u64 {
    return arg1 + arg2 + arg3;
}

export fn b(arg1: u64, arg2: u64) u64 {
    return @call(.never_inline, a, .{arg1, arg2, 0xdeadbeef});
}

Compiles to this (ReleaseSmall):

b:
        jmp     example.a

example.a:
        mov     eax, 3735928559
        add     rax, rdi
        add     rax, rsi
        ret

Is there a way I keep the constant from being injected into a() without actually exporting a()?

You can use std.mem.doNotOptimizeAway:

    var constant: u64 = 0xdeadbeef;
    std.mem.doNotOptimizeAway(&constant);
    return @call(.never_inline, a, .{arg1, arg2, constant});

Also may I ask why you want to do this?

1 Like

That adds a lot of additional instructions. The following produce the right code:

fn a(arg1: u64, arg2: u64, arg3: u64) u64 {
    return arg1 + arg2 + arg3;
}

const A: *const anyopaque = @ptrCast(&a);

export fn b(arg1: u64, arg2: u64) u64 {
    _ = A;
    return @call(.never_inline, a, .{arg1, arg2, 0xdeadbeef});
}

But there’s no guarantee it’ll continue to work in the future.

What I’m trying to do is dynamically create new functions. b() wouldn’t actually be called. Instead, it’s going to be used as a template. The deadbeef will get replaced by actual ids referencing JavaScript functions.