@@ -38,16 +38,98 @@ Normally, you shouldn't have to use this function, as it's used by `FunctionSpec
38
38
"""
39
39
get_world
40
40
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"
46
42
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 )
48
51
@nospecialize
52
+ @assert Core. Compiler. isType (ft) && Core. Compiler. isType (tt)
53
+ ft = ft. parameters[1 ]
54
+ tt = tt. parameters[1 ]
49
55
50
56
# 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" )))
51
133
sig = Tuple{ft, tt. parameters... }
52
134
min_world = Ref {UInt} (typemin (UInt))
53
135
max_world = Ref {UInt} (typemax (UInt))
@@ -63,11 +145,7 @@ function get_world_generator(self, ::Type{Type{ft}}, ::Type{Type{tt}}) where {ft
63
145
min_world, max_world, has_ambig)
64
146
end
65
147
# 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)))
69
148
mthds === nothing && return method_error
70
- Base. isdispatchtuple (tt) || return (:(error (" $tt is not a dispatch tuple" )))
71
149
length (mthds) == 1 || return method_error
72
150
73
151
# look up the method and code instance
127
205
true )))
128
206
end
129
207
208
+ end
209
+
130
210
const cache_lock = ReentrantLock ()
131
211
132
212
"""
0 commit comments