Skip to content

Commit 709ed69

Browse files
committed
Keep track of module validity by wiping the reference if it isn't.
Fixes #192
1 parent b40d63f commit 709ed69

File tree

4 files changed

+26
-9
lines changed

4 files changed

+26
-9
lines changed

src/core/module.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ export dispose,
99

1010
# forward definition of Module in src/core/value/constant.jl
1111

12-
Base.unsafe_convert(::Type{API.LLVMModuleRef}, mod::Module) = mod.ref
12+
function Base.unsafe_convert(::Type{API.LLVMModuleRef}, mod::Module)
13+
# modules can get destroyed, so be sure to check for validity
14+
mod.ref == C_NULL && throw(UndefRefError())
15+
mod.ref
16+
end
17+
18+
Base.:(==)(x::Module, y::Module) = (x.ref === y.ref)
1319

1420
# forward declarations
1521
@checked struct DataLayout

src/core/value/constant.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ UndefValue(typ::LLVMType) = UndefValue(API.LLVMGetUndef(typ))
1818
abstract type Constant <: User end
1919

2020
# forward declarations
21-
@checked struct Module
21+
@checked mutable struct Module
2222
ref::API.LLVMModuleRef
2323
end
2424
abstract type Instruction <: User end

src/execution.jl

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export ExecutionEngine, Interpreter, JIT,
5555

5656
@checked struct ExecutionEngine
5757
ref::API.LLVMExecutionEngineRef
58+
mods::Set{Module}
5859
end
5960

6061
Base.unsafe_convert(::Type{API.LLVMExecutionEngineRef}, engine::ExecutionEngine) = engine.ref
@@ -64,29 +65,29 @@ function ExecutionEngine(mod::Module)
6465
out_ref = Ref{API.LLVMExecutionEngineRef}()
6566
out_error = Ref{Cstring}()
6667
status = convert(Core.Bool, API.LLVMCreateExecutionEngineForModule(out_ref, mod,
67-
out_error))
68+
out_error))
6869

6970
if status
7071
error = unsafe_message(out_error[])
7172
throw(LLVMException(error))
7273
end
7374

74-
return ExecutionEngine(out_ref[])
75+
return ExecutionEngine(out_ref[], Set([mod]))
7576
end
7677
function Interpreter(mod::Module)
7778
API.LLVMLinkInInterpreter()
7879

7980
out_ref = Ref{API.LLVMExecutionEngineRef}()
8081
out_error = Ref{Cstring}()
8182
status = convert(Core.Bool, API.LLVMCreateInterpreterForModule(out_ref, mod,
82-
out_error))
83+
out_error))
8384

8485
if status
8586
error = unsafe_message(out_error[])
8687
throw(LLVMException(error))
8788
end
8889

89-
return ExecutionEngine(out_ref[])
90+
return ExecutionEngine(out_ref[], Set([mod]))
9091
end
9192
function JIT(mod::Module, optlevel::API.LLVMCodeGenOptLevel=API.LLVMCodeGenLevelDefault)
9293
API.LLVMLinkInMCJIT()
@@ -101,10 +102,15 @@ function JIT(mod::Module, optlevel::API.LLVMCodeGenOptLevel=API.LLVMCodeGenLevel
101102
throw(LLVMException(error))
102103
end
103104

104-
return ExecutionEngine(out_ref[])
105+
return ExecutionEngine(out_ref[], Set([mod]))
105106
end
106107

107-
dispose(engine::ExecutionEngine) = API.LLVMDisposeExecutionEngine(engine)
108+
function dispose(engine::ExecutionEngine)
109+
for mod in engine.mods
110+
mod.ref = C_NULL
111+
end
112+
API.LLVMDisposeExecutionEngine(engine)
113+
end
108114

109115
for x in [:ExecutionEngine, :Interpreter, :JIT]
110116
@eval function $x(f::Core.Function, args...)
@@ -123,7 +129,9 @@ Base.push!(engine::ExecutionEngine, mod::Module) = API.LLVMAddModule(engine.ref,
123129
function Base.delete!(engine::ExecutionEngine, mod::Module)
124130
out_ref = Ref{API.LLVMModuleRef}()
125131
API.LLVMRemoveModule(engine.ref, mod.ref, out_ref, Ref{Cstring}()) # out string is not used
126-
return Module(out_ref[])
132+
@assert mod == Module(out_ref[])
133+
delete!(engine.mods, mod)
134+
return
127135
end
128136

129137
Base.run(engine::ExecutionEngine, f::Function, args::Vector{GenericValue}=GenericValue[]) =

test/execution.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ Context() do ctx
144144
@test convert(Int, res) == 3
145145
dispose(res)
146146
end
147+
@test_throws UndefRefError show(mod)
147148
end
148149

149150
dispose.(args)
@@ -155,6 +156,7 @@ Context() do ctx
155156
@test convert(Int, res) == 42
156157
dispose(res)
157158
end
159+
@test_throws UndefRefError show(mod)
158160
end
159161

160162
let mod = emit_retint(ctx, 42)
@@ -164,6 +166,7 @@ Context() do ctx
164166
@test convert(Int, res) == 42
165167
dispose(res)
166168
end
169+
@test_throws UndefRefError show(mod)
167170
end
168171

169172
args1 =

0 commit comments

Comments
 (0)