Skip to content

Commit 517206f

Browse files
committed
Merge pull request #3621 from z0w0/jit-crates
Add support for crate loading to JIT
2 parents a6fe5ef + 00b2086 commit 517206f

File tree

4 files changed

+107
-57
lines changed

4 files changed

+107
-57
lines changed

src/rustc/back/link.rs

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,47 @@ mod jit {
7474
m: ModuleRef,
7575
opt: c_int,
7676
stacks: bool) unsafe {
77-
let ptr = llvm::LLVMRustJIT(rusti::morestack_addr(),
78-
pm, m, opt, stacks);
77+
let manager = llvm::LLVMRustPrepareJIT(rusti::morestack_addr());
78+
79+
// We need to tell JIT where to resolve all linked
80+
// symbols from. The equivalent of -lstd, -lcore, etc.
81+
// By default the JIT will resolve symbols from the std and
82+
// core linked into rustc. We don't want that,
83+
// incase the user wants to use an older std library.
84+
85+
let cstore = sess.cstore;
86+
for cstore::get_used_crate_files(cstore).each |cratepath| {
87+
let path = cratepath.to_str();
88+
89+
debug!("linking: %s", path);
90+
91+
let _: () = str::as_c_str(
92+
path,
93+
|buf_t| {
94+
if !llvm::LLVMRustLoadCrate(manager, buf_t) {
95+
llvm_err(sess, ~"Could not link");
96+
}
97+
debug!("linked: %s", path);
98+
});
99+
}
100+
101+
// The execute function will return a void pointer
102+
// to the _rust_main function. We can do closure
103+
// magic here to turn it straight into a callable rust
104+
// closure. It will also cleanup the memory manager
105+
// for us.
79106

80-
if ptr::is_null(ptr) {
107+
let entry = llvm::LLVMRustExecuteJIT(manager,
108+
pm, m, opt, stacks);
109+
110+
if ptr::is_null(entry) {
81111
llvm_err(sess, ~"Could not JIT");
82112
} else {
83113
let closure = Closure {
84-
code: ptr,
114+
code: entry,
85115
env: ptr::null()
86116
};
87-
let func: fn(~[~str]) = cast::transmute(move closure);
117+
let func: fn(++argv: ~[~str]) = cast::transmute(move closure);
88118

89119
func(~[sess.opts.binary]);
90120
}
@@ -193,30 +223,9 @@ mod write {
193223
// JIT execution takes ownership of the module,
194224
// so don't dispose and return.
195225

196-
// We need to tell LLVM where to resolve all linked
197-
// symbols from. The equivalent of -lstd, -lcore, etc.
198-
// By default the JIT will resolve symbols from the std and
199-
// core linked into rustc. We don't want that,
200-
// incase the user wants to use an older std library.
201-
/*let cstore = sess.cstore;
202-
for cstore::get_used_crate_files(cstore).each |cratepath| {
203-
debug!{"linking: %s", cratepath};
204-
205-
let _: () = str::as_c_str(
206-
cratepath,
207-
|buf_t| {
208-
if !llvm::LLVMRustLoadLibrary(buf_t) {
209-
llvm_err(sess, ~"Could not link");
210-
}
211-
debug!{"linked: %s", cratepath};
212-
});
213-
}*/
214-
215226
jit::exec(sess, pm.llpm, llmod, CodeGenOptLevel, true);
216227

217-
if sess.time_llvm_passes() {
218-
llvm::LLVMRustPrintPassTimings();
219-
}
228+
if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
220229
return;
221230
}
222231

src/rustc/lib/llvm.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -990,15 +990,19 @@ extern mod llvm {
990990
call. */
991991
fn LLVMRustGetLastError() -> *c_char;
992992

993-
/** Load a shared library to resolve symbols against. */
994-
fn LLVMRustLoadLibrary(Filename: *c_char) -> bool;
995-
996-
/** Create and execute the JIT engine. */
997-
fn LLVMRustJIT(__morestack: *(),
998-
PM: PassManagerRef,
999-
M: ModuleRef,
1000-
OptLevel: c_int,
1001-
EnableSegmentedStacks: bool) -> *();
993+
/** Prepare the JIT. Returns a memory manager that can load crates. */
994+
fn LLVMRustPrepareJIT(__morestack: *()) -> *();
995+
996+
/** Load a crate into the memory manager. */
997+
fn LLVMRustLoadCrate(MM: *(),
998+
Filename: *c_char) -> bool;
999+
1000+
/** Execute the JIT engine. */
1001+
fn LLVMRustExecuteJIT(MM: *(),
1002+
PM: PassManagerRef,
1003+
M: ModuleRef,
1004+
OptLevel: c_int,
1005+
EnableSegmentedStacks: bool) -> *();
10021006

10031007
/** Parses the bitcode in the given memory buffer. */
10041008
fn LLVMRustParseBitcode(MemBuf: MemoryBufferRef) -> ModuleRef;

src/rustllvm/RustWrapper.cpp

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "llvm/Transforms/Scalar.h"
2121
#include "llvm/Transforms/IPO.h"
2222
#include "llvm/ADT/Triple.h"
23+
#include "llvm/ADT/DenseSet.h"
2324
#include "llvm/Assembly/Parser.h"
2425
#include "llvm/Assembly/PrintModulePass.h"
2526
#include "llvm/Support/FormattedStream.h"
@@ -42,7 +43,6 @@
4243
#include "llvm-c/Core.h"
4344
#include "llvm-c/BitReader.h"
4445
#include "llvm-c/Object.h"
45-
#include <cstdlib>
4646

4747
// Used by RustMCJITMemoryManager::getPointerToNamedFunction()
4848
// to get around glibc issues. See the function for more information.
@@ -53,6 +53,7 @@
5353
#endif
5454

5555
using namespace llvm;
56+
using namespace llvm::sys;
5657

5758
static const char *LLVMRustError;
5859

@@ -100,18 +101,6 @@ void LLVMRustInitializeTargets() {
100101
LLVMInitializeX86AsmParser();
101102
}
102103

103-
extern "C" bool
104-
LLVMRustLoadLibrary(const char* file) {
105-
std::string err;
106-
107-
if(llvm::sys::DynamicLibrary::LoadLibraryPermanently(file, &err)) {
108-
LLVMRustError = err.c_str();
109-
return false;
110-
}
111-
112-
return true;
113-
}
114-
115104
// Custom memory manager for MCJITting. It needs special features
116105
// that the generic JIT memory manager doesn't entail. Based on
117106
// code from LLI, change where needed for Rust.
@@ -121,10 +110,13 @@ class RustMCJITMemoryManager : public JITMemoryManager {
121110
SmallVector<sys::MemoryBlock, 16> AllocatedCodeMem;
122111
SmallVector<sys::MemoryBlock, 16> FreeCodeMem;
123112
void* __morestack;
113+
DenseSet<DynamicLibrary*> crates;
124114

125115
RustMCJITMemoryManager(void* sym) : __morestack(sym) { }
126116
~RustMCJITMemoryManager();
127117

118+
bool loadCrate(const char*, std::string*);
119+
128120
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
129121
unsigned SectionID);
130122

@@ -197,6 +189,19 @@ class RustMCJITMemoryManager : public JITMemoryManager {
197189
}
198190
};
199191

192+
bool RustMCJITMemoryManager::loadCrate(const char* file, std::string* err) {
193+
DynamicLibrary crate = DynamicLibrary::getPermanentLibrary(file,
194+
err);
195+
196+
if(crate.isValid()) {
197+
crates.insert(&crate);
198+
199+
return true;
200+
}
201+
202+
return false;
203+
}
204+
200205
uint8_t *RustMCJITMemoryManager::allocateDataSection(uintptr_t Size,
201206
unsigned Alignment,
202207
unsigned SectionID) {
@@ -276,6 +281,9 @@ void *RustMCJITMemoryManager::getPointerToNamedFunction(const std::string &Name,
276281
if (Name == "__morestack") return &__morestack;
277282

278283
const char *NameStr = Name.c_str();
284+
285+
// Look through loaded crates and main for symbols.
286+
279287
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
280288
if (Ptr) return Ptr;
281289

@@ -293,21 +301,49 @@ RustMCJITMemoryManager::~RustMCJITMemoryManager() {
293301
}
294302

295303
extern "C" void*
296-
LLVMRustJIT(void* __morestack,
297-
LLVMPassManagerRef PMR,
298-
LLVMModuleRef M,
299-
CodeGenOpt::Level OptLevel,
300-
bool EnableSegmentedStacks) {
304+
LLVMRustPrepareJIT(void* __morestack) {
305+
// An execution engine will take ownership of this later
306+
// and clean it up for us.
307+
308+
return (void*) new RustMCJITMemoryManager(__morestack);
309+
}
310+
311+
extern "C" bool
312+
LLVMRustLoadCrate(void* mem, const char* crate) {
313+
RustMCJITMemoryManager* manager = (RustMCJITMemoryManager*) mem;
314+
std::string Err;
315+
316+
assert(manager);
317+
318+
if(!manager->loadCrate(crate, &Err)) {
319+
LLVMRustError = Err.c_str();
320+
return false;
321+
}
322+
323+
return true;
324+
}
325+
326+
extern "C" void*
327+
LLVMRustExecuteJIT(void* mem,
328+
LLVMPassManagerRef PMR,
329+
LLVMModuleRef M,
330+
CodeGenOpt::Level OptLevel,
331+
bool EnableSegmentedStacks) {
301332

302333
InitializeNativeTarget();
303334
InitializeNativeTargetAsmPrinter();
335+
InitializeNativeTargetAsmParser();
304336

305337
std::string Err;
306338
TargetOptions Options;
339+
Options.JITExceptionHandling = true;
307340
Options.JITEmitDebugInfo = true;
308341
Options.NoFramePointerElim = true;
309342
Options.EnableSegmentedStacks = EnableSegmentedStacks;
310343
PassManager *PM = unwrap<PassManager>(PMR);
344+
RustMCJITMemoryManager* MM = (RustMCJITMemoryManager*) mem;
345+
346+
assert(MM);
311347

312348
PM->add(createBasicAliasAnalysisPass());
313349
PM->add(createInstructionCombiningPass());
@@ -318,8 +354,8 @@ LLVMRustJIT(void* __morestack,
318354
PM->add(createPromoteMemoryToRegisterPass());
319355
PM->run(*unwrap(M));
320356

321-
RustMCJITMemoryManager* MM = new RustMCJITMemoryManager(__morestack);
322357
ExecutionEngine* EE = EngineBuilder(unwrap(M))
358+
.setErrorStr(&Err)
323359
.setTargetOptions(Options)
324360
.setJITMemoryManager(MM)
325361
.setOptLevel(OptLevel)

src/rustllvm/rustllvm.def.in

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ LLVMRustWriteOutputFile
44
LLVMRustGetLastError
55
LLVMRustConstSmallInt
66
LLVMRustConstInt
7-
LLVMRustLoadLibrary
8-
LLVMRustJIT
7+
LLVMRustLoadCrate
8+
LLVMRustPrepareJIT
9+
LLVMRustExecuteJIT
910
LLVMRustParseBitcode
1011
LLVMRustParseAssemblyFile
1112
LLVMRustPrintPassTimings

0 commit comments

Comments
 (0)