about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/back/link.rs106
-rw-r--r--src/librustc/driver/driver.rs10
-rw-r--r--src/librustc/lib/llvm.rs87
-rw-r--r--src/librustc/middle/trans/base.rs51
-rw-r--r--src/librustc/middle/trans/build.rs3
-rw-r--r--src/librustc/middle/trans/cabi_mips.rs3
-rw-r--r--src/librustc/middle/trans/closure.rs4
-rw-r--r--src/librustc/middle/trans/common.rs73
-rw-r--r--src/librustc/middle/trans/debuginfo.rs9
-rw-r--r--src/librustc/middle/trans/type_of.rs2
-rw-r--r--src/librusti/rusti.rc14
-rw-r--r--src/librustpkg/tests.rs16
-rw-r--r--src/rustllvm/RustWrapper.cpp69
-rw-r--r--src/rustllvm/rustllvm.def.in7
-rw-r--r--src/rustllvm/rustllvm.h1
15 files changed, 241 insertions, 214 deletions
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 7760982130f..c22a432ad78 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -101,34 +101,21 @@ 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, ContextRef};
     use metadata::cstore;
 
     use core::cast;
-    use core::libc::c_int;
     use core::ptr;
     use core::str;
-
-    pub mod rusti {
-        #[nolink]
-        #[abi = "rust-intrinsic"]
-        pub extern "rust-intrinsic" {
-            pub fn morestack_addr() -> *();
-        }
-    }
-
-    pub struct Closure {
-        code: *(),
-        env: *(),
-    }
+    use core::sys;
+    use core::unstable::intrinsics;
 
     pub fn exec(sess: Session,
-                pm: PassManagerRef,
+                c: ContextRef,
                 m: ModuleRef,
-                opt: c_int,
                 stacks: bool) {
         unsafe {
-            let manager = llvm::LLVMRustPrepareJIT(rusti::morestack_addr());
+            let manager = llvm::LLVMRustPrepareJIT(intrinsics::morestack_addr());
 
             // We need to tell JIT where to resolve all linked
             // symbols from. The equivalent of -lstd, -lcore, etc.
@@ -152,26 +139,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, m, 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 = sys::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);
         }
     }
 }
@@ -188,6 +192,7 @@ pub mod write {
     use driver::session;
     use lib::llvm::llvm;
     use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
+    use lib::llvm::{ContextRef};
     use lib;
 
     use back::passes;
@@ -206,6 +211,7 @@ pub mod write {
     }
 
     pub fn run_passes(sess: Session,
+                      llcx: ContextRef,
                       llmod: ModuleRef,
                       output_type: output_type,
                       output: &Path) {
@@ -261,7 +267,17 @@ pub mod write {
             debug!("Running Module Optimization Pass");
             mpm.run(llmod);
 
-            if is_object_or_assembly_or_exe(output_type) || opts.jit {
+            if opts.jit {
+                // If we are using JIT, go ahead and create and execute the
+                // engine now.  JIT execution takes ownership of the module and
+                // context, so don't dispose and return.
+                jit::exec(sess, llcx, llmod, true);
+
+                if sess.time_llvm_passes() {
+                    llvm::LLVMRustPrintPassTimings();
+                }
+                return;
+            } else if is_object_or_assembly_or_exe(output_type) {
                 let LLVMOptNone       = 0 as c_int; // -O0
                 let LLVMOptLess       = 1 as c_int; // -O1
                 let LLVMOptDefault    = 2 as c_int; // -O2, -Os
@@ -274,20 +290,6 @@ pub mod write {
                   session::Aggressive => LLVMOptAggressive
                 };
 
-                if opts.jit {
-                    // If we are using JIT, go ahead and create and
-                    // execute the engine now.
-                    // JIT execution takes ownership of the module,
-                    // so don't dispose and return.
-
-                    jit::exec(sess, pm.llpm, llmod, CodeGenOptLevel, true);
-
-                    if sess.time_llvm_passes() {
-                        llvm::LLVMRustPrintPassTimings();
-                    }
-                    return;
-                }
-
                 let FileType;
                 if output_type == output_type_object ||
                        output_type == output_type_exe {
@@ -348,6 +350,7 @@ pub mod write {
                 // Clean up and return
 
                 llvm::LLVMDisposeModule(llmod);
+                llvm::LLVMContextDispose(llcx);
                 if sess.time_llvm_passes() {
                     llvm::LLVMRustPrintPassTimings();
                 }
@@ -366,6 +369,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 61254740dcd..9274eb879f1 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -215,7 +215,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));
 
@@ -338,14 +338,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 f6beb078e46..289bb4f63f5 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};
@@ -239,16 +241,12 @@ pub mod llvm {
         #[fast_ffi]
         pub unsafe fn LLVMContextCreate() -> ContextRef;
         #[fast_ffi]
-        pub unsafe fn LLVMGetGlobalContext() -> ContextRef;
-        #[fast_ffi]
         pub unsafe fn LLVMContextDispose(C: ContextRef);
         #[fast_ffi]
         pub unsafe fn LLVMGetMDKindIDInContext(C: ContextRef,
                                            Name: *c_char,
                                            SLen: c_uint)
                                         -> c_uint;
-        #[fast_ffi]
-        pub unsafe fn LLVMGetMDKindID(Name: *c_char, SLen: c_uint) -> c_uint;
 
         /* Create and destroy modules. */
         #[fast_ffi]
@@ -256,6 +254,8 @@ pub mod llvm {
                                                     C: ContextRef)
                                                  -> ModuleRef;
         #[fast_ffi]
+        pub unsafe fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef;
+        #[fast_ffi]
         pub unsafe fn LLVMDisposeModule(M: ModuleRef);
 
         /** Data layout. See Module::getDataLayout. */
@@ -301,18 +301,6 @@ pub mod llvm {
                                            NumBits: c_uint) -> TypeRef;
 
         #[fast_ffi]
-        pub unsafe fn LLVMInt1Type() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMInt8Type() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMInt16Type() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMInt32Type() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMInt64Type() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMIntType(NumBits: c_uint) -> TypeRef;
-        #[fast_ffi]
         pub unsafe fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint;
 
         /* Operations on real types */
@@ -327,17 +315,6 @@ pub mod llvm {
         #[fast_ffi]
         pub unsafe fn LLVMPPCFP128TypeInContext(C: ContextRef) -> TypeRef;
 
-        #[fast_ffi]
-        pub unsafe fn LLVMFloatType() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMDoubleType() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMX86FP80Type() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMFP128Type() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMPPCFP128Type() -> TypeRef;
-
         /* Operations on function types */
         #[fast_ffi]
         pub unsafe fn LLVMFunctionType(ReturnType: TypeRef,
@@ -361,11 +338,6 @@ pub mod llvm {
                                               ElementCount: c_uint,
                                               Packed: Bool) -> TypeRef;
         #[fast_ffi]
-        pub unsafe fn LLVMStructType(ElementTypes: *TypeRef,
-                                     ElementCount: c_uint,
-                                     Packed: Bool)
-                                  -> TypeRef;
-        #[fast_ffi]
         pub unsafe fn LLVMCountStructElementTypes(StructTy: TypeRef)
                                                -> c_uint;
         #[fast_ffi]
@@ -393,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 */
@@ -403,13 +379,6 @@ pub mod llvm {
         #[fast_ffi]
         pub unsafe fn LLVMMetadataTypeInContext(C: ContextRef) -> TypeRef;
 
-        #[fast_ffi]
-        pub unsafe fn LLVMVoidType() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMLabelType() -> TypeRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMMetadataType() -> TypeRef;
-
         /* Operations on all values */
         #[fast_ffi]
         pub unsafe fn LLVMTypeOf(Val: ValueRef) -> TypeRef;
@@ -482,15 +451,11 @@ pub mod llvm {
                                         SLen: c_uint)
                                      -> ValueRef;
         #[fast_ffi]
-        pub unsafe fn LLVMMDString(Str: *c_char, SLen: c_uint) -> ValueRef;
-        #[fast_ffi]
         pub unsafe fn LLVMMDNodeInContext(C: ContextRef,
                                       Vals: *ValueRef,
                                       Count: c_uint)
                                    -> ValueRef;
         #[fast_ffi]
-        pub unsafe fn LLVMMDNode(Vals: *ValueRef, Count: c_uint) -> ValueRef;
-        #[fast_ffi]
         pub unsafe fn LLVMAddNamedMetadataOperand(M: ModuleRef, Str: *c_char,
                                        Val: ValueRef);
 
@@ -544,20 +509,11 @@ pub mod llvm {
                                                Packed: Bool) -> ValueRef;
 
         #[fast_ffi]
-        pub unsafe fn LLVMConstString(Str: *c_char,
-                                      Length: c_uint,
-                                      DontNullTerminate: Bool)
-                                   -> ValueRef;
-        #[fast_ffi]
         pub unsafe fn LLVMConstArray(ElementTy: TypeRef,
                                      ConstantVals: *ValueRef,
                                      Length: c_uint)
                                   -> ValueRef;
         #[fast_ffi]
-        pub unsafe fn LLVMConstStruct(ConstantVals: *ValueRef,
-                                      Count: c_uint,
-                                      Packed: Bool) -> ValueRef;
-        #[fast_ffi]
         pub unsafe fn LLVMConstVector(ScalarConstantVals: *ValueRef,
                                       Size: c_uint) -> ValueRef;
 
@@ -970,15 +926,6 @@ pub mod llvm {
                                                     BB: BasicBlockRef,
                                                     Name: *c_char)
                                                  -> BasicBlockRef;
-
-        #[fast_ffi]
-        pub unsafe fn LLVMAppendBasicBlock(Fn: ValueRef,
-                                       Name: *c_char)
-                                    -> BasicBlockRef;
-        #[fast_ffi]
-        pub unsafe fn LLVMInsertBasicBlock(InsertBeforeBB: BasicBlockRef,
-                                       Name: *c_char)
-                                    -> BasicBlockRef;
         #[fast_ffi]
         pub unsafe fn LLVMDeleteBasicBlock(BB: BasicBlockRef);
 
@@ -1039,8 +986,6 @@ pub mod llvm {
         #[fast_ffi]
         pub unsafe fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef;
         #[fast_ffi]
-        pub unsafe fn LLVMCreateBuilder() -> BuilderRef;
-        #[fast_ffi]
         pub unsafe fn LLVMPositionBuilder(Builder: BuilderRef,
                                           Block: BasicBlockRef,
                                           Instr: ValueRef);
@@ -1064,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]
@@ -1880,11 +1827,9 @@ pub mod llvm {
 
         /** Execute the JIT engine. */
         #[fast_ffi]
-        pub unsafe fn LLVMRustExecuteJIT(MM: *(),
-                              PM: PassManagerRef,
+        pub unsafe fn LLVMRustBuildJIT(MM: *(),
                               M: ModuleRef,
-                              OptLevel: c_int,
-                              EnableSegmentedStacks: bool) -> *();
+                              EnableSegmentedStacks: bool) -> ExecutionEngineRef;
 
         /** Parses the bitcode in the given memory buffer. */
         #[fast_ffi]
@@ -1893,7 +1838,8 @@ pub mod llvm {
 
         /** Parses LLVM asm in the given file */
         #[fast_ffi]
-        pub unsafe fn LLVMRustParseAssemblyFile(Filename: *c_char)
+        pub unsafe fn LLVMRustParseAssemblyFile(Filename: *c_char,
+                                                C: ContextRef)
                                              -> ModuleRef;
 
         #[fast_ffi]
@@ -1910,6 +1856,9 @@ pub mod llvm {
         pub unsafe fn LLVMRustPrintPassTimings();
 
         #[fast_ffi]
+        pub unsafe fn LLVMRustStartMultithreading() -> bool;
+
+        #[fast_ffi]
         pub unsafe fn LLVMStructCreateNamed(C: ContextRef, Name: *c_char)
                                          -> TypeRef;
 
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 6b56bbb470a..1eb5936e314 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -29,7 +29,7 @@ use back::link::{mangle_exported_name};
 use back::{link, abi, upcall};
 use driver::session;
 use driver::session::Session;
-use lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef};
+use lib::llvm::{ContextRef, ModuleRef, ValueRef, TypeRef, BasicBlockRef};
 use lib::llvm::{True, False};
 use lib::llvm::{llvm, mk_target_data, mk_type_names};
 use lib;
@@ -72,6 +72,7 @@ use core::libc::c_uint;
 use core::str;
 use core::uint;
 use core::vec;
+use core::local_data;
 use extra::time;
 use syntax::ast::ident;
 use syntax::ast_map::{path, path_elt_to_str, path_name};
@@ -1186,7 +1187,7 @@ pub fn new_block(cx: fn_ctxt, parent: Option<block>, kind: block_kind,
     };
     unsafe {
         let llbb = str::as_c_str(cx.ccx.sess.str_of(s), |buf| {
-            llvm::LLVMAppendBasicBlock(cx.llfn, buf)
+            llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf)
         });
         let bcx = mk_block(llbb,
                            parent,
@@ -1553,11 +1554,12 @@ pub struct BasicBlocks {
 // Creates the standard set of basic blocks for a function
 pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks {
     unsafe {
+        let cx = task_llcx();
         BasicBlocks {
             sa: str::as_c_str("static_allocas",
-                           |buf| llvm::LLVMAppendBasicBlock(llfn, buf)),
+                           |buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)),
             rt: str::as_c_str("return",
-                           |buf| llvm::LLVMAppendBasicBlock(llfn, buf))
+                           |buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf))
         }
     }
 }
@@ -2340,7 +2342,7 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
         };
         let llbb = str::as_c_str("top", |buf| {
             unsafe {
-                llvm::LLVMAppendBasicBlock(llfn, buf)
+                llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
             }
         });
         let bld = ccx.builder.B;
@@ -2658,10 +2660,10 @@ pub fn declare_intrinsics(llmod: ModuleRef) -> HashMap<&'static str, ValueRef> {
                            T_void()));
     let memcpy32 =
         decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i32",
-                      T_fn(copy T_memcpy32_args, T_void()));
+                      T_fn(T_memcpy32_args, T_void()));
     let memcpy64 =
         decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i64",
-                      T_fn(copy T_memcpy64_args, T_void()));
+                      T_fn(T_memcpy64_args, T_void()));
     let memmove32 =
         decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i32",
                       T_fn(T_memcpy32_args, T_void()));
@@ -3015,7 +3017,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);
@@ -3037,9 +3039,15 @@ pub fn trans_crate(sess: session::Session,
     let llmod_id = link_meta.name.to_owned() + ".rc";
 
     unsafe {
+        // 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| {
-            llvm::LLVMModuleCreateWithNameInContext
-                (buf, llvm::LLVMGetGlobalContext())
+            llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
         });
         let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
         let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
@@ -3070,6 +3078,7 @@ pub fn trans_crate(sess: session::Session,
         let ccx = @CrateContext {
               sess: sess,
               llmod: llmod,
+              llcx: llcx,
               td: td,
               tn: tn,
               externs: @mut HashMap::new(),
@@ -3124,7 +3133,9 @@ pub fn trans_crate(sess: session::Session,
               int_type: int_type,
               float_type: float_type,
               opaque_vec_type: T_opaque_vec(targ_cfg),
-              builder: BuilderRef_res(unsafe { llvm::LLVMCreateBuilder() }),
+              builder: BuilderRef_res(unsafe {
+                  llvm::LLVMCreateBuilderInContext(llcx)
+              }),
               shape_cx: mk_ctxt(llmod),
               crate_map: crate_map,
               uses_gc: @mut false,
@@ -3169,6 +3180,22 @@ 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);
     }
 }
+
+fn task_local_llcx_key(_v: @ContextRef) {}
+
+pub fn task_llcx() -> ContextRef {
+    let opt = unsafe { local_data::local_data_get(task_local_llcx_key) };
+    *opt.expect("task-local LLVMContextRef wasn't ever set!")
+}
+
+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/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs
index 8ac47ed135a..af108451810 100644
--- a/src/librustc/middle/trans/build.rs
+++ b/src/librustc/middle/trans/build.rs
@@ -564,7 +564,8 @@ pub fn LoadRangeAssert(cx: block, PointerVal: ValueRef, lo: c_ulonglong,
 
         do vec::as_imm_buf([min, max]) |ptr, len| {
             llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
-                                  llvm::LLVMMDNode(ptr, len as c_uint));
+                                  llvm::LLVMMDNodeInContext(cx.fcx.ccx.llcx,
+                                                            ptr, len as c_uint));
         }
     }
 
diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs
index 83acfc661d2..3dd59c05435 100644
--- a/src/librustc/middle/trans/cabi_mips.rs
+++ b/src/librustc/middle/trans/cabi_mips.rs
@@ -18,6 +18,7 @@ use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double};
 use lib::llvm::{Struct, Array, Attribute};
 use lib::llvm::{StructRetAttribute};
 use lib::llvm::True;
+use middle::trans::base::task_llcx;
 use middle::trans::common::*;
 use middle::trans::cabi::*;
 
@@ -165,7 +166,7 @@ fn coerce_to_int(size: uint) -> ~[TypeRef] {
     let r = size % 32;
     if r > 0 {
         unsafe {
-            args.push(llvm::LLVMIntType(r as c_uint))
+            args.push(llvm::LLVMIntTypeInContext(task_llcx(), r as c_uint))
         }
     }
 
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index fcbfe62dbc9..ad591336a71 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -326,7 +326,9 @@ pub fn load_environment(fcx: fn_ctxt,
                 str::as_c_str("load_env",
                               |buf|
                               unsafe {
-                                llvm::LLVMAppendBasicBlock(fcx.llfn, buf)
+                                llvm::LLVMAppendBasicBlockInContext(fcx.ccx.llcx,
+                                                                    fcx.llfn,
+                                                                    buf)
                               });
             fcx.llloadenv = Some(ll);
             ll
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 9134ece7b89..ff2f3841040 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -16,7 +16,7 @@ use back::{abi, upcall};
 use driver::session;
 use driver::session::Session;
 use lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef, BuilderRef};
-use lib::llvm::{True, False, Bool};
+use lib::llvm::{ContextRef, True, False, Bool};
 use lib::llvm::{llvm, TargetData, TypeNames, associate_type, name_has_type};
 use lib;
 use metadata::common::LinkMeta;
@@ -160,6 +160,7 @@ pub type ExternMap = @mut HashMap<@str, ValueRef>;
 pub struct CrateContext {
      sess: session::Session,
      llmod: ModuleRef,
+     llcx: ContextRef,
      td: TargetData,
      tn: @TypeNames,
      externs: ExternMap,
@@ -799,30 +800,44 @@ impl block_ {
 
 // LLVM type constructors.
 pub fn T_void() -> TypeRef {
-    unsafe {
-        return llvm::LLVMVoidType();
-    }
+    unsafe { return llvm::LLVMVoidTypeInContext(base::task_llcx()); }
 }
 
 pub fn T_nil() -> TypeRef {
     return T_struct([], false)
 }
 
-pub fn T_metadata() -> TypeRef { unsafe { return llvm::LLVMMetadataType(); } }
+pub fn T_metadata() -> TypeRef {
+    unsafe { return llvm::LLVMMetadataTypeInContext(base::task_llcx()); }
+}
 
-pub fn T_i1() -> TypeRef { unsafe { return llvm::LLVMInt1Type(); } }
+pub fn T_i1() -> TypeRef {
+    unsafe { return llvm::LLVMInt1TypeInContext(base::task_llcx()); }
+}
 
-pub fn T_i8() -> TypeRef { unsafe { return llvm::LLVMInt8Type(); } }
+pub fn T_i8() -> TypeRef {
+    unsafe { return llvm::LLVMInt8TypeInContext(base::task_llcx()); }
+}
 
-pub fn T_i16() -> TypeRef { unsafe { return llvm::LLVMInt16Type(); } }
+pub fn T_i16() -> TypeRef {
+    unsafe { return llvm::LLVMInt16TypeInContext(base::task_llcx()); }
+}
 
-pub fn T_i32() -> TypeRef { unsafe { return llvm::LLVMInt32Type(); } }
+pub fn T_i32() -> TypeRef {
+    unsafe { return llvm::LLVMInt32TypeInContext(base::task_llcx()); }
+}
 
-pub fn T_i64() -> TypeRef { unsafe { return llvm::LLVMInt64Type(); } }
+pub fn T_i64() -> TypeRef {
+    unsafe { return llvm::LLVMInt64TypeInContext(base::task_llcx()); }
+}
 
-pub fn T_f32() -> TypeRef { unsafe { return llvm::LLVMFloatType(); } }
+pub fn T_f32() -> TypeRef {
+    unsafe { return llvm::LLVMFloatTypeInContext(base::task_llcx()); }
+}
 
-pub fn T_f64() -> TypeRef { unsafe { return llvm::LLVMDoubleType(); } }
+pub fn T_f64() -> TypeRef {
+    unsafe { return llvm::LLVMDoubleTypeInContext(base::task_llcx()); }
+}
 
 pub fn T_bool() -> TypeRef { return T_i8(); }
 
@@ -882,8 +897,8 @@ pub fn T_size_t(targ_cfg: @session::config) -> TypeRef {
 pub fn T_fn(inputs: &[TypeRef], output: TypeRef) -> TypeRef {
     unsafe {
         return llvm::LLVMFunctionType(output, to_ptr(inputs),
-                                   inputs.len() as c_uint,
-                                   False);
+                                      inputs.len() as c_uint,
+                                      False);
     }
 }
 
@@ -905,16 +920,18 @@ pub fn T_root(t: TypeRef, addrspace: addrspace) -> TypeRef {
 
 pub fn T_struct(elts: &[TypeRef], packed: bool) -> TypeRef {
     unsafe {
-        return llvm::LLVMStructType(to_ptr(elts),
-                                    elts.len() as c_uint,
-                                    packed as Bool);
+        return llvm::LLVMStructTypeInContext(base::task_llcx(),
+                                             to_ptr(elts),
+                                             elts.len() as c_uint,
+                                             packed as Bool);
     }
 }
 
 pub fn T_named_struct(name: &str) -> TypeRef {
     unsafe {
-        let c = llvm::LLVMGetGlobalContext();
-        return str::as_c_str(name, |buf| llvm::LLVMStructCreateNamed(c, buf));
+        return str::as_c_str(name, |buf| {
+            llvm::LLVMStructCreateNamed(base::task_llcx(), buf)
+        });
     }
 }
 
@@ -1168,7 +1185,8 @@ pub fn C_cstr(cx: @CrateContext, s: @str) -> ValueRef {
         }
 
         let sc = do str::as_c_str(s) |buf| {
-            llvm::LLVMConstString(buf, s.len() as c_uint, False)
+            llvm::LLVMConstStringInContext(cx.llcx, buf, s.len() as c_uint,
+                                           False)
         };
         let g =
             str::as_c_str(fmt!("str%u", (cx.names)("str").name),
@@ -1197,7 +1215,8 @@ pub fn C_estr_slice(cx: @CrateContext, s: @str) -> ValueRef {
 pub fn C_postr(s: &str) -> ValueRef {
     unsafe {
         return do str::as_c_str(s) |buf| {
-            llvm::LLVMConstString(buf, s.len() as c_uint, False)
+            llvm::LLVMConstStringInContext(base::task_llcx(),
+                                           buf, s.len() as c_uint, False)
         };
     }
 }
@@ -1216,7 +1235,8 @@ pub fn C_zero_byte_arr(size: uint) -> ValueRef {
 pub fn C_struct(elts: &[ValueRef]) -> ValueRef {
     unsafe {
         do vec::as_imm_buf(elts) |ptr, len| {
-            llvm::LLVMConstStruct(ptr, len as c_uint, False)
+            llvm::LLVMConstStructInContext(base::task_llcx(),
+                                           ptr, len as c_uint, False)
         }
     }
 }
@@ -1224,7 +1244,8 @@ pub fn C_struct(elts: &[ValueRef]) -> ValueRef {
 pub fn C_packed_struct(elts: &[ValueRef]) -> ValueRef {
     unsafe {
         do vec::as_imm_buf(elts) |ptr, len| {
-            llvm::LLVMConstStruct(ptr, len as c_uint, True)
+            llvm::LLVMConstStructInContext(base::task_llcx(),
+                                           ptr, len as c_uint, True)
         }
     }
 }
@@ -1240,13 +1261,13 @@ pub fn C_named_struct(T: TypeRef, elts: &[ValueRef]) -> ValueRef {
 pub fn C_array(ty: TypeRef, elts: &[ValueRef]) -> ValueRef {
     unsafe {
         return llvm::LLVMConstArray(ty, vec::raw::to_ptr(elts),
-                                 elts.len() as c_uint);
+                                    elts.len() as c_uint);
     }
 }
 
 pub fn C_bytes(bytes: &[u8]) -> ValueRef {
     unsafe {
-        return llvm::LLVMConstString(
+        return llvm::LLVMConstStringInContext(base::task_llcx(),
             cast::transmute(vec::raw::to_ptr(bytes)),
             bytes.len() as c_uint, True);
     }
@@ -1254,7 +1275,7 @@ pub fn C_bytes(bytes: &[u8]) -> ValueRef {
 
 pub fn C_bytes_plus_null(bytes: &[u8]) -> ValueRef {
     unsafe {
-        return llvm::LLVMConstString(
+        return llvm::LLVMConstStringInContext(base::task_llcx(),
             cast::transmute(vec::raw::to_ptr(bytes)),
             bytes.len() as c_uint, False);
     }
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 83c1bfdb0dd..3bb9d4abab0 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -13,6 +13,7 @@ use core::prelude::*;
 use driver::session;
 use lib::llvm::ValueRef;
 use lib::llvm::llvm;
+use middle::trans::base::task_llcx;
 use middle::trans::common::*;
 use middle::trans::machine;
 use middle::trans::type_of;
@@ -61,7 +62,9 @@ static DW_ATE_unsigned_char: int = 0x08;
 fn llstr(s: &str) -> ValueRef {
     do str::as_c_str(s) |sbuf| {
         unsafe {
-            llvm::LLVMMDString(sbuf, s.len() as libc::c_uint)
+            llvm::LLVMMDStringInContext(task_llcx(),
+                                        sbuf,
+                                        s.len() as libc::c_uint)
         }
     }
 }
@@ -79,7 +82,9 @@ fn lli1(bval: bool) -> ValueRef {
 }
 fn llmdnode(elems: &[ValueRef]) -> ValueRef {
     unsafe {
-        llvm::LLVMMDNode(vec::raw::to_ptr(elems), elems.len() as libc::c_uint)
+        llvm::LLVMMDNodeInContext(task_llcx(),
+                                  vec::raw::to_ptr(elems),
+                                  elems.len() as libc::c_uint)
     }
 }
 fn llunused() -> ValueRef {
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index e3c424f8e7e..2fff45678bc 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -58,7 +58,7 @@ pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::t], output: ty::t)
         if output_is_immediate {
             T_fn(atys, lloutputtype)
         } else {
-            T_fn(atys, llvm::LLVMVoidType())
+            T_fn(atys, llvm::LLVMVoidTypeInContext(cx.llcx))
         }
     }
 }
diff --git a/src/librusti/rusti.rc b/src/librusti/rusti.rc
index 91658928f08..06ec6769385 100644
--- a/src/librusti/rusti.rc
+++ b/src/librusti/rusti.rc
@@ -421,7 +421,7 @@ pub fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str,
     -> Option<Repl> {
     if line.starts_with(":") {
         // drop the : and the \n (one byte each)
-        let full = line.slice(1, line.len() - 1);
+        let full = line.slice(1, line.len());
         let split: ~[~str] = full.word_iter().transform(|s| s.to_owned()).collect();
         let len = split.len();
 
@@ -538,7 +538,7 @@ mod tests {
 
     #[test]
     fn run_all() {
-        // FIXME(#6511):
+        // FIXME(#7071):
         // By default, unit tests are run in parallel. Rusti, on the other hand,
         // does not enjoy doing this. I suspect that it is because the LLVM
         // bindings are not thread-safe (when running parallel tests, some tests
@@ -646,4 +646,14 @@ mod tests {
             f()
         ");
     }
+
+    #[test]
+    fn exit_quits() {
+        let mut r = repl();
+        assert!(r.running);
+        let result = run_line(&mut r, io::stdin(), io::stdout(),
+                              ~":exit", false);
+        assert!(result.is_none());
+        assert!(!r.running);
+    }
 }
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index b8cce8055d3..3b68fc030f5 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -114,6 +114,17 @@ fn test_sysroot() -> Path {
 }
 
 #[test]
+fn test_all() {
+    // FIXME(#7071): these tests use rustc, so they can't be run in parallel
+    //               until this issue is resolved
+    test_make_dir_rwx();
+    test_install_valid();
+    test_install_invalid();
+    test_install_url();
+    test_package_ids_must_be_relative_path_like();
+    test_package_version();
+}
+
 fn test_make_dir_rwx() {
     let temp = &os::tmpdir();
     let dir = temp.push("quux");
@@ -126,7 +137,6 @@ fn test_make_dir_rwx() {
     assert!(os::remove_dir_recursive(&dir));
 }
 
-#[test]
 fn test_install_valid() {
     use path_util::installed_library_in_workspace;
 
@@ -155,7 +165,6 @@ fn test_install_valid() {
     assert!(!os::path_exists(&bench));
 }
 
-#[test]
 fn test_install_invalid() {
     use conditions::nonexistent_package::cond;
     use cond1 = conditions::missing_pkg_files::cond;
@@ -178,7 +187,6 @@ fn test_install_invalid() {
     assert!(error_occurred && error1_occurred);
 }
 
-#[test]
 fn test_install_url() {
     let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
     let sysroot = test_sysroot();
@@ -214,7 +222,6 @@ fn test_install_url() {
     assert!(!os::path_exists(&bench));
 }
 
-#[test]
 fn test_package_ids_must_be_relative_path_like() {
     use conditions::bad_pkg_id::cond;
 
@@ -255,7 +262,6 @@ fn test_package_ids_must_be_relative_path_like() {
 
 }
 
-#[test]
 fn test_package_version() {
     let temp_pkg_id = PkgId::new("github.com/catamorphism/test_pkg_version");
     match temp_pkg_id.version {
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 4ee5df28d24..ba87624e2dd 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -329,12 +329,10 @@ 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,
+                 LLVMModuleRef M,
+                 bool EnableSegmentedStacks) {
 
   InitializeNativeTarget();
   InitializeNativeTargetAsmPrinter();
@@ -346,46 +344,28 @@ LLVMRustExecuteJIT(void* mem,
   Options.JITEmitDebugInfo = true;
   Options.NoFramePointerElim = true;
   Options.EnableSegmentedStacks = EnableSegmentedStacks;
-  PassManager *PM = unwrap<PassManager>(PMR);
   RustMCJITMemoryManager* MM = (RustMCJITMemoryManager*) mem;
-
   assert(MM);
 
-  PM->add(createBasicAliasAnalysisPass());
-  PM->add(createInstructionCombiningPass());
-  PM->add(createReassociatePass());
-  PM->add(createGVNPass());
-  PM->add(createCFGSimplificationPass());
-  PM->add(createFunctionInliningPass());
-  PM->add(createPromoteMemoryToRegisterPass());
-  PM->run(*unwrap(M));
-
   ExecutionEngine* EE = EngineBuilder(unwrap(M))
     .setErrorStr(&Err)
     .setTargetOptions(Options)
     .setJITMemoryManager(MM)
-    .setOptLevel(OptLevel)
     .setUseMCJIT(true)
     .setAllocateGVsWithCode(false)
     .create();
 
   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
@@ -447,9 +427,10 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
   return true;
 }
 
-extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(const char *Filename) {
+extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(LLVMContextRef C,
+                                                   const char *Filename) {
   SMDiagnostic d;
-  Module *m = ParseAssemblyFile(Filename, d, getGlobalContext());
+  Module *m = ParseAssemblyFile(Filename, d, *unwrap(C));
   if (m) {
     return wrap(m);
   } else {
@@ -499,9 +480,6 @@ extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M,
 extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) {
   return wrap(Type::getMetadataTy(*unwrap(C)));
 }
-extern "C" LLVMTypeRef LLVMMetadataType(void) {
-  return LLVMMetadataTypeInContext(LLVMGetGlobalContext());
-}
 
 extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B,
                                             LLVMValueRef source,
@@ -561,3 +539,24 @@ extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty,
                                Constraints, HasSideEffects,
                                IsAlignStack, (InlineAsm::AsmDialect) Dialect));
 }
+
+/**
+ * This function is intended to be a threadsafe interface into enabling a
+ * multithreaded LLVM. This is invoked at the start of the translation phase of
+ * compilation to ensure that LLVM is ready.
+ *
+ * All of trans properly isolates LLVM with the use of a different
+ * LLVMContextRef per task, thus allowing parallel compilation of different
+ * crates in the same process. At the time of this writing, the use case for
+ * this is unit tests for rusti, but there are possible other applications.
+ */
+extern "C" bool LLVMRustStartMultithreading() {
+    static Mutex lock;
+    bool ret = true;
+    assert(lock.acquire());
+    if (!LLVMIsMultithreaded()) {
+        ret = LLVMStartMultithreaded();
+    }
+    assert(lock.release());
+    return ret;
+}
diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in
index 8ebdbd0f307..f5397165781 100644
--- a/src/rustllvm/rustllvm.def.in
+++ b/src/rustllvm/rustllvm.def.in
@@ -6,12 +6,14 @@ LLVMRustConstSmallInt
 LLVMRustConstInt
 LLVMRustLoadCrate
 LLVMRustPrepareJIT
-LLVMRustExecuteJIT
+LLVMRustBuildJIT
 LLVMRustParseBitcode
 LLVMRustParseAssemblyFile
 LLVMRustPrintPassTimings
+LLVMRustStartMultithreading
 LLVMCreateObjectFile
 LLVMDisposeObjectFile
+LLVMDisposeExecutionEngine
 LLVMGetSections
 LLVMDisposeSectionIterator
 LLVMIsSectionIteratorAtEnd
@@ -319,7 +321,6 @@ LLVMGetFunctionAttr
 LLVMGetFunctionCallConv
 LLVMGetGC
 LLVMGetGlobalContext
-LLVMGetGlobalContext
 LLVMGetGlobalParent
 LLVMGetGlobalPassRegistry
 LLVMGetIncomingBlock
@@ -356,6 +357,7 @@ LLVMGetParamParent
 LLVMGetParamTypes
 LLVMGetParams
 LLVMGetPointerAddressSpace
+LLVMGetPointerToGlobal
 LLVMGetPreviousBasicBlock
 LLVMGetPreviousFunction
 LLVMGetPreviousGlobal
@@ -500,7 +502,6 @@ LLVMMDNode
 LLVMMDNodeInContext
 LLVMMDString
 LLVMMDStringInContext
-LLVMMetadataType
 LLVMMetadataTypeInContext
 LLVMModuleCreateWithName
 LLVMModuleCreateWithNameInContext
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index a66ad3704be..6f11202800c 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()