about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-05-17 19:44:50 -0400
committerAlex Crichton <alex@alexcrichton.com>2013-06-10 13:17:04 -0700
commit5c5095d25e3652c434c8d4ec178e6844877e3c2d (patch)
treec43b05c69fa971a2be82bb62b7f814ddcc4aa1b6
parent779191cd4b8719e8efdf69fb6da93e2a8905ca1d (diff)
downloadrust-5c5095d25e3652c434c8d4ec178e6844877e3c2d.tar.gz
rust-5c5095d25e3652c434c8d4ec178e6844877e3c2d.zip
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
-rw-r--r--src/librustc/back/link.rs62
-rw-r--r--src/librustc/driver/driver.rs10
-rw-r--r--src/librustc/lib/llvm.rs14
-rw-r--r--src/librustc/middle/trans/base.rs23
-rw-r--r--src/librusti/rusti.rc8
-rw-r--r--src/rustllvm/RustWrapper.cpp30
-rw-r--r--src/rustllvm/rustllvm.def.in4
-rw-r--r--src/rustllvm/rustllvm.h1
8 files changed, 93 insertions, 59 deletions
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 496c1f88a6c..5375425b853 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -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;
@@ -126,6 +126,7 @@ pub mod jit {
 
     pub fn exec(sess: Session,
                 pm: PassManagerRef,
+                c: ContextRef,
                 m: ModuleRef,
                 opt: c_int,
                 stacks: bool) {
@@ -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);
         }
     }
 }
@@ -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;
@@ -208,6 +227,7 @@ pub mod write {
     }
 
     pub fn run_passes(sess: Session,
+                      llcx: ContextRef,
                       llmod: ModuleRef,
                       output_type: output_type,
                       output: &Path) {
@@ -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();
@@ -350,6 +370,7 @@ pub mod write {
                 // Clean up and return
 
                 llvm::LLVMDisposeModule(llmod);
+                llvm::LLVMContextDispose(llcx);
                 if sess.time_llvm_passes() {
                     llvm::LLVMRustPrintPassTimings();
                 }
@@ -368,6 +389,7 @@ pub mod write {
             }
 
             llvm::LLVMDisposeModule(llmod);
+            llvm::LLVMContextDispose(llcx);
             if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
         }
     }
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index ef5670da455..9a6f48a3257 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -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));
 
@@ -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 =
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index 0e9ea982d9f..b18c9e9b4c2 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -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 {}
@@ -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};
@@ -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 */
@@ -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]
@@ -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]
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 393155ddd7f..f0b57fe37ef 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -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);
@@ -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| {
@@ -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);
     }
 }
 
@@ -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);
 }
diff --git a/src/librusti/rusti.rc b/src/librusti/rusti.rc
index 9cb98dd8c2d..f8b39d9fbc7 100644
--- a/src/librusti/rusti.rc
+++ b/src/librusti/rusti.rc
@@ -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?\"); }"]);
     }
 }
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 17eb0f50b9b..30e01b53ab7 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -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();
@@ -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
diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in
index f8c68d798b9..f5397165781 100644
--- a/src/rustllvm/rustllvm.def.in
+++ b/src/rustllvm/rustllvm.def.in
@@ -6,13 +6,14 @@ LLVMRustConstSmallInt
 LLVMRustConstInt
 LLVMRustLoadCrate
 LLVMRustPrepareJIT
-LLVMRustExecuteJIT
+LLVMRustBuildJIT
 LLVMRustParseBitcode
 LLVMRustParseAssemblyFile
 LLVMRustPrintPassTimings
 LLVMRustStartMultithreading
 LLVMCreateObjectFile
 LLVMDisposeObjectFile
+LLVMDisposeExecutionEngine
 LLVMGetSections
 LLVMDisposeSectionIterator
 LLVMIsSectionIteratorAtEnd
@@ -356,6 +357,7 @@ LLVMGetParamParent
 LLVMGetParamTypes
 LLVMGetParams
 LLVMGetPointerAddressSpace
+LLVMGetPointerToGlobal
 LLVMGetPreviousBasicBlock
 LLVMGetPreviousFunction
 LLVMGetPreviousGlobal
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index 1c8842f7b4a..394146eea20 100644
--- a/src/rustllvm/rustllvm.h
+++ b/src/rustllvm/rustllvm.h
@@ -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()