@@ -38,16 +38,98 @@ Normally, you shouldn't have to use this function, as it's used by `FunctionSpec
3838"""
3939get_world
4040
41- # generate functions currently do not know which world they are invoked for, so we fall
42- # back to using the current world. this may be wrong when the generator is invoked in a
43- # different world (TODO : when does this happen?)
44- #
45- # XXX : this should be fixed by JuliaLang/julia#48611
41+ if VERSION >= v " 1.10.0-DEV.873"
4642
47- function get_world_generator (self, :: Type{Type{ft}} , :: Type{Type{tt}} ) where {ft, tt}
43+ # on 1.10 (JuliaLang/julia#48611) the generated function knows which world it was invoked in
44+
45+ function _generated_ex (world, source, ex)
46+ stub = Core. GeneratedFunctionStub (identity, Core. svec (:get_world , :ft , :tt ), Core. svec ())
47+ stub (world, source, ex)
48+ end
49+
50+ function get_world_generator (world:: UInt , source, self, ft:: Type , tt:: Type )
4851 @nospecialize
52+ @assert Core. Compiler. isType (ft) && Core. Compiler. isType (tt)
53+ ft = ft. parameters[1 ]
54+ tt = tt. parameters[1 ]
4955
5056 # look up the method
57+ method_error = :(throw (MethodError (ft, tt, $ world)))
58+ Base. isdispatchtuple (tt) || return _generated_ex (world, source, :(error (" $tt is not a dispatch tuple" )))
59+ sig = Tuple{ft, tt. parameters... }
60+ min_world = Ref {UInt} (typemin (UInt))
61+ max_world = Ref {UInt} (typemax (UInt))
62+ has_ambig = Ptr {Int32} (C_NULL ) # don't care about ambiguous results
63+ mthds = if VERSION >= v " 1.7.0-DEV.1297"
64+ Base. _methods_by_ftype (sig, #= mt=# nothing , #= lim=# - 1 ,
65+ world, #= ambig=# false ,
66+ min_world, max_world, has_ambig)
67+ # XXX : use the correct method table to support overlaying kernels
68+ else
69+ Base. _methods_by_ftype (sig, #= lim=# - 1 ,
70+ world, #= ambig=# false ,
71+ min_world, max_world, has_ambig)
72+ end
73+ mthds === nothing && return _generated_ex (world, source, method_error)
74+ length (mthds) == 1 || return _generated_ex (world, source, method_error)
75+
76+ # look up the method and code instance
77+ mtypes, msp, m = mthds[1 ]
78+ mi = ccall (:jl_specializations_get_linfo , Ref{MethodInstance}, (Any, Any, Any), m, mtypes, msp)
79+ ci = retrieve_code_info (mi, world):: CodeInfo
80+
81+ # prepare a new code info
82+ new_ci = copy (ci)
83+ empty! (new_ci. code)
84+ empty! (new_ci. codelocs)
85+ resize! (new_ci. linetable, 1 ) # see note below
86+ empty! (new_ci. ssaflags)
87+ new_ci. ssavaluetypes = 0
88+ new_ci. min_world = min_world[]
89+ new_ci. max_world = max_world[]
90+ new_ci. edges = MethodInstance[mi]
91+ # XXX : setting this edge does not give us proper method invalidation, see
92+ # JuliaLang/julia#34962 which demonstrates we also need to "call" the kernel.
93+ # invoking `code_llvm` also does the necessary codegen, as does calling the
94+ # underlying C methods -- which GPUCompiler does, so everything Just Works.
95+
96+ # prepare the slots
97+ new_ci. slotnames = Symbol[Symbol (" #self#" ), :ft , :tt ]
98+ new_ci. slotflags = UInt8[0x00 for i = 1 : 3 ]
99+
100+ # return the world
101+ push! (new_ci. code, ReturnNode (world))
102+ push! (new_ci. ssaflags, 0x00 ) # Julia's native compilation pipeline (and its verifier) expects `ssaflags` to be the same length as `code`
103+ push! (new_ci. codelocs, 1 ) # see note below
104+ new_ci. ssavaluetypes += 1
105+
106+ # NOTE: we keep the first entry of the original linetable, and use it for location info
107+ # on the call to check_cache. we can't not have a codeloc (using 0 causes
108+ # corruption of the back trace), and reusing the target function's info
109+ # has as advantage that we see the name of the kernel in the backtraces.
110+
111+ return new_ci
112+ end
113+
114+ @eval function get_world (ft, tt)
115+ $ (Expr (:meta , :generated_only ))
116+ $ (Expr (:meta , :generated , get_world_generator))
117+ end
118+
119+ else
120+
121+ # on older versions of Julia we fall back to looking up the current world. this may be wrong
122+ # when the generator is invoked in a different world (TODO : when does this happen?)
123+
124+ function get_world_generator (self, ft:: Type , tt:: Type )
125+ @nospecialize
126+ @assert Core. Compiler. isType (ft) && Core. Compiler. isType (tt)
127+ ft = ft. parameters[1 ]
128+ tt = tt. parameters[1 ]
129+
130+ # look up the method
131+ method_error = :(throw (MethodError (ft, tt)))
132+ Base. isdispatchtuple (tt) || return (:(error (" $tt is not a dispatch tuple" )))
51133 sig = Tuple{ft, tt. parameters... }
52134 min_world = Ref {UInt} (typemin (UInt))
53135 max_world = Ref {UInt} (typemax (UInt))
@@ -63,11 +145,7 @@ function get_world_generator(self, ::Type{Type{ft}}, ::Type{Type{tt}}) where {ft
63145 min_world, max_world, has_ambig)
64146 end
65147 # XXX : using world=-1 is wrong, but the current world isn't exposed to this generator
66-
67- # check the validity of the method matches
68- method_error = :(throw (MethodError (ft, tt)))
69148 mthds === nothing && return method_error
70- Base. isdispatchtuple (tt) || return (:(error (" $tt is not a dispatch tuple" )))
71149 length (mthds) == 1 || return method_error
72150
73151 # look up the method and code instance
127205 true )))
128206end
129207
208+ end
209+
130210const cache_lock = ReentrantLock ()
131211
132212"""
0 commit comments