Passing struct by value in static compiling

We know in Julia structs are passed by reference, and this is also the case in StaticCompiler.jl:

using StaticTools
using StaticCompiler

struct StudentInfo 
    name::StaticString
    id::Cint
end

id(student::StudentInfo) = student.id

compile_shlib(id, (StudentInfo,))

# The following line is wrong: Julia functions only accept pointers to structs 
# It likely gives you some nonsense like 1461676824
@ccall "./id.so".id(StudentInfo(c"Lucas", 14)::StudentInfo)::Cint

# The following line is right
@ccall "./id.so".id(Ref(StudentInfo(c"Lucas", 14))::Ref{StudentInfo})::Cint

Now suppose I’m to write a library that is static enough to be compiled by StaticCompiler and might be called by non-Julia codes, like a C++ project. Suppose I want to pass a 3D vector (a composite type, but a small one) to a function in the library. In Julia this can be easily done as in my_function(SVector{3, Float64}(1.0, 2.0, 3.0)); in C/C++, however, you can’t write my_function(Point{1.0, 2.0, 3.0}) where Point is appropriately defined: you have to pass a pointer to my_function, which makes the code verbose.

Is there any way to let a Julia function recognize an incoming immutable composite type variable as a value, not a pointer? If this is not supported currently (it seems to be not supported), is there any inherent obstruction that prevents this from being done in the future?

Are they? There are many mentions of passing by value here.

What you mentioned here is the behavior of ccall, and in @ccall "my-library.so".my_function(somet_struct), some_struct is indeed passed by value. But this is calling C function from Julia: when a Julia function is defined, it seems to accept a pointer to the struct being passed.

This can also be directly verified by @code_llvm:


using StaticArrays

function first(s::SVector{3, Int})
s[1]
end

arr = SVector{3, Int}([1, 2, 3])
@code_llvm first(arr)


; @ REPL[9]:1 within `first`
define i64 @julia_first_909([1 x [3 x i64]]* nocapture noundef nonnull readonly align 8 dereferenceable(24) %0) #0 {
top:
; @ REPL[9]:2 within `first`
; ┌ @ /home/jinyuan/.julia/packages/StaticArrays/yXGNL/src/SArray.jl:62 within `getindex` @ tuple.jl:29
%1 = getelementptr inbounds [1 x [3 x i64]], [1 x [3 x i64]]* %0, i64 0, i64 0, i64 0
; └
%2 = load i64, i64* %1, align 8
ret i64 %2
}

Note that * after [1 x [3 x i64]], which is SVector{3, Int64} (a tuple of three 64bit integers in a struct).

1 Like