Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/ccalls.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,18 +120,36 @@ else
# we need to do so ourselves in order to insert a jl_gc_safe_enter|leave
# just around the inner ccall

# like Base, support calling a function pointer that is interpolated with `$`
statements = []
if Meta.isexpr(func, :$)
fptr = gensym("fptr")
push!(statements, :($fptr = $(esc(func.args[1]))))
name = QuoteNode(func.args[1])
push!(statements, quote
if !isa($fptr, Ptr{Cvoid})
throw(ArgumentError(LazyString("interpolated function `", $name,
"` was not a Ptr{Cvoid}, but ",
typeof($fptr))))
end
end)
func = fptr
else
func = esc(func)
end

cconvert_exprs = []
cconvert_args = []
for (typ, arg) in zip(types, args)
var = gensym("$(func)_cconvert")
var = gensym("cconvert")
push!(cconvert_args, var)
push!(cconvert_exprs, :($var = Base.cconvert($(esc(typ)), $(esc(arg)))))
end

unsafe_convert_exprs = []
unsafe_convert_args = []
for (typ, arg) in zip(types, cconvert_args)
var = gensym("$(func)_unsafe_convert")
var = gensym("unsafe_convert")
push!(unsafe_convert_args, var)
push!(unsafe_convert_exprs, :($var = Base.unsafe_convert($(esc(typ)), $arg)))
end
Expand All @@ -141,7 +159,7 @@ else

gc_state = @ccall(jl_gc_safe_enter()::Int8)
ret = ccall(
$(esc(func)), $(esc(rettype)), $(Expr(:tuple, map(esc, types)...)),
$func, $(esc(rettype)), $(Expr(:tuple, map(esc, types)...)),
$(unsafe_convert_args...)
)
@ccall(jl_gc_safe_leave(gc_state::Int8)::Cvoid)
Expand All @@ -150,6 +168,7 @@ else

return quote
@inline
$(statements...)
$(cconvert_exprs...)
GC.@preserve $(cconvert_args...) $(call)
end
Expand Down
8 changes: 8 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ using IOCapture
@gcsafe_ccall jl_rand()::UInt64
end

# interpolated function pointers
fptr = cglobal(:jl_rand)
@test (@gcsafe_ccall $fptr()::UInt64) isa UInt64
if !GPUToolbox.HAS_CCALL_GCSAFE
# like `@ccall` on these Julia versions, the fallback checks the pointer
@test_throws ArgumentError @gcsafe_ccall $(nothing)()::UInt64
end

let llvm = sprint(code_llvm, gc_safe_ccall, ())
# check that the call works
@test gc_safe_ccall() isa UInt64
Expand Down
Loading