-
Notifications
You must be signed in to change notification settings - Fork 58
Enable users to map from GV to Julia value #746
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
2773ec1
1c22f00
213a066
91012be
acd969c
bc3e9d1
9973a9e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -253,6 +253,13 @@ end | |
| if !ondisk_hit && path !== nothing && disk_cache_enabled() | ||
| @debug "Writing out on-disk cache" job path | ||
| mkpath(dirname(path)) | ||
| if haskey(asm[2], :gv_to_value) | ||
| # TODO: Serializer cannot handle Core.IntrinsicFunction | ||
| # We kinda want Julia to serialize the values in `gv_to_value` in the pkgimg and us just having to store an index | ||
| # for now we just empty them out | ||
| # We would need to remove the initializers from LLVM IR as well to be correct, and then link these in at runtime | ||
| empty!(asm[2].gv_to_value) | ||
|
Comment on lines
+256
to
+261
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should likely just give up on caching this for now if For proper caching, we would want to create an |
||
| end | ||
| entry = DiskCacheEntry(src.specTypes, cfg, asm) | ||
|
|
||
| # atomic write to disk | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -672,6 +672,28 @@ end | |
| CompilationPolicyExtern = 1 | ||
| end | ||
|
|
||
| const AL_N_INLINE = 29 | ||
| # mirrows arraylist_t | ||
| mutable struct ArrayList | ||
| len::Csize_t | ||
| max::Csize_t | ||
| items::Ptr{Ptr{Cvoid}} | ||
| _space::NTuple{AL_N_INLINE, Ptr{Cvoid}} | ||
|
|
||
| function ArrayList() | ||
| list = new(0, AL_N_INLINE, Ptr{Ptr{Cvoid}}(C_NULL), ntuple(_->Ptr{Cvoid}(C_NULL), AL_N_INLINE)) | ||
| list.items = Base.pointer_from_objref(list) + fieldoffset(typeof(list), 4) | ||
|
|
||
| finalizer(list) do list | ||
| if list.items != Base.pointer_from_objref(list) + fieldoffset(typeof(list), 4) | ||
| Libc.free(list.items) | ||
| end | ||
| end | ||
| return list | ||
| end | ||
| end | ||
|
|
||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😱 For backwards compatibility we need to support the internal |
||
|
|
||
| """ | ||
| precompile(job::CompilerJob) | ||
|
|
||
|
|
@@ -786,25 +808,73 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) | |
| cache_gbl = nothing | ||
| end | ||
|
|
||
| gv_to_value = Dict{String, Ptr{Cvoid}}() | ||
|
|
||
| # The caller is responsible for initializing global variables that | ||
| # point to global values or bindings with their address in memory. | ||
| # For Julia < v"1.13" to enable relocation we strip out the initializers here. | ||
| if VERSION >= v"1.13.0-DEV.623" | ||
| # Since Julia 1.13, the caller is responsible for initializing global variables that | ||
| # point to global values or bindings with their address in memory. | ||
| num_gvars = Ref{Csize_t}(0) | ||
| @ccall jl_get_llvm_gvs(native_code::Ptr{Cvoid}, num_gvars::Ptr{Csize_t}, | ||
| C_NULL::Ptr{Cvoid})::Nothing | ||
| C_NULL::Ptr{Cvoid})::Nothing | ||
| gvs = Vector{Ptr{LLVM.API.LLVMOpaqueValue}}(undef, num_gvars[]) | ||
| @ccall jl_get_llvm_gvs(native_code::Ptr{Cvoid}, num_gvars::Ptr{Csize_t}, | ||
| gvs::Ptr{LLVM.API.LLVMOpaqueValue})::Nothing | ||
| gvs::Ptr{LLVM.API.LLVMOpaqueValue})::Nothing | ||
|
|
||
| inits = Vector{Ptr{Cvoid}}(undef, num_gvars[]) | ||
| @ccall jl_get_llvm_gv_inits(native_code::Ptr{Cvoid}, num_gvars::Ptr{Csize_t}, | ||
| inits::Ptr{Cvoid})::Nothing | ||
|
|
||
| for (gv_ref, init) in zip(gvs, inits) | ||
| gv = GlobalVariable(gv_ref) | ||
| val = const_inttoptr(ConstantInt(Int64(init)), LLVM.PointerType()) | ||
| initializer!(gv, val) | ||
| gv_to_value[LLVM.name(gv)] = init | ||
| end | ||
| else | ||
| # Prior to this version of Julia we only had access to the values that the global variables | ||
| # were initialized with, so we have to match them up manually. | ||
| # get the global values | ||
| if VERSION >= v"1.12.0-DEV.1703" | ||
| num_gvars = Ref{Csize_t}(0) | ||
| @ccall jl_get_llvm_gvs(native_code::Ptr{Cvoid}, num_gvars::Ptr{Csize_t}, | ||
| C_NULL::Ptr{Cvoid})::Nothing | ||
| gvalues = Vector{Ptr{Cvoid}}(undef, num_gvars[]) | ||
| @ccall jl_get_llvm_gvs(native_code::Ptr{Cvoid}, num_gvars::Ptr{Csize_t}, | ||
| gvalues::Ptr{Cvoid})::Nothing | ||
| else | ||
| # Sigh on older version of Julia we have to use `arraylist_t` which doesn't have a Julia API. | ||
| gvars = ArrayList() | ||
| GC.@preserve gvars begin | ||
| p_gvars = Base.pointer_from_objref(gvars) | ||
| @ccall jl_get_llvm_gvs(native_code::Ptr{Cvoid}, p_gvars::Ptr{Cvoid})::Nothing | ||
| gvalues = Vector{Ptr{Cvoid}}(undef, gvars.len) | ||
| for i in 1:gvars.len | ||
| gvalues[i] = unsafe_load(gvars.items, i) | ||
| end | ||
| end | ||
| end | ||
| gvalues = Set(gvalues) | ||
| for gv in globals(llvm_mod) | ||
| init = LLVM.initializer(gv) | ||
| if init === nothing | ||
| continue | ||
| end | ||
| if init isa LLVM.ConstantExpr && opcode(init) == LLVM.API.LLVMIntToPtr | ||
| init = operands(init)[1] | ||
| end | ||
| if !(init isa LLVM.ConstantInt) | ||
| continue | ||
| end | ||
| ptr = reinterpret(Ptr{Cvoid}, convert(UInt, init)) | ||
| if ptr in gvalues | ||
| gv_to_value[LLVM.name(gv)] = ptr | ||
| end | ||
| LLVM.initializer!(gv, nothing) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we don't necessarily need to delete the initializer here, but it makes the code a bit more consistent. |
||
| end | ||
| @assert length(gv_to_value) == length(gvalues) | ||
| end | ||
| # It's valid to call Base.unsafe_pointer_to_objref on values(gv_to_value), | ||
| # but we may not be able to "easily" obtain the pointer back later. | ||
| # (Types, etc, disallow Base.pointer_from_objref on them.) | ||
|
|
||
| if VERSION >= v"1.13.0-DEV.1120" | ||
| # on sufficiently recent versions of Julia, we can query the CIs compiled. | ||
|
|
@@ -874,7 +944,7 @@ function compile_method_instance(@nospecialize(job::CompilerJob)) | |
| # ensure that the requested method instance was compiled | ||
| @assert haskey(compiled, job.source) | ||
|
|
||
| return llvm_mod, compiled | ||
| return llvm_mod, compiled, gv_to_value | ||
| end | ||
|
|
||
| # partially revert JuliaLangjulia#49391 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am open to a better name