jit: Add custom memory manager (still segfaulting)
This commit is contained in:
parent
d7aa9918ef
commit
7993f48209
5 changed files with 275 additions and 184 deletions
|
@ -1,167 +0,0 @@
|
|||
# This file is generated by gyp; do not edit.
|
||||
|
||||
TOOLSET := target
|
||||
TARGET := uv
|
||||
DEFS_Debug := '-DWIN32' \
|
||||
'-D_CRT_SECURE_NO_DEPRECATE' \
|
||||
'-D_CRT_NONSTDC_NO_DEPRECATE' \
|
||||
'-DHAVE_CONFIG_H' \
|
||||
'-D_WIN32_WINNT=0x0600' \
|
||||
'-DEIO_STACKSIZE=262144' \
|
||||
'-D_GNU_SOURCE' \
|
||||
'-DDEBUG' \
|
||||
'-D_DEBUG'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Debug := -g \
|
||||
-O0
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Debug :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Debug :=
|
||||
|
||||
INCS_Debug := -I$(srcdir)\src\libuv\include \
|
||||
-I$(srcdir)\src\libuv\include\uv-private \
|
||||
-I$(srcdir)\src\libuv\src \
|
||||
-I$(srcdir)\src\libuv\src\ares\config_win32
|
||||
|
||||
DEFS_Release := '-DWIN32' \
|
||||
'-D_CRT_SECURE_NO_DEPRECATE' \
|
||||
'-D_CRT_NONSTDC_NO_DEPRECATE' \
|
||||
'-DHAVE_CONFIG_H' \
|
||||
'-D_WIN32_WINNT=0x0600' \
|
||||
'-DEIO_STACKSIZE=262144' \
|
||||
'-D_GNU_SOURCE' \
|
||||
'-DNDEBUG'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Release := -O3 \
|
||||
-fomit-frame-pointer \
|
||||
-fdata-sections \
|
||||
-ffunction-sections
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Release :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Release :=
|
||||
|
||||
INCS_Release := -I$(srcdir)\src\libuv\include \
|
||||
-I$(srcdir)\src\libuv\include\uv-private \
|
||||
-I$(srcdir)\src\libuv\src \
|
||||
-I$(srcdir)\src\libuv\src\ares\config_win32
|
||||
|
||||
OBJS := $(obj).target\$(TARGET)\src\libuv\src\uv-common.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_cancel.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares__close_sockets.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_data.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_destroy.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_expand_name.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_expand_string.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_fds.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_free_hostent.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_free_string.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_gethostbyaddr.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_gethostbyname.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares__get_hostent.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_getnameinfo.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_getopt.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_getsock.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_init.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_library_init.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_llist.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_mkquery.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_nowarn.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_options.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_aaaa_reply.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_a_reply.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_mx_reply.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_ns_reply.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_ptr_reply.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_srv_reply.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_txt_reply.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_process.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_query.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares__read_line.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_search.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_send.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_strcasecmp.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_strdup.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_strerror.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_timeout.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares__timeval.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_version.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_writev.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\bitncmp.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\inet_net_pton.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\inet_ntop.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\windows_port.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_getenv.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\ares\ares_platform.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\async.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\cares.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\core.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\dl.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\error.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\fs.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\fs-event.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\getaddrinfo.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\handle.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\loop-watcher.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\pipe.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\thread.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\process.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\req.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\stream.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\tcp.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\tty.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\threadpool.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\timer.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\udp.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\util.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\winapi.o \
|
||||
$(obj).target\$(TARGET)\src\libuv\src\win\winsock.o
|
||||
|
||||
# Add to the list of files we specially track dependencies for.
|
||||
all_deps += $(OBJS)
|
||||
|
||||
# CFLAGS et al overrides must be target-local.
|
||||
# See "Target-specific Variable Values" in the GNU Make manual.
|
||||
$(OBJS): TOOLSET := $(TOOLSET)
|
||||
$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
|
||||
$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
|
||||
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
|
||||
$(obj).$(TOOLSET)\$(TARGET)\%.o: $(srcdir)\%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
|
||||
$(obj).$(TOOLSET)\$(TARGET)\%.o: $(obj).$(TOOLSET)\%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
$(obj).$(TOOLSET)\$(TARGET)\%.o: $(obj)\%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# End of this set of suffix rules
|
||||
### Rules for final target.
|
||||
LDFLAGS_Debug :=
|
||||
|
||||
LDFLAGS_Release :=
|
||||
|
||||
LIBS :=
|
||||
|
||||
$(obj).target\src\libuv\libuv.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
|
||||
$(obj).target\src\libuv\libuv.a: LIBS := $(LIBS)
|
||||
$(obj).target\src\libuv\libuv.a: TOOLSET := $(TOOLSET)
|
||||
$(obj).target\src\libuv\libuv.a: $(OBJS) FORCE_DO_CMD
|
||||
$(call do_cmd,alink)
|
||||
|
||||
all_deps += $(obj).target\src\libuv\libuv.a
|
||||
# Add target alias
|
||||
.PHONY: uv
|
||||
uv: $(obj).target\src\libuv\libuv.a
|
||||
|
|
@ -160,14 +160,37 @@ mod write {
|
|||
llvm::LLVMAddCFGSimplificationPass(pm.llpm);*/
|
||||
|
||||
// JIT execution takes ownership of the module,
|
||||
// so don't dispose and return.
|
||||
// so don't dispose and return. Due to a weird bug
|
||||
// with dynamic libraries, we need to separate jitting
|
||||
// into two functions and load crates inbetween.
|
||||
|
||||
if !llvm::LLVMRustJIT(pm.llpm,
|
||||
llmod,
|
||||
CodeGenOptLevel,
|
||||
true) {
|
||||
if !llvm::LLVMRustPrepareJIT(pm.llpm,
|
||||
llmod,
|
||||
CodeGenOptLevel,
|
||||
true) {
|
||||
llvm_err(sess, ~"Could not JIT");
|
||||
}
|
||||
|
||||
// We need to tell LLVM where to resolve all linked
|
||||
// symbols from. The equivalent of -lstd, -lcore, etc.
|
||||
/*let cstore = sess.cstore;
|
||||
for cstore::get_used_crate_files(cstore).each |cratepath| {
|
||||
debug!{"linking: %s", cratepath};
|
||||
|
||||
let _: () = str::as_c_str(
|
||||
cratepath,
|
||||
|buf_t| {
|
||||
if !llvm::LLVMRustLoadLibrary(buf_t) {
|
||||
llvm_err(sess, ~"Could not link");
|
||||
}
|
||||
debug!{"linked: %s", cratepath};
|
||||
});
|
||||
}*/
|
||||
|
||||
if !llvm::LLVMRustExecuteJIT() {
|
||||
llvm_err(sess, ~"Could not JIT");
|
||||
}
|
||||
|
||||
if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -986,12 +986,18 @@ extern mod llvm {
|
|||
call. */
|
||||
fn LLVMRustGetLastError() -> *c_char;
|
||||
|
||||
/** JIT the module. **/
|
||||
fn LLVMRustJIT(PM: PassManagerRef,
|
||||
/** Load a shared library to resolve symbols against. */
|
||||
fn LLVMRustLoadLibrary(Filename: *c_char) -> bool;
|
||||
|
||||
/** Create the JIT engine. */
|
||||
fn LLVMRustPrepareJIT(PM: PassManagerRef,
|
||||
M: ModuleRef,
|
||||
OptLevel: c_int,
|
||||
EnableSegmentedStacks: bool) -> bool;
|
||||
|
||||
/** Execute the JIT engine. */
|
||||
fn LLVMRustExecuteJIT() -> bool;
|
||||
|
||||
/** Parses the bitcode in the given memory buffer. */
|
||||
fn LLVMRustParseBitcode(MemBuf: MemoryBufferRef) -> ModuleRef;
|
||||
|
||||
|
|
|
@ -29,8 +29,11 @@
|
|||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/ExecutionEngine/JITMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/MCJIT.h"
|
||||
#include "llvm/ExecutionEngine/Interpreter.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm-c/Core.h"
|
||||
|
@ -38,6 +41,14 @@
|
|||
#include "llvm-c/Object.h"
|
||||
#include <cstdlib>
|
||||
|
||||
// Used by RustMCJITMemoryManager::getPointerToNamedFunction()
|
||||
// to get around glibc issues. See the function for more information.
|
||||
#ifdef __linux__
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static const char *LLVMRustError;
|
||||
|
@ -85,7 +96,208 @@ void LLVMInitializeX86AsmParser();
|
|||
LLVMInitializeX86AsmParser();
|
||||
|
||||
extern "C" bool
|
||||
LLVMRustJIT(LLVMPassManagerRef PMR,
|
||||
LLVMRustLoadLibrary(const char* file) {
|
||||
std::string err;
|
||||
|
||||
if(llvm::sys::DynamicLibrary::LoadLibraryPermanently(file, &err)) {
|
||||
LLVMRustError = err.c_str();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ExecutionEngine* EE;
|
||||
|
||||
// Custom memory manager for MCJITting. It needs special features
|
||||
// that the generic JIT memory manager doesn't entail. Based on
|
||||
// code from LLI, change where needed for Rust.
|
||||
class RustMCJITMemoryManager : public JITMemoryManager {
|
||||
public:
|
||||
SmallVector<sys::MemoryBlock, 16> AllocatedDataMem;
|
||||
SmallVector<sys::MemoryBlock, 16> AllocatedCodeMem;
|
||||
SmallVector<sys::MemoryBlock, 16> FreeCodeMem;
|
||||
|
||||
RustMCJITMemoryManager() { }
|
||||
~RustMCJITMemoryManager();
|
||||
|
||||
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID);
|
||||
|
||||
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID);
|
||||
|
||||
virtual void *getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure = true);
|
||||
|
||||
// Invalidate instruction cache for code sections. Some platforms with
|
||||
// separate data cache and instruction cache require explicit cache flush,
|
||||
// otherwise JIT code manipulations (like resolved relocations) will get to
|
||||
// the data cache but not to the instruction cache.
|
||||
virtual void invalidateInstructionCache();
|
||||
|
||||
// The MCJITMemoryManager doesn't use the following functions, so we don't
|
||||
// need implement them.
|
||||
virtual void setMemoryWritable() {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual void setMemoryExecutable() {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual void setPoisonMemory(bool poison) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual void AllocateGOT() {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual uint8_t *getGOTBase() const {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
return 0;
|
||||
}
|
||||
virtual uint8_t *startFunctionBody(const Function *F,
|
||||
uintptr_t &ActualSize){
|
||||
llvm_unreachable("Unimplemented call");
|
||||
return 0;
|
||||
}
|
||||
virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
|
||||
unsigned Alignment) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
return 0;
|
||||
}
|
||||
virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart,
|
||||
uint8_t *FunctionEnd) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
return 0;
|
||||
}
|
||||
virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
return 0;
|
||||
}
|
||||
virtual void deallocateFunctionBody(void *Body) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual uint8_t* startExceptionTable(const Function* F,
|
||||
uintptr_t &ActualSize) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
return 0;
|
||||
}
|
||||
virtual void endExceptionTable(const Function *F, uint8_t *TableStart,
|
||||
uint8_t *TableEnd, uint8_t* FrameRegister) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual void deallocateExceptionTable(void *ET) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
};
|
||||
|
||||
uint8_t *RustMCJITMemoryManager::allocateDataSection(uintptr_t Size,
|
||||
unsigned Alignment,
|
||||
unsigned SectionID) {
|
||||
if (!Alignment)
|
||||
Alignment = 16;
|
||||
uint8_t *Addr = (uint8_t*)calloc((Size + Alignment - 1)/Alignment, Alignment);
|
||||
AllocatedDataMem.push_back(sys::MemoryBlock(Addr, Size));
|
||||
return Addr;
|
||||
}
|
||||
|
||||
uint8_t *RustMCJITMemoryManager::allocateCodeSection(uintptr_t Size,
|
||||
unsigned Alignment,
|
||||
unsigned SectionID) {
|
||||
if (!Alignment)
|
||||
Alignment = 16;
|
||||
unsigned NeedAllocate = Alignment * ((Size + Alignment - 1)/Alignment + 1);
|
||||
uintptr_t Addr = 0;
|
||||
// Look in the list of free code memory regions and use a block there if one
|
||||
// is available.
|
||||
for (int i = 0, e = FreeCodeMem.size(); i != e; ++i) {
|
||||
sys::MemoryBlock &MB = FreeCodeMem[i];
|
||||
if (MB.size() >= NeedAllocate) {
|
||||
Addr = (uintptr_t)MB.base();
|
||||
uintptr_t EndOfBlock = Addr + MB.size();
|
||||
// Align the address.
|
||||
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
|
||||
// Store cutted free memory block.
|
||||
FreeCodeMem[i] = sys::MemoryBlock((void*)(Addr + Size),
|
||||
EndOfBlock - Addr - Size);
|
||||
return (uint8_t*)Addr;
|
||||
}
|
||||
}
|
||||
|
||||
// No pre-allocated free block was large enough. Allocate a new memory region.
|
||||
sys::MemoryBlock MB = sys::Memory::AllocateRWX(NeedAllocate, 0, 0);
|
||||
|
||||
AllocatedCodeMem.push_back(MB);
|
||||
Addr = (uintptr_t)MB.base();
|
||||
uintptr_t EndOfBlock = Addr + MB.size();
|
||||
// Align the address.
|
||||
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
|
||||
// The AllocateRWX may allocate much more memory than we need. In this case,
|
||||
// we store the unused memory as a free memory block.
|
||||
unsigned FreeSize = EndOfBlock-Addr-Size;
|
||||
if (FreeSize > 16)
|
||||
FreeCodeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize));
|
||||
|
||||
// Return aligned address
|
||||
return (uint8_t*)Addr;
|
||||
}
|
||||
|
||||
void RustMCJITMemoryManager::invalidateInstructionCache() {
|
||||
for (int i = 0, e = AllocatedCodeMem.size(); i != e; ++i)
|
||||
sys::Memory::InvalidateInstructionCache(AllocatedCodeMem[i].base(),
|
||||
AllocatedCodeMem[i].size());
|
||||
}
|
||||
|
||||
void *RustMCJITMemoryManager::getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure) {
|
||||
#ifdef __linux__
|
||||
// Force the following functions to be linked in to anything that uses the
|
||||
// JIT. This is a hack designed to work around the all-too-clever Glibc
|
||||
// strategy of making these functions work differently when inlined vs. when
|
||||
// not inlined, and hiding their real definitions in a separate archive file
|
||||
// that the dynamic linker can't see. For more info, search for
|
||||
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
|
||||
if (Name == "stat") return (void*)(intptr_t)&stat;
|
||||
if (Name == "fstat") return (void*)(intptr_t)&fstat;
|
||||
if (Name == "lstat") return (void*)(intptr_t)&lstat;
|
||||
if (Name == "stat64") return (void*)(intptr_t)&stat64;
|
||||
if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
|
||||
if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
|
||||
if (Name == "atexit") return (void*)(intptr_t)&atexit;
|
||||
if (Name == "mknod") return (void*)(intptr_t)&mknod;
|
||||
#endif
|
||||
|
||||
const char *NameStr = Name.c_str();
|
||||
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
|
||||
if (Ptr) return Ptr;
|
||||
|
||||
// If it wasn't found and if it starts with an underscore ('_') character,
|
||||
// try again without the underscore.
|
||||
if (NameStr[0] == '_') {
|
||||
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
|
||||
if (Ptr) return Ptr;
|
||||
}
|
||||
|
||||
if (AbortOnFailure)
|
||||
report_fatal_error("Program used external function '" + Name +
|
||||
"' which could not be resolved!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
RustMCJITMemoryManager::~RustMCJITMemoryManager() {
|
||||
for (unsigned i = 0, e = AllocatedCodeMem.size(); i != e; ++i)
|
||||
sys::Memory::ReleaseRWX(AllocatedCodeMem[i]);
|
||||
for (unsigned i = 0, e = AllocatedDataMem.size(); i != e; ++i)
|
||||
free(AllocatedDataMem[i].base());
|
||||
}
|
||||
|
||||
// Separated functions because loading libraries before creating
|
||||
// an execution engine seems to break stuff.
|
||||
|
||||
extern "C" bool
|
||||
LLVMRustPrepareJIT(LLVMPassManagerRef PMR,
|
||||
LLVMModuleRef M,
|
||||
CodeGenOpt::Level OptLevel,
|
||||
bool EnableSegmentedStacks) {
|
||||
|
@ -96,15 +308,16 @@ LLVMRustJIT(LLVMPassManagerRef PMR,
|
|||
|
||||
std::string Err;
|
||||
TargetOptions Options;
|
||||
Options.NoFramePointerElim = true;
|
||||
Options.EnableSegmentedStacks = EnableSegmentedStacks;
|
||||
Options.JITEmitDebugInfo = true;
|
||||
//Options.NoFramePointerElim = true;
|
||||
//Options.EnableSegmentedStacks = EnableSegmentedStacks;
|
||||
|
||||
PassManager *PM = unwrap<PassManager>(PMR);
|
||||
unwrap<PassManager>(PMR)->run(*unwrap(M));
|
||||
|
||||
PM->run(*unwrap(M));
|
||||
|
||||
ExecutionEngine* EE = EngineBuilder(unwrap(M))
|
||||
RustMCJITMemoryManager* MM = new RustMCJITMemoryManager();
|
||||
EE = EngineBuilder(unwrap(M))
|
||||
.setTargetOptions(Options)
|
||||
.setJITMemoryManager(MM)
|
||||
.setOptLevel(OptLevel)
|
||||
.setUseMCJIT(true)
|
||||
.create();
|
||||
|
@ -114,6 +327,16 @@ LLVMRustJIT(LLVMPassManagerRef PMR,
|
|||
return false;
|
||||
}
|
||||
|
||||
MM->invalidateInstructionCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool
|
||||
LLVMRustExecuteJIT() {
|
||||
assert(EE);
|
||||
|
||||
std::string Err;
|
||||
Function* func = EE->FindFunctionNamed("main");
|
||||
|
||||
if(!func || Err != "") {
|
||||
|
@ -121,9 +344,13 @@ LLVMRustJIT(LLVMPassManagerRef PMR,
|
|||
return false;
|
||||
}
|
||||
|
||||
std::vector<GenericValue> args;
|
||||
//std::vector<GenericValue> args;
|
||||
typedef int (*entry_t)(int, int);
|
||||
entry_t entry = (entry_t) EE->getPointerToFunction(func);
|
||||
|
||||
EE->runFunction(func, args);
|
||||
assert(entry);
|
||||
entry(0, 0);
|
||||
//EE->runFunction(func, args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ LLVMRustWriteOutputFile
|
|||
LLVMRustGetLastError
|
||||
LLVMRustConstSmallInt
|
||||
LLVMRustConstInt
|
||||
LLVMRustJIT
|
||||
LLVMRustLoadLibrary
|
||||
LLVMRustPrepareJIT
|
||||
LLVMRustExecuteJIT
|
||||
LLVMRustParseBitcode
|
||||
LLVMRustParseAssemblyFile
|
||||
LLVMRustPrintPassTimings
|
||||
|
|
Loading…
Add table
Reference in a new issue