JuliaLang / AllocCheck.jl

AllocCheck
Other
209 stars 8 forks source link

Bug: ccall method definition: return type doesn't correspond to a C type #70

Open jakobnissen opened 5 months ago

jakobnissen commented 5 months ago

MWE:

julia> using AllocCheck

julia> @check_allocs function foobars(d::Dict{Tuple{Float64, Float64}, Int})
           peeled = Iterators.peel(keys(d))
           isnothing(peeled) && return nothing
           (recall, precision), rest = peeled
           (max_recall, max_precision, max_f1) = (recall, precision, recall + precision)
           for (recall, precision) in rest
               this_f1 = recall + precision
               if this_f1 > max_f1
                   (max_f1, max_recall, max_precision) = (recall, precision, this_f1)
               end
           end
           (max_recall, max_precision)
       end
foobars (generic function with 1 method)

julia> foobars(Dict((1.0, 1.0)=>1))
ERROR: ccall method definition: return type doesn't correspond to a C type
Stacktrace:
 [1] (::AllocCheck.CompileResult{true, var"###foobars#225", Tuple{…}, Union{…}})(args::Dict{Tuple{…}, Int6
4})
   @ AllocCheck ~/.julia/packages/AllocCheck/xTVrb/src/compiler.jl:156
 [2] foobars(d::Dict{Tuple{Float64, Float64}, Int64})
   @ Main ./REPL[3]:144
 [3] top-level scope
   @ REPL[4]:1

julia> versioninfo()
Julia Version 1.10.0
Commit 3120989f39b (2023-12-25 18:01 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 16 × AMD Ryzen 7 PRO 7840U w/ Radeon 780M Graphics
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, znver3)
  Threads: 1 on 16 virtual cores
topolarity commented 5 months ago

This is a tricky one. I've started an implementation at https://github.com/JuliaLang/AllocCheck.jl/commit/75112007e700880eaaaf3948a71160b2e38ba3dc but I need to figure out how to re-construct the Union return type from the returned selector + payload, which I'm not sure is possible/legal from the Julia side. If that fails, we'll be forced to fall back to the slower invoke ABI that passes all arguments/return types in boxes.

Since this is a dynamic dispatch + cache lookup anyway, it's probably a tolerable performance cost (certainly not ideal though).