From 1bd4f59049fe6c9ee3af0239d978de9ca12cb756 Mon Sep 17 00:00:00 2001 From: "William S. Moses" Date: Fri, 16 Jan 2026 12:42:31 -0600 Subject: [PATCH 1/6] Fix codeinstance mapping when using nested interpretation --- src/jlgen.jl | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/jlgen.jl b/src/jlgen.jl index 0d380cbf..64ef603b 100644 --- a/src/jlgen.jl +++ b/src/jlgen.jl @@ -670,6 +670,11 @@ function Base.precompile(@nospecialize(job::CompilerJob)) return true end + +const HAS_LLVM_GET_CIS = VERSION >= v"1.13.0-DEV.1120" || Libdl.dlsym( + unsafe_load(cglobal(:jl_libjulia_handle, Ptr{Cvoid})), :jl_get_llvm_cis, throw_error = false +) !== nothing + function compile_method_instance(@nospecialize(job::CompilerJob)) if job.source.def.primary_world > job.world error("Cannot compile $(job.source) for world $(job.world); method is only valid from world $(job.source.def.primary_world) onwards") @@ -786,7 +791,9 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) end end - if VERSION >= v"1.13.0-DEV.1120" + code_instances = Core.CodeInstance[] + + if HAS_LLVM_GET_CIS # on sufficiently recent versions of Julia, we can query the CIs compiled. # this is required after the move to `invoke(::CodeInstance)`, because our # lookup function (used to populate method_instances) isn't always called then. @@ -794,14 +801,10 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) num_cis = Ref{Csize_t}(0) @ccall jl_get_llvm_cis(native_code::Ptr{Cvoid}, num_cis::Ptr{Csize_t}, C_NULL::Ptr{Cvoid})::Nothing - resize!(method_instances, num_cis[]) + resize!(code_instances, num_cis[]) @ccall jl_get_llvm_cis(native_code::Ptr{Cvoid}, num_cis::Ptr{Csize_t}, - method_instances::Ptr{Cvoid})::Nothing - - for (i, ci) in enumerate(method_instances) - method_instances[i] = ci.def::MethodInstance - end - + code_instances::Ptr{Cvoid} + )::Nothing elseif VERSION >= v"1.12.0-DEV.1703" # slightly older versions of Julia used MIs directly @@ -813,12 +816,32 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) method_instances::Ptr{Cvoid})::Nothing end - # process all compiled method instances - compiled = Dict() - for mi in method_instances + if !HAS_LLVM_GET_CIS ci = ci_cache_lookup(cache, mi, job.world, job.world) ci === nothing && continue + llvm_func_idx = Ref{Int32}(-1) + llvm_specfunc_idx = Ref{Int32}(-1) + ccall( + :jl_get_function_id, Nothing, + (Ptr{Cvoid}, Any, Ptr{Int32}, Ptr{Int32}), + native_code, ci, llvm_func_idx, llvm_specfunc_idx + ) + if llvm_func_idx[] != -1 + continue + end + push!(code_instances, ci) + end + + resize!(method_instances, length(code_instances)) + for (i, ci) in enumerate(code_instances) + code_instances[i] = ci.def::MethodInstance + end + + # process all compiled method instances + compiled = Dict() + for (ci, mi) in zip(code_instances, method_instances) + # get the function index llvm_func_idx = Ref{Int32}(-1) llvm_specfunc_idx = Ref{Int32}(-1) @@ -846,6 +869,8 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) nothing end + @assert !haskey(compiled, mi) + # NOTE: it's not safe to store raw LLVM functions here, since those may get # removed or renamed during optimization, so we store their name instead. compiled[mi] = (; ci, func=llvm_func, specfunc=llvm_specfunc) From 3b0aeaed6f7e8aedab2d597f4882e3b1d85781f6 Mon Sep 17 00:00:00 2001 From: "William S. Moses" Date: Fri, 16 Jan 2026 12:48:47 -0600 Subject: [PATCH 2/6] syntax? --- src/jlgen.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jlgen.jl b/src/jlgen.jl index 64ef603b..9bd51a37 100644 --- a/src/jlgen.jl +++ b/src/jlgen.jl @@ -671,9 +671,9 @@ function Base.precompile(@nospecialize(job::CompilerJob)) end -const HAS_LLVM_GET_CIS = VERSION >= v"1.13.0-DEV.1120" || Libdl.dlsym( +const HAS_LLVM_GET_CIS = (VERSION >= v"1.13.0-DEV.1120" || (Libdl.dlsym( unsafe_load(cglobal(:jl_libjulia_handle, Ptr{Cvoid})), :jl_get_llvm_cis, throw_error = false -) !== nothing + ) !== nothing)) function compile_method_instance(@nospecialize(job::CompilerJob)) if job.source.def.primary_world > job.world From 875e7c4267e72d7dde0c46277a0396fe5d9edb23 Mon Sep 17 00:00:00 2001 From: "William S. Moses" Date: Fri, 16 Jan 2026 12:49:27 -0600 Subject: [PATCH 3/6] syntax? --- src/jlgen.jl | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/jlgen.jl b/src/jlgen.jl index 9bd51a37..6808450b 100644 --- a/src/jlgen.jl +++ b/src/jlgen.jl @@ -671,9 +671,13 @@ function Base.precompile(@nospecialize(job::CompilerJob)) end -const HAS_LLVM_GET_CIS = (VERSION >= v"1.13.0-DEV.1120" || (Libdl.dlsym( - unsafe_load(cglobal(:jl_libjulia_handle, Ptr{Cvoid})), :jl_get_llvm_cis, throw_error = false - ) !== nothing)) +const HAS_LLVM_GET_CIS = ( + VERSION >= v"1.13.0-DEV.1120" || ( + Libdl.dlsym( + unsafe_load(cglobal(:jl_libjulia_handle, Ptr{Cvoid})), :jl_get_llvm_cis, throw_error = false + ) !== nothing + ) +) function compile_method_instance(@nospecialize(job::CompilerJob)) if job.source.def.primary_world > job.world @@ -817,20 +821,22 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) end if !HAS_LLVM_GET_CIS + for mi in method_instances ci = ci_cache_lookup(cache, mi, job.world, job.world) ci === nothing && continue - llvm_func_idx = Ref{Int32}(-1) - llvm_specfunc_idx = Ref{Int32}(-1) - ccall( - :jl_get_function_id, Nothing, - (Ptr{Cvoid}, Any, Ptr{Int32}, Ptr{Int32}), - native_code, ci, llvm_func_idx, llvm_specfunc_idx - ) - if llvm_func_idx[] != -1 - continue + llvm_func_idx = Ref{Int32}(-1) + llvm_specfunc_idx = Ref{Int32}(-1) + ccall( + :jl_get_function_id, Nothing, + (Ptr{Cvoid}, Any, Ptr{Int32}, Ptr{Int32}), + native_code, ci, llvm_func_idx, llvm_specfunc_idx + ) + if llvm_func_idx[] != -1 + continue + end + push!(code_instances, ci) end - push!(code_instances, ci) end resize!(method_instances, length(code_instances)) From 2d0a25582db69a162a7a1a73f80dc05bc1315564 Mon Sep 17 00:00:00 2001 From: "William S. Moses" Date: Fri, 16 Jan 2026 12:53:27 -0600 Subject: [PATCH 4/6] correct --- src/jlgen.jl | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/jlgen.jl b/src/jlgen.jl index 6808450b..5650c05e 100644 --- a/src/jlgen.jl +++ b/src/jlgen.jl @@ -822,8 +822,8 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) if !HAS_LLVM_GET_CIS for mi in method_instances - ci = ci_cache_lookup(cache, mi, job.world, job.world) - ci === nothing && continue + ci = ci_cache_lookup(cache, mi, job.world, job.world) + ci === nothing && continue llvm_func_idx = Ref{Int32}(-1) llvm_specfunc_idx = Ref{Int32}(-1) @@ -832,16 +832,32 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) (Ptr{Cvoid}, Any, Ptr{Int32}, Ptr{Int32}), native_code, ci, llvm_func_idx, llvm_specfunc_idx ) - if llvm_func_idx[] != -1 + if llvm_func_idx[] == -1 continue end push!(code_instances, ci) end + else + # To avoid a clash in the compiled cache containing both with an interpreter token (like GPUCompiler.GPUCompilerCacheToken) and native, + # prefer the non-native code-instance. + # TODO: in the future we should migrate compiled to have the ci as the key, not the mi. + native_mis = Set{MethodInstance}() + for ci in code_instances + if ci.cache !== nothing + push!(native_mis, ci.def::MethodInstance) + end + end + filter!(code_instances) do ci + return ci.cache !== nothing || in(ci.def, native_mis) + end end + # Avoid redundant code_instances. This is necessary to avoid false positives trying to add the same key'd mi to the compiled Dict. + unique!(code_instances) + resize!(method_instances, length(code_instances)) for (i, ci) in enumerate(code_instances) - code_instances[i] = ci.def::MethodInstance + method_instances[i] = ci.def::MethodInstance end # process all compiled method instances From 90005764089526e73d4c3260b0bfaebe34447305 Mon Sep 17 00:00:00 2001 From: "William S. Moses" Date: Sun, 18 Jan 2026 11:44:25 -0600 Subject: [PATCH 5/6] add comment --- src/jlgen.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jlgen.jl b/src/jlgen.jl index 5650c05e..cfc99d8d 100644 --- a/src/jlgen.jl +++ b/src/jlgen.jl @@ -832,6 +832,10 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) (Ptr{Cvoid}, Any, Ptr{Int32}, Ptr{Int32}), native_code, ci, llvm_func_idx, llvm_specfunc_idx ) + # Suppose we have two nested interpreters in use at the same time. + # Looking up a ci from the cache is not unique for a given mi. + # Consequently its possible we may not have compiled the ci found + # by the cache (instead having compiled the ci from the other interp). if llvm_func_idx[] == -1 continue end From 6fb410ab1b06683cb58e50d1aadafaf53417afea Mon Sep 17 00:00:00 2001 From: "William S. Moses" Date: Sun, 18 Jan 2026 12:00:06 -0600 Subject: [PATCH 6/6] fix 1.13 --- src/jlgen.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jlgen.jl b/src/jlgen.jl index cfc99d8d..00e5b39c 100644 --- a/src/jlgen.jl +++ b/src/jlgen.jl @@ -847,12 +847,12 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) # TODO: in the future we should migrate compiled to have the ci as the key, not the mi. native_mis = Set{MethodInstance}() for ci in code_instances - if ci.cache !== nothing + if ci.owner !== nothing push!(native_mis, ci.def::MethodInstance) end end filter!(code_instances) do ci - return ci.cache !== nothing || in(ci.def, native_mis) + return ci.owner !== nothing || in(ci.def, native_mis) end end