Skip to content

Commit 5d25c12

Browse files
authored
Merge pull request #62 from SciML/myb/robustness
The body might be wrongly garbage collected when we drop the body
2 parents 9a7e9ed + 0a82fbb commit 5d25c12

File tree

2 files changed

+23
-24
lines changed

2 files changed

+23
-24
lines changed

src/RuntimeGeneratedFunctions.jl

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,18 @@ struct RuntimeGeneratedFunction{argnames, cache_tag, context_tag, id, B} <: Func
6666

6767
# For internal use in deserialize() - doesen't check whether the body is in the cache!
6868
function RuntimeGeneratedFunction{argnames, cache_tag, context_tag, id}(body) where {
69-
argnames,
70-
cache_tag,
71-
context_tag,
72-
id,
73-
}
69+
argnames,
70+
cache_tag,
71+
context_tag,
72+
id
73+
}
7474
new{argnames, cache_tag, context_tag, id, typeof(body)}(body)
7575
end
7676
end
7777

78-
drop_expr(::RuntimeGeneratedFunction{A, C1, C2, ID}) where {A, C1, C2, ID} = RuntimeGeneratedFunction{A, C1, C2, ID}(nothing)
78+
function drop_expr(::RuntimeGeneratedFunction{A, C1, C2, ID}) where {A, C1, C2, ID}
79+
RuntimeGeneratedFunction{A, C1, C2, ID}(nothing)
80+
end
7981

8082
function _check_rgf_initialized(mods...)
8183
for mod in mods
@@ -172,24 +174,19 @@ function _cache_body(cache_tag, id, body)
172174
# canonical one rather than `body`. This ensures the lifetime of the
173175
# body in the cache will always cover the lifetime of the parent
174176
# `RuntimeGeneratedFunction`s when they share the same `id`.
175-
#
176-
# Tricky case #2: Unless we hold a separate reference to
177-
# `cache[id].value`, the GC can collect it (causing it to become
178-
# `nothing`). So root it in a local variable first.
179-
#
180-
cached_body = haskey(cache, id) ? cache[id].value : nothing
177+
cached_body = haskey(cache, id) ? cache[id] : nothing
181178
cached_body = cached_body !== nothing ? cached_body : body
182-
# Use a WeakRef to allow `body` to be garbage collected. (After GC, the
183-
# cache will still contain an empty entry with key `id`.)
184-
cache[id] = WeakRef(cached_body)
179+
# We cannot use WeakRef because we might drop body to make RGF GPU
180+
# compatible.
181+
cache[id] = cached_body
185182
return cached_body
186183
end
187184
end
188185

189186
function _lookup_body(cache_tag, id)
190187
lock(_cache_lock) do
191188
cache = getfield(parentmodule(cache_tag), _cachename)
192-
cache[id].value
189+
cache[id]
193190
end
194191
end
195192

@@ -300,13 +297,14 @@ end
300297
# We write an explicit deserialize() here to trigger caching of the body on a
301298
# remote node when using Serialialization.jl (in Distributed.jl and elsewhere)
302299
function Serialization.deserialize(s::AbstractSerializer,
303-
::Type{<:RuntimeGeneratedFunction{argnames, cache_tag,
304-
context_tag, id}}) where {
305-
argnames,
306-
cache_tag,
307-
context_tag,
308-
id
309-
}
300+
::Type{
301+
<:RuntimeGeneratedFunction{argnames, cache_tag,
302+
context_tag, id}}) where {
303+
argnames,
304+
cache_tag,
305+
context_tag,
306+
id
307+
}
310308
body = deserialize(s)
311309
cached_body = _cache_body(cache_tag, id, body)
312310
RuntimeGeneratedFunction{argnames, cache_tag, context_tag, id}(cached_body)

test/runtests.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ end
164164

165165
# Serialization
166166

167-
buf = IOBuffer(read(`$(Base.julia_cmd()) "serialize_rgf.jl"`))
167+
proj = dirname(Base.active_project())
168+
buf = IOBuffer(read(`$(Base.julia_cmd()) --startup-file=no --project=$proj "serialize_rgf.jl"`))
168169
deserialized_f = deserialize(buf)
169170
@test deserialized_f(11) == "Hi from a separate process. x=11"

0 commit comments

Comments
 (0)