Skip to content

Commit 52da96a

Browse files
committed
Have JIT execution take ownership of the LLVMContextRef
Also stop leaking the ExecutionEngine created for jit code by forcibly disposing of it after the JIT code has finished executing
1 parent 5bd50ca commit 52da96a

File tree

6 files changed

+83
-54
lines changed

6 files changed

+83
-54
lines changed

src/librustc/back/link.rs

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ pub mod jit {
9393
use back::link::llvm_err;
9494
use driver::session::Session;
9595
use lib::llvm::llvm;
96-
use lib::llvm::{ModuleRef, PassManagerRef};
96+
use lib::llvm::{ModuleRef, PassManagerRef, ContextRef};
9797
use metadata::cstore;
9898

9999
use core::libc::c_int;
@@ -113,6 +113,7 @@ pub mod jit {
113113

114114
pub fn exec(sess: Session,
115115
pm: PassManagerRef,
116+
c: ContextRef,
116117
m: ModuleRef,
117118
opt: c_int,
118119
stacks: bool) {
@@ -141,26 +142,43 @@ pub mod jit {
141142
});
142143
}
143144

144-
// The execute function will return a void pointer
145-
// to the _rust_main function. We can do closure
146-
// magic here to turn it straight into a callable rust
147-
// closure. It will also cleanup the memory manager
148-
// for us.
149-
150-
let entry = llvm::LLVMRustExecuteJIT(manager,
151-
pm, m, opt, stacks);
152-
153-
if ptr::is_null(entry) {
154-
llvm_err(sess, ~"Could not JIT");
155-
} else {
156-
let closure = Closure {
157-
code: entry,
158-
env: ptr::null()
159-
};
160-
let func: &fn() = cast::transmute(closure);
145+
// We custom-build a JIT execution engine via some rust wrappers
146+
// first. This wrappers takes ownership of the module passed in.
147+
let ee = llvm::LLVMRustBuildJIT(manager, pm, m, opt, stacks);
148+
if ptr::is_null(ee) {
149+
llvm::LLVMContextDispose(c);
150+
llvm_err(sess, ~"Could not create the JIT");
151+
}
161152

162-
func();
153+
// Next, we need to get a handle on the _rust_main function by
154+
// looking up it's corresponding ValueRef and then requesting that
155+
// the execution engine compiles the function.
156+
let fun = do str::as_c_str("_rust_main") |entry| {
157+
llvm::LLVMGetNamedFunction(m, entry)
158+
};
159+
if fun.is_null() {
160+
llvm::LLVMDisposeExecutionEngine(ee);
161+
llvm::LLVMContextDispose(c);
162+
llvm_err(sess, ~"Could not find _rust_main in the JIT");
163163
}
164+
165+
// Finally, once we have the pointer to the code, we can do some
166+
// closure magic here to turn it straight into a callable rust
167+
// closure
168+
let code = llvm::LLVMGetPointerToGlobal(ee, fun);
169+
assert!(!code.is_null());
170+
let closure = Closure {
171+
code: code,
172+
env: ptr::null()
173+
};
174+
let func: &fn() = cast::transmute(closure);
175+
func();
176+
177+
// Sadly, there currently is no interface to re-use this execution
178+
// engine, so it's disposed of here along with the context to
179+
// prevent leaks.
180+
llvm::LLVMDisposeExecutionEngine(ee);
181+
llvm::LLVMContextDispose(c);
164182
}
165183
}
166184
}
@@ -174,7 +192,7 @@ pub mod write {
174192
use driver::session::Session;
175193
use driver::session;
176194
use lib::llvm::llvm;
177-
use lib::llvm::{False, ModuleRef, mk_pass_manager, mk_target_data};
195+
use lib::llvm::{False, ContextRef, ModuleRef, mk_pass_manager, mk_target_data};
178196
use lib;
179197

180198
use core::libc::{c_int, c_uint};
@@ -190,6 +208,7 @@ pub mod write {
190208
}
191209

192210
pub fn run_passes(sess: Session,
211+
llcx: ContextRef,
193212
llmod: ModuleRef,
194213
output_type: output_type,
195214
output: &Path) {
@@ -287,7 +306,7 @@ pub mod write {
287306
// JIT execution takes ownership of the module,
288307
// so don't dispose and return.
289308

290-
jit::exec(sess, pm.llpm, llmod, CodeGenOptLevel, true);
309+
jit::exec(sess, pm.llpm, llcx, llmod, CodeGenOptLevel, true);
291310

292311
if sess.time_llvm_passes() {
293312
llvm::LLVMRustPrintPassTimings();
@@ -358,6 +377,7 @@ pub mod write {
358377
// Clean up and return
359378

360379
llvm::LLVMDisposeModule(llmod);
380+
llvm::LLVMContextDispose(llcx);
361381
if sess.time_llvm_passes() {
362382
llvm::LLVMRustPrintPassTimings();
363383
}
@@ -377,6 +397,7 @@ pub mod write {
377397
}
378398

379399
llvm::LLVMDisposeModule(llmod);
400+
llvm::LLVMContextDispose(llcx);
380401
if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
381402
}
382403
}

src/librustc/driver/driver.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ pub fn compile_rest(sess: Session,
236236

237237
let outputs = outputs.get();
238238

239-
let (llmod, link_meta) = {
239+
let (llcx, llmod, link_meta) = {
240240

241241
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
242242
region_map, rp_set, lang_items);
@@ -318,14 +318,14 @@ pub fn compile_rest(sess: Session,
318318
let obj_filename = outputs.obj_filename.with_filetype("s");
319319

320320
time(time_passes, ~"LLVM passes", ||
321-
link::write::run_passes(sess, llmod, output_type,
322-
&obj_filename));
321+
link::write::run_passes(sess, llcx, llmod, output_type,
322+
&obj_filename));
323323

324324
link::write::run_ndk(sess, &obj_filename, &outputs.obj_filename);
325325
} else {
326326
time(time_passes, ~"LLVM passes", ||
327-
link::write::run_passes(sess, llmod, sess.opts.output_type,
328-
&outputs.obj_filename));
327+
link::write::run_passes(sess, llcx, llmod, sess.opts.output_type,
328+
&outputs.obj_filename));
329329
}
330330

331331
let stop_after_codegen =

src/librustc/lib/llvm.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ pub enum BasicBlock_opaque {}
199199
pub type BasicBlockRef = *BasicBlock_opaque;
200200
pub enum Builder_opaque {}
201201
pub type BuilderRef = *Builder_opaque;
202+
pub enum ExecutionEngine_opaque {}
203+
pub type ExecutionEngineRef = *ExecutionEngine_opaque;
202204
pub enum MemoryBuffer_opaque {}
203205
pub type MemoryBufferRef = *MemoryBuffer_opaque;
204206
pub enum PassManager_opaque {}
@@ -215,7 +217,7 @@ pub enum SectionIterator_opaque {}
215217
pub type SectionIteratorRef = *SectionIterator_opaque;
216218

217219
pub mod llvm {
218-
use super::{AtomicBinOp, AtomicOrdering, BasicBlockRef};
220+
use super::{AtomicBinOp, AtomicOrdering, BasicBlockRef, ExecutionEngineRef};
219221
use super::{Bool, BuilderRef, ContextRef, MemoryBufferRef, ModuleRef};
220222
use super::{ObjectFileRef, Opcode, PassManagerRef, PassManagerBuilderRef};
221223
use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef};
@@ -355,6 +357,10 @@ pub mod llvm {
355357
pub unsafe fn LLVMGetPointerAddressSpace(PointerTy: TypeRef)
356358
-> c_uint;
357359
#[fast_ffi]
360+
pub unsafe fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef,
361+
V: ValueRef)
362+
-> *();
363+
#[fast_ffi]
358364
pub unsafe fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint;
359365

360366
/* Operations on other types */
@@ -995,6 +1001,8 @@ pub mod llvm {
9951001
Name: *c_char);
9961002
#[fast_ffi]
9971003
pub unsafe fn LLVMDisposeBuilder(Builder: BuilderRef);
1004+
#[fast_ffi]
1005+
pub unsafe fn LLVMDisposeExecutionEngine(EE: ExecutionEngineRef);
9981006

9991007
/* Metadata */
10001008
#[fast_ffi]
@@ -1785,11 +1793,11 @@ pub mod llvm {
17851793

17861794
/** Execute the JIT engine. */
17871795
#[fast_ffi]
1788-
pub unsafe fn LLVMRustExecuteJIT(MM: *(),
1796+
pub unsafe fn LLVMRustBuildJIT(MM: *(),
17891797
PM: PassManagerRef,
17901798
M: ModuleRef,
17911799
OptLevel: c_int,
1792-
EnableSegmentedStacks: bool) -> *();
1800+
EnableSegmentedStacks: bool) -> ExecutionEngineRef;
17931801

17941802
/** Parses the bitcode in the given memory buffer. */
17951803
#[fast_ffi]

src/librustc/middle/trans/base.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,7 +2984,7 @@ pub fn trans_crate(sess: session::Session,
29842984
tcx: ty::ctxt,
29852985
output: &Path,
29862986
emap2: resolve::ExportMap2,
2987-
maps: astencode::Maps) -> (ModuleRef, LinkMeta) {
2987+
maps: astencode::Maps) -> (ContextRef, ModuleRef, LinkMeta) {
29882988
29892989
let symbol_hasher = @mut hash::default_state();
29902990
let link_meta = link::build_link_meta(sess, crate, output, symbol_hasher);
@@ -3148,7 +3148,8 @@ pub fn trans_crate(sess: session::Session,
31483148
io::println(fmt!("%-7u %s", v, k));
31493149
}
31503150
}
3151-
return (llmod, link_meta);
3151+
unset_task_llcx();
3152+
return (llcx, llmod, link_meta);
31523153
}
31533154
}
31543155
@@ -3159,8 +3160,10 @@ pub fn task_llcx() -> ContextRef {
31593160
*opt.expect("task-local LLVMContextRef wasn't ever set!")
31603161
}
31613162

3162-
fn set_task_llcx(c: ContextRef) {
3163-
unsafe {
3164-
local_data::local_data_set(task_local_llcx_key, @c);
3165-
}
3163+
unsafe fn set_task_llcx(c: ContextRef) {
3164+
local_data::local_data_set(task_local_llcx_key, @c);
3165+
}
3166+
3167+
unsafe fn unset_task_llcx() {
3168+
local_data::local_data_pop(task_local_llcx_key);
31663169
}

src/rustllvm/RustWrapper.cpp

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "llvm/Transforms/IPO.h"
5151
#include "llvm-c/Core.h"
5252
#include "llvm-c/BitReader.h"
53+
#include "llvm-c/ExecutionEngine.h"
5354
#include "llvm-c/Object.h"
5455

5556
// Used by RustMCJITMemoryManager::getPointerToNamedFunction()
@@ -372,12 +373,12 @@ LLVMRustLoadCrate(void* mem, const char* crate) {
372373
return true;
373374
}
374375

375-
extern "C" void*
376-
LLVMRustExecuteJIT(void* mem,
377-
LLVMPassManagerRef PMR,
378-
LLVMModuleRef M,
379-
CodeGenOpt::Level OptLevel,
380-
bool EnableSegmentedStacks) {
376+
extern "C" LLVMExecutionEngineRef
377+
LLVMRustBuildJIT(void* mem,
378+
LLVMPassManagerRef PMR,
379+
LLVMModuleRef M,
380+
CodeGenOpt::Level OptLevel,
381+
bool EnableSegmentedStacks) {
381382

382383
InitializeNativeTarget();
383384
InitializeNativeTargetAsmPrinter();
@@ -414,21 +415,15 @@ LLVMRustExecuteJIT(void* mem,
414415

415416
if(!EE || Err != "") {
416417
LLVMRustError = Err.c_str();
417-
return 0;
418+
// The EngineBuilder only takes ownership of these two structures if the
419+
// create() call is successful, but here it wasn't successful.
420+
LLVMDisposeModule(M);
421+
delete MM;
422+
return NULL;
418423
}
419424

420425
MM->invalidateInstructionCache();
421-
Function* func = EE->FindFunctionNamed("_rust_main");
422-
423-
if(!func || Err != "") {
424-
LLVMRustError = Err.c_str();
425-
return 0;
426-
}
427-
428-
void* entry = EE->getPointerToFunction(func);
429-
assert(entry);
430-
431-
return entry;
426+
return wrap(EE);
432427
}
433428

434429
extern "C" bool

src/rustllvm/rustllvm.def.in

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ LLVMRustConstSmallInt
66
LLVMRustConstInt
77
LLVMRustLoadCrate
88
LLVMRustPrepareJIT
9-
LLVMRustExecuteJIT
9+
LLVMRustBuildJIT
1010
LLVMRustParseBitcode
1111
LLVMRustParseAssemblyFile
1212
LLVMRustPrintPassTimings
1313
LLVMRustStartMultithreading
1414
LLVMCreateObjectFile
1515
LLVMDisposeObjectFile
16+
LLVMDisposeExecutionEngine
1617
LLVMGetSections
1718
LLVMDisposeSectionIterator
1819
LLVMIsSectionIteratorAtEnd
@@ -356,6 +357,7 @@ LLVMGetParamParent
356357
LLVMGetParamTypes
357358
LLVMGetParams
358359
LLVMGetPointerAddressSpace
360+
LLVMGetPointerToGlobal
359361
LLVMGetPreviousBasicBlock
360362
LLVMGetPreviousFunction
361363
LLVMGetPreviousGlobal

0 commit comments

Comments
 (0)