Skip to content

Commit

Permalink
Have JIT execution take ownership of the LLVMContextRef
Browse files Browse the repository at this point in the history
Also stop leaking the ExecutionEngine created for jit code by forcibly disposing
of it after the JIT code has finished executing
  • Loading branch information
alexcrichton committed Jun 10, 2013
1 parent 779191c commit 5c5095d
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 59 deletions.
62 changes: 42 additions & 20 deletions src/librustc/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub mod jit {
use back::link::llvm_err;
use driver::session::Session;
use lib::llvm::llvm;
use lib::llvm::{ModuleRef, PassManagerRef};
use lib::llvm::{ModuleRef, PassManagerRef, ContextRef};
use metadata::cstore;

use core::cast;
Expand All @@ -126,6 +126,7 @@ pub mod jit {

pub fn exec(sess: Session,
pm: PassManagerRef,
c: ContextRef,
m: ModuleRef,
opt: c_int,
stacks: bool) {
Expand Down Expand Up @@ -154,26 +155,43 @@ pub mod jit {
});
}

// The execute function will return a void pointer
// to the _rust_main function. We can do closure
// magic here to turn it straight into a callable rust
// closure. It will also cleanup the memory manager
// for us.

let entry = llvm::LLVMRustExecuteJIT(manager,
pm, m, opt, stacks);

if ptr::is_null(entry) {
llvm_err(sess, ~"Could not JIT");
} else {
let closure = Closure {
code: entry,
env: ptr::null()
};
let func: &fn() = cast::transmute(closure);
// We custom-build a JIT execution engine via some rust wrappers
// first. This wrappers takes ownership of the module passed in.
let ee = llvm::LLVMRustBuildJIT(manager, pm, m, opt, stacks);
if ee.is_null() {
llvm::LLVMContextDispose(c);
llvm_err(sess, ~"Could not create the JIT");
}

func();
// Next, we need to get a handle on the _rust_main function by
// looking up it's corresponding ValueRef and then requesting that
// the execution engine compiles the function.
let fun = do str::as_c_str("_rust_main") |entry| {
llvm::LLVMGetNamedFunction(m, entry)
};
if fun.is_null() {
llvm::LLVMDisposeExecutionEngine(ee);
llvm::LLVMContextDispose(c);
llvm_err(sess, ~"Could not find _rust_main in the JIT");
}

// Finally, once we have the pointer to the code, we can do some
// closure magic here to turn it straight into a callable rust
// closure
let code = llvm::LLVMGetPointerToGlobal(ee, fun);
assert!(!code.is_null());
let closure = Closure {
code: code,
env: ptr::null()
};
let func: &fn() = cast::transmute(closure);
func();

// Sadly, there currently is no interface to re-use this execution
// engine, so it's disposed of here along with the context to
// prevent leaks.
llvm::LLVMDisposeExecutionEngine(ee);
llvm::LLVMContextDispose(c);
}
}
}
Expand All @@ -190,6 +208,7 @@ pub mod write {
use driver::session;
use lib::llvm::llvm;
use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
use lib::llvm::{False, ContextRef};
use lib;

use back::passes;
Expand All @@ -208,6 +227,7 @@ pub mod write {
}

pub fn run_passes(sess: Session,
llcx: ContextRef,
llmod: ModuleRef,
output_type: output_type,
output: &Path) {
Expand Down Expand Up @@ -282,7 +302,7 @@ pub mod write {
// JIT execution takes ownership of the module,
// so don't dispose and return.

jit::exec(sess, pm.llpm, llmod, CodeGenOptLevel, true);
jit::exec(sess, pm.llpm, llcx, llmod, CodeGenOptLevel, true);

if sess.time_llvm_passes() {
llvm::LLVMRustPrintPassTimings();
Expand Down Expand Up @@ -350,6 +370,7 @@ pub mod write {
// Clean up and return

llvm::LLVMDisposeModule(llmod);
llvm::LLVMContextDispose(llcx);
if sess.time_llvm_passes() {
llvm::LLVMRustPrintPassTimings();
}
Expand All @@ -368,6 +389,7 @@ pub mod write {
}

llvm::LLVMDisposeModule(llmod);
llvm::LLVMContextDispose(llcx);
if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ pub fn compile_rest(sess: Session,

let mut crate = crate_opt.unwrap();

let (llmod, link_meta) = {
let (llcx, llmod, link_meta) = {
crate = time(time_passes, ~"intrinsic injection", ||
front::intrinsic_inject::inject_intrinsic(sess, crate));

Expand Down Expand Up @@ -340,14 +340,14 @@ pub fn compile_rest(sess: Session,
let obj_filename = outputs.obj_filename.with_filetype("s");

time(time_passes, ~"LLVM passes", ||
link::write::run_passes(sess, llmod, output_type,
&obj_filename));
link::write::run_passes(sess, llcx, llmod, output_type,
&obj_filename));

link::write::run_ndk(sess, &obj_filename, &outputs.obj_filename);
} else {
time(time_passes, ~"LLVM passes", ||
link::write::run_passes(sess, llmod, sess.opts.output_type,
&outputs.obj_filename));
link::write::run_passes(sess, llcx, llmod, sess.opts.output_type,
&outputs.obj_filename));
}

let stop_after_codegen =
Expand Down
14 changes: 11 additions & 3 deletions src/librustc/lib/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ pub enum BasicBlock_opaque {}
pub type BasicBlockRef = *BasicBlock_opaque;
pub enum Builder_opaque {}
pub type BuilderRef = *Builder_opaque;
pub enum ExecutionEngine_opaque {}
pub type ExecutionEngineRef = *ExecutionEngine_opaque;
pub enum MemoryBuffer_opaque {}
pub type MemoryBufferRef = *MemoryBuffer_opaque;
pub enum PassManager_opaque {}
Expand All @@ -223,7 +225,7 @@ pub enum Pass_opaque {}
pub type PassRef = *Pass_opaque;

pub mod llvm {
use super::{AtomicBinOp, AtomicOrdering, BasicBlockRef};
use super::{AtomicBinOp, AtomicOrdering, BasicBlockRef, ExecutionEngineRef};
use super::{Bool, BuilderRef, ContextRef, MemoryBufferRef, ModuleRef};
use super::{ObjectFileRef, Opcode, PassManagerRef, PassManagerBuilderRef};
use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef};
Expand Down Expand Up @@ -363,6 +365,10 @@ pub mod llvm {
pub unsafe fn LLVMGetPointerAddressSpace(PointerTy: TypeRef)
-> c_uint;
#[fast_ffi]
pub unsafe fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef,
V: ValueRef)
-> *();
#[fast_ffi]
pub unsafe fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint;

/* Operations on other types */
Expand Down Expand Up @@ -1003,6 +1009,8 @@ pub mod llvm {
Name: *c_char);
#[fast_ffi]
pub unsafe fn LLVMDisposeBuilder(Builder: BuilderRef);
#[fast_ffi]
pub unsafe fn LLVMDisposeExecutionEngine(EE: ExecutionEngineRef);

/* Metadata */
#[fast_ffi]
Expand Down Expand Up @@ -1819,11 +1827,11 @@ pub mod llvm {

/** Execute the JIT engine. */
#[fast_ffi]
pub unsafe fn LLVMRustExecuteJIT(MM: *(),
pub unsafe fn LLVMRustBuildJIT(MM: *(),
PM: PassManagerRef,
M: ModuleRef,
OptLevel: c_int,
EnableSegmentedStacks: bool) -> *();
EnableSegmentedStacks: bool) -> ExecutionEngineRef;

/** Parses the bitcode in the given memory buffer. */
#[fast_ffi]
Expand Down
23 changes: 14 additions & 9 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3023,7 +3023,7 @@ pub fn trans_crate(sess: session::Session,
tcx: ty::ctxt,
output: &Path,
emap2: resolve::ExportMap2,
maps: astencode::Maps) -> (ModuleRef, LinkMeta) {
maps: astencode::Maps) -> (ContextRef, ModuleRef, LinkMeta) {
let symbol_hasher = @mut hash::default_state();
let link_meta = link::build_link_meta(sess, crate, output, symbol_hasher);
Expand All @@ -3045,9 +3045,11 @@ pub fn trans_crate(sess: session::Session,
let llmod_id = link_meta.name.to_owned() + ".rc";
unsafe {
if !llvm::LLVMRustStartMultithreading() {
sess.bug("couldn't enable multi-threaded LLVM");
}
// FIXME(#6511): get LLVM building with --enable-threads so this
// function can be called
// if !llvm::LLVMRustStartMultithreading() {
// sess.bug("couldn't enable multi-threaded LLVM");
// }
let llcx = llvm::LLVMContextCreate();
set_task_llcx(llcx);
let llmod = str::as_c_str(llmod_id, |buf| {
Expand Down Expand Up @@ -3187,7 +3189,8 @@ pub fn trans_crate(sess: session::Session,
io::println(fmt!("%-7u %s", v, k));
}
}
return (llmod, link_meta);
unset_task_llcx();
return (llcx, llmod, link_meta);
}
}
Expand All @@ -3198,8 +3201,10 @@ pub fn task_llcx() -> ContextRef {
*opt.expect("task-local LLVMContextRef wasn't ever set!")
}

fn set_task_llcx(c: ContextRef) {
unsafe {
local_data::local_data_set(task_local_llcx_key, @c);
}
unsafe fn set_task_llcx(c: ContextRef) {
local_data::local_data_set(task_local_llcx_key, @c);
}

unsafe fn unset_task_llcx() {
local_data::local_data_pop(task_local_llcx_key);
}
8 changes: 5 additions & 3 deletions src/librusti/rusti.rc
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,10 @@ mod tests {
debug!("regression test for #5784");
run_cmds(["let a = 1;"]);

debug!("regression test for #5803");
run_cmds(["spawn( || println(\"Please don't segfault\") );",
"do spawn { println(\"Please?\"); }"]);
// XXX: can't spawn new tasks because the JIT code is cleaned up
// after the main function is done.
// debug!("regression test for #5803");
// run_cmds(["spawn( || println(\"Please don't segfault\") );",
// "do spawn { println(\"Please?\"); }"]);
}
}
30 changes: 12 additions & 18 deletions src/rustllvm/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,12 @@ LLVMRustLoadCrate(void* mem, const char* crate) {
return true;
}

extern "C" void*
LLVMRustExecuteJIT(void* mem,
LLVMPassManagerRef PMR,
LLVMModuleRef M,
CodeGenOpt::Level OptLevel,
bool EnableSegmentedStacks) {
extern "C" LLVMExecutionEngineRef
LLVMRustBuildJIT(void* mem,
LLVMPassManagerRef PMR,
LLVMModuleRef M,
CodeGenOpt::Level OptLevel,
bool EnableSegmentedStacks) {

InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
Expand Down Expand Up @@ -371,21 +371,15 @@ LLVMRustExecuteJIT(void* mem,

if(!EE || Err != "") {
LLVMRustError = Err.c_str();
return 0;
// The EngineBuilder only takes ownership of these two structures if the
// create() call is successful, but here it wasn't successful.
LLVMDisposeModule(M);
delete MM;
return NULL;
}

MM->invalidateInstructionCache();
Function* func = EE->FindFunctionNamed("_rust_main");

if(!func || Err != "") {
LLVMRustError = Err.c_str();
return 0;
}

void* entry = EE->getPointerToFunction(func);
assert(entry);

return entry;
return wrap(EE);
}

extern "C" bool
Expand Down
4 changes: 3 additions & 1 deletion src/rustllvm/rustllvm.def.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ LLVMRustConstSmallInt
LLVMRustConstInt
LLVMRustLoadCrate
LLVMRustPrepareJIT
LLVMRustExecuteJIT
LLVMRustBuildJIT
LLVMRustParseBitcode
LLVMRustParseAssemblyFile
LLVMRustPrintPassTimings
LLVMRustStartMultithreading
LLVMCreateObjectFile
LLVMDisposeObjectFile
LLVMDisposeExecutionEngine
LLVMGetSections
LLVMDisposeSectionIterator
LLVMIsSectionIteratorAtEnd
Expand Down Expand Up @@ -356,6 +357,7 @@ LLVMGetParamParent
LLVMGetParamTypes
LLVMGetParams
LLVMGetPointerAddressSpace
LLVMGetPointerToGlobal
LLVMGetPreviousBasicBlock
LLVMGetPreviousFunction
LLVMGetPreviousGlobal
Expand Down
1 change: 1 addition & 0 deletions src/rustllvm/rustllvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "llvm/Transforms/Vectorize.h"
#include "llvm-c/Core.h"
#include "llvm-c/BitReader.h"
#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Object.h"

// Used by RustMCJITMemoryManager::getPointerToNamedFunction()
Expand Down

9 comments on commit 5c5095d

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from graydon
at alexcrichton@5c5095d

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging alexcrichton/rust/issue-6511-threadsafe-llvm = 5c5095d into auto

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alexcrichton/rust/issue-6511-threadsafe-llvm = 5c5095d merged ok, testing candidate = 443a48e

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from graydon
at alexcrichton@5c5095d

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging alexcrichton/rust/issue-6511-threadsafe-llvm = 5c5095d into auto

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alexcrichton/rust/issue-6511-threadsafe-llvm = 5c5095d merged ok, testing candidate = da9172a

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors
Copy link
Contributor

@bors bors commented on 5c5095d Jun 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding incoming to auto = da9172a

Please sign in to comment.