Skip to content

Commit

Permalink
Revert "Use normal RuntimeGeneratedFunction constructor rather than m…
Browse files Browse the repository at this point in the history
…acro"

This reverts commit ff1fd50.

As discussed in #21, it's error prone for the user to control the module
used for the RGF cache. So it's easiest to keep the constructor macro.
  • Loading branch information
c42f committed Jan 4, 2021
1 parent cee1c8a commit 4e5de90
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 38 deletions.
58 changes: 31 additions & 27 deletions src/RuntimeGeneratedFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,31 @@ module RuntimeGeneratedFunctions

using ExprTools, Serialization, SHA

export RuntimeGeneratedFunction, @RuntimeGeneratedFunction
export @RuntimeGeneratedFunction


"""
RuntimeGeneratedFunction(module, function_expression)
RuntimeGeneratedFunction
Construct a function from `function_expression` in the scope of `module` which
can be called immediately without world age problems. Somewhat like using
`eval(function_expression)` and then calling the resulting function. The
differences are:
This type should be constructed via the macro @RuntimeGeneratedFunction.
"""
struct RuntimeGeneratedFunction{argnames,moduletag,id} <: Function
body::Expr
function RuntimeGeneratedFunction(moduletag, ex)
def = splitdef(ex)
args, body = normalize_args(def[:args]), def[:body]
id = expr_to_id(body)
cached_body = _cache_body(moduletag, id, body)
new{Tuple(args),moduletag,id}(cached_body)
end
end

"""
@RuntimeGeneratedFunction(function_expression)
Construct a function from `function_expression` which can be called immediately
without world age problems. Somewhat like using `eval(function_expression)` and
then calling the resulting function. The differences are:
* The result can be called immediately (immune to world age errors)
* The result is not a named generic function, and doesn't participate in
Expand All @@ -26,32 +41,21 @@ RuntimeGeneratedFunctions.init(@__MODULE__) # Required at module top-level
function foo()
expression = :((x,y)->x+y+1) # May be generated dynamically
f = RuntimeGeneratedFunction(@__MODULE__, expression)
f = @RuntimeGeneratedFunction(expression)
f(1,2) # May be called immediately
end
```
"""
struct RuntimeGeneratedFunction{argnames,moduletag,id} <: Function
body::Expr
function RuntimeGeneratedFunction(mod::Module, ex)
if !isdefined(mod, _tagname)
macro RuntimeGeneratedFunction(ex)
quote
if !($(esc(:(@isdefined($_tagname)))))
error("""You must use `RuntimeGeneratedFunctions.init(@__MODULE__)` at module
top level before using runtime generated functions""")
end
moduletag = getfield(mod, _tagname)
def = splitdef(ex)
args, body = normalize_args(def[:args]), def[:body]
id = expr_to_id(body)
cached_body = _cache_body(moduletag, id, body)
new{Tuple(args),moduletag,id}(cached_body)
end
end


macro RuntimeGeneratedFunction(ex)
Base.depwarn("`@RuntimeGeneratedFunction(ex)` is deprecated, use `RuntimeGeneratedFunction(@__MODULE__, ex)` instead.", :RuntimeGeneratedFunction)
quote
RuntimeGeneratedFunction(@__MODULE__, $(esc(ex)))
RuntimeGeneratedFunction(
$(esc(_tagname)),
$(esc(ex))
)
end
end

Expand All @@ -64,7 +68,7 @@ end
(f::RuntimeGeneratedFunction)(args::Vararg{Any,N}) where N = generated_callfunc(f, args...)

# We'll generate a method of this function in every module which wants to use
# RuntimeGeneratedFunction
# @RuntimeGeneratedFunction
function generated_callfunc end

function generated_callfunc_body(argnames, moduletag, id, __args)
Expand Down Expand Up @@ -134,7 +138,7 @@ end
RuntimeGeneratedFunctions.init(mod)
Use this at top level to set up your module `mod` before using
`RuntimeGeneratedFunction(mod, ...)`.
`@RuntimeGeneratedFunction`.
"""
function init(mod)
lock(_cache_lock) do
Expand Down
2 changes: 1 addition & 1 deletion test/precomp/RGFPrecompTest.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ module RGFPrecompTest
using RuntimeGeneratedFunctions
RuntimeGeneratedFunctions.init(@__MODULE__)

f = RuntimeGeneratedFunction(@__MODULE__, :((x,y)->x+y))
f = @RuntimeGeneratedFunction(:((x,y)->x+y))
end
20 changes: 10 additions & 10 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ ex3 = :(function (_du::T,_u::Vector{E},_p::P,_t::Any) where {T<:Vector,E,P}
nothing
end)

f1 = RuntimeGeneratedFunction(@__MODULE__, ex1)
f2 = RuntimeGeneratedFunction(@__MODULE__, ex2)
f3 = RuntimeGeneratedFunction(@__MODULE__, ex3)
f1 = @RuntimeGeneratedFunction(ex1)
f2 = @RuntimeGeneratedFunction(ex2)
f3 = @RuntimeGeneratedFunction(ex3)

@test f1 isa Function

Expand Down Expand Up @@ -62,7 +62,7 @@ function no_worldage()
@inbounds _du[2] = _u[2]
nothing
end)
f1 = RuntimeGeneratedFunction(@__MODULE__, ex)
f1 = @RuntimeGeneratedFunction(ex)
du = rand(2)
u = rand(2)
p = nothing
Expand All @@ -72,7 +72,7 @@ end
@test no_worldage() === nothing

# Test show()
@test sprint(show, RuntimeGeneratedFunction(@__MODULE__, Base.remove_linenums!(:((x,y)->x+y+1)))) ==
@test sprint(show, @RuntimeGeneratedFunction(Base.remove_linenums!(:((x,y)->x+y+1)))) ==
"""
RuntimeGeneratedFunction(#=in $(@__MODULE__)=#, :((x, y)->begin
x + y + 1
Expand All @@ -86,9 +86,9 @@ using RGFPrecompTest

# Test that RuntimeGeneratedFunction with identical body expressions (but
# allocated separately) don't clobber each other when one is GC'd.
f_gc = RuntimeGeneratedFunction(@__MODULE__, Base.remove_linenums!(:((x,y)->x+y+100001)))
f_gc = @RuntimeGeneratedFunction(Base.remove_linenums!(:((x,y)->x+y+100001)))
let
RuntimeGeneratedFunction(@__MODULE__, Base.remove_linenums!(:((x,y)->x+y+100001)))
@RuntimeGeneratedFunction(Base.remove_linenums!(:((x,y)->x+y+100001)))
end
GC.gc()
@test f_gc(1,-1) == 100001
Expand All @@ -100,7 +100,7 @@ for k=1:4
t = Threads.@spawn begin
r = Bool[]
for i=1:100
f = RuntimeGeneratedFunction(@__MODULE__, Base.remove_linenums!(:((x,y)->x+y+$i*$k)))
f = @RuntimeGeneratedFunction(Base.remove_linenums!(:((x,y)->x+y+$i*$k)))
x = 1; y = 2;
push!(r, f(x,y) == x + y + i*k)
end
Expand All @@ -119,13 +119,13 @@ module GlobalsTest
RuntimeGeneratedFunctions.init(@__MODULE__)

y = 40
f = RuntimeGeneratedFunction(@__MODULE__, :(x->x+y))
f = @RuntimeGeneratedFunction(:(x->x+y))
end

@test GlobalsTest.f(2) == 42

@test_throws ErrorException @eval(module NotInitTest
using RuntimeGeneratedFunctions
# RuntimeGeneratedFunctions.init(@__MODULE__) # <-- missing
f = RuntimeGeneratedFunction(@__MODULE__, :(x->x+y))
f = @RuntimeGeneratedFunction(:(x->x+y))
end)

0 comments on commit 4e5de90

Please sign in to comment.