diff --git a/src/jlgen.jl b/src/jlgen.jl index d4820377..d55517fe 100644 --- a/src/jlgen.jl +++ b/src/jlgen.jl @@ -796,8 +796,11 @@ function relocate_gvs!(mod::LLVM.Module, gv_to_value::Dict{String, Ptr{Cvoid}}) val = nothing if init != C_NULL obj = Base.unsafe_pointer_to_objref(init) - # Zero-sized objects remain identity tokens. - if isbitstype(typeof(obj)) && sizeof(obj) > 0 && !(obj isa Bool) + # Zero-sized objects remain identity tokens. Type objects also stay + # identity tokens: some are isbits singletons (e.g. `Union{}`, whose + # `typeof` is the isbits singleton `Core.TypeofBottom`), but `sizeof` + # is undefined for uninhabited types and would throw here. + if isbitstype(typeof(obj)) && !(obj isa Type) && sizeof(obj) > 0 && !(obj isa Bool) val, hdr = materialize_box!(mod, gv, obj, init) # non-smalltag headers carry a host DataType pointer portable &= hdr < UInt(64 << 4) # jl_max_tags << 4 diff --git a/test/native.jl b/test/native.jl index 834c0f20..27df7b4d 100644 --- a/test/native.jl +++ b/test/native.jl @@ -429,6 +429,19 @@ end @test length(elements(LLVM.global_value_type(box))) == 3 dispose(m) end + + # Type objects stay identity tokens rather than being materialized. + # `Union{}` is the tricky case: `typeof(Union{})` is the isbits + # singleton `Core.TypeofBottom`, so the `isbitstype` guard passes, + # but `sizeof(Union{})` throws (uninhabited type). It must be baked + # as an address, not fed to `materialize_box!`. + let ptr = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), Union{}) + m, map = slot_module(ptr) + @test !GPUCompiler.relocate_gvs!(m, map) + @test !haskey(globals(m), "jl_global_0_box") + @test occursin("inttoptr", string(m)) + dispose(m) + end end end