summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilip Pizlo <fpizlo@apple.com>2013-05-21 20:00:56 +0000
committerFilip Pizlo <fpizlo@apple.com>2013-05-21 20:00:56 +0000
commit52755c472a738e48a9687240368e4c1f78c45711 (patch)
treea46afa0466ad3fcd997652f29d16f069170ac0c2
parent3bcc3e6f6316f82adff52a04b0c320c2ce3a3d86 (diff)
downloadllvm-52755c472a738e48a9687240368e4c1f78c45711.tar.gz
llvm-52755c472a738e48a9687240368e4c1f78c45711.tar.bz2
llvm-52755c472a738e48a9687240368e4c1f78c45711.tar.xz
Expose the RTDyldMemoryManager through the C API. This allows clients of
the C API to provide their own way of allocating JIT memory (both code and data) and finalizing memory permissions (page protections, cache flush). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182408 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm-c/Core.h1
-rw-r--r--include/llvm-c/ExecutionEngine.h28
-rw-r--r--include/llvm/ExecutionEngine/RTDyldMemoryManager.h4
-rw-r--r--lib/ExecutionEngine/ExecutionEngineBindings.cpp114
-rw-r--r--lib/IR/Core.cpp4
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp163
6 files changed, 273 insertions, 41 deletions
diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h
index 6b62f33261..0920c5d0b0 100644
--- a/include/llvm-c/Core.h
+++ b/include/llvm-c/Core.h
@@ -411,6 +411,7 @@ void LLVMShutdown();
/*===-- Error handling ----------------------------------------------------===*/
+char *LLVMCreateMessage(const char *Message);
void LLVMDisposeMessage(char *Message);
diff --git a/include/llvm-c/ExecutionEngine.h b/include/llvm-c/ExecutionEngine.h
index 8fae77def4..50fdb6bd73 100644
--- a/include/llvm-c/ExecutionEngine.h
+++ b/include/llvm-c/ExecutionEngine.h
@@ -40,12 +40,14 @@ void LLVMLinkInInterpreter(void);
typedef struct LLVMOpaqueGenericValue *LLVMGenericValueRef;
typedef struct LLVMOpaqueExecutionEngine *LLVMExecutionEngineRef;
+typedef struct LLVMOpaqueMCJITMemoryManager *LLVMMCJITMemoryManagerRef;
struct LLVMMCJITCompilerOptions {
unsigned OptLevel;
LLVMCodeModel CodeModel;
LLVMBool NoFramePointerElim;
LLVMBool EnableFastISel;
+ LLVMMCJITMemoryManagerRef MCJMM;
};
/*===-- Operations on generic values --------------------------------------===*/
@@ -167,6 +169,32 @@ void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global,
void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global);
+/*===-- Operations on memory managers -------------------------------------===*/
+
+/**
+ * Create a simple custom MCJIT memory manager. This memory manager can
+ * intercept allocations in a module-oblivious way. This will return NULL
+ * if any of the passed functions are NULL.
+ *
+ * @param Opaque An opaque client object to pass back to the callbacks.
+ * @param AllocateCodeSection Allocate a block of memory for executable code.
+ * @param AllocateDataSection Allocate a block of memory for data.
+ * @param FinalizeMemory Set page permissions and flush cache. Return 0 on
+ * success, 1 on error.
+ */
+LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager(
+ void *Opaque,
+ uint8_t *(*AllocateCodeSection)(void *Opaque,
+ uintptr_t Size, unsigned Alignment,
+ unsigned SectionID),
+ uint8_t *(*AllocateDataSection)(void *Opaque,
+ uintptr_t Size, unsigned Alignment,
+ unsigned SectionID, LLVMBool IsReadOnly),
+ LLVMBool (*FinalizeMemory)(void *Opaque, char **ErrMsg),
+ void (*Destroy)(void *Opaque));
+
+void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM);
+
/**
* @}
*/
diff --git a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h
index 2e1fc56512..99e2594f3c 100644
--- a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h
+++ b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h
@@ -71,6 +71,10 @@ public:
virtual bool finalizeMemory(std::string *ErrMsg = 0) = 0;
};
+// Create wrappers for C Binding types (see CBindingWrapping.h).
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(
+ RTDyldMemoryManager, LLVMMCJITMemoryManagerRef)
+
} // namespace llvm
#endif // LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H
diff --git a/lib/ExecutionEngine/ExecutionEngineBindings.cpp b/lib/ExecutionEngine/ExecutionEngineBindings.cpp
index f9b08a01ea..88e73bf253 100644
--- a/lib/ExecutionEngine/ExecutionEngineBindings.cpp
+++ b/lib/ExecutionEngine/ExecutionEngineBindings.cpp
@@ -15,6 +15,7 @@
#include "llvm-c/ExecutionEngine.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ErrorHandling.h"
@@ -157,10 +158,8 @@ LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions,
size_t SizeOfPassedOptions) {
LLVMMCJITCompilerOptions options;
- options.OptLevel = 0;
+ memset(&options, 0, sizeof(options)); // Most fields are zero by default.
options.CodeModel = LLVMCodeModelJITDefault;
- options.NoFramePointerElim = false;
- options.EnableFastISel = false;
memcpy(PassedOptions, &options,
std::min(sizeof(options), SizeOfPassedOptions));
@@ -199,6 +198,8 @@ LLVMBool LLVMCreateMCJITCompilerForModule(
.setOptLevel((CodeGenOpt::Level)options.OptLevel)
.setCodeModel(unwrap(options.CodeModel))
.setTargetOptions(targetOptions);
+ if (options.MCJMM)
+ builder.setMCJITMemoryManager(unwrap(options.MCJMM));
if (ExecutionEngine *JIT = builder.create()) {
*OutJIT = wrap(JIT);
return 0;
@@ -332,3 +333,110 @@ void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) {
return unwrap(EE)->getPointerToGlobal(unwrap<GlobalValue>(Global));
}
+
+/*===-- Operations on memory managers -------------------------------------===*/
+
+namespace {
+
+struct SimpleBindingMMFunctions {
+ uint8_t *(*AllocateCodeSection)(void *Opaque,
+ uintptr_t Size, unsigned Alignment,
+ unsigned SectionID);
+ uint8_t *(*AllocateDataSection)(void *Opaque,
+ uintptr_t Size, unsigned Alignment,
+ unsigned SectionID, LLVMBool IsReadOnly);
+ LLVMBool (*FinalizeMemory)(void *Opaque, char **ErrMsg);
+ void (*Destroy)(void *Opaque);
+};
+
+class SimpleBindingMemoryManager : public RTDyldMemoryManager {
+public:
+ SimpleBindingMemoryManager(const SimpleBindingMMFunctions& Functions,
+ void *Opaque);
+ virtual ~SimpleBindingMemoryManager();
+
+ virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID);
+
+ virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID,
+ bool isReadOnly);
+
+ virtual bool finalizeMemory(std::string *ErrMsg);
+
+private:
+ SimpleBindingMMFunctions Functions;
+ void *Opaque;
+};
+
+SimpleBindingMemoryManager::SimpleBindingMemoryManager(
+ const SimpleBindingMMFunctions& Functions,
+ void *Opaque)
+ : Functions(Functions), Opaque(Opaque) {
+ assert(Functions.AllocateCodeSection &&
+ "No AllocateCodeSection function provided!");
+ assert(Functions.AllocateDataSection &&
+ "No AllocateDataSection function provided!");
+ assert(Functions.FinalizeMemory &&
+ "No FinalizeMemory function provided!");
+ assert(Functions.Destroy &&
+ "No Destroy function provided!");
+}
+
+SimpleBindingMemoryManager::~SimpleBindingMemoryManager() {
+ Functions.Destroy(Opaque);
+}
+
+uint8_t *SimpleBindingMemoryManager::allocateCodeSection(
+ uintptr_t Size, unsigned Alignment, unsigned SectionID) {
+ return Functions.AllocateCodeSection(Opaque, Size, Alignment, SectionID);
+}
+
+uint8_t *SimpleBindingMemoryManager::allocateDataSection(
+ uintptr_t Size, unsigned Alignment, unsigned SectionID, bool isReadOnly) {
+ return Functions.AllocateDataSection(Opaque, Size, Alignment, SectionID,
+ isReadOnly);
+}
+
+bool SimpleBindingMemoryManager::finalizeMemory(std::string *ErrMsg) {
+ char *errMsgCString = 0;
+ bool result = Functions.FinalizeMemory(Opaque, &errMsgCString);
+ assert((result || !errMsgCString) &&
+ "Did not expect an error message if FinalizeMemory succeeded");
+ if (errMsgCString) {
+ if (ErrMsg)
+ *ErrMsg = errMsgCString;
+ free(errMsgCString);
+ }
+ return result;
+}
+
+} // anonymous namespace
+
+LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager(
+ void *Opaque,
+ uint8_t *(*AllocateCodeSection)(void *Opaque,
+ uintptr_t Size, unsigned Alignment,
+ unsigned SectionID),
+ uint8_t *(*AllocateDataSection)(void *Opaque,
+ uintptr_t Size, unsigned Alignment,
+ unsigned SectionID, LLVMBool IsReadOnly),
+ LLVMBool (*FinalizeMemory)(void *Opaque, char **ErrMsg),
+ void (*Destroy)(void *Opaque)) {
+
+ if (!AllocateCodeSection || !AllocateDataSection || !FinalizeMemory ||
+ !Destroy)
+ return NULL;
+
+ SimpleBindingMMFunctions functions;
+ functions.AllocateCodeSection = AllocateCodeSection;
+ functions.AllocateDataSection = AllocateDataSection;
+ functions.FinalizeMemory = FinalizeMemory;
+ functions.Destroy = Destroy;
+ return wrap(new SimpleBindingMemoryManager(functions, Opaque));
+}
+
+void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM) {
+ delete unwrap(MM);
+}
+
diff --git a/lib/IR/Core.cpp b/lib/IR/Core.cpp
index 889d574290..66610bd7f5 100644
--- a/lib/IR/Core.cpp
+++ b/lib/IR/Core.cpp
@@ -58,6 +58,10 @@ void LLVMShutdown() {
/*===-- Error handling ----------------------------------------------------===*/
+char *LLVMCreateMessage(const char *Message) {
+ return strdup(Message);
+}
+
void LLVMDisposeMessage(char *Message) {
free(Message);
}
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
index e49af05a23..c434a7c0b2 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
+++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
@@ -17,12 +17,46 @@
#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Target.h"
#include "llvm-c/Transforms/Scalar.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Support/Host.h"
#include "MCJITTestAPICommon.h"
#include "gtest/gtest.h"
using namespace llvm;
+static bool didCallAllocateCodeSection;
+
+static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
+ unsigned alignment,
+ unsigned sectionID) {
+ didCallAllocateCodeSection = true;
+ return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
+ size, alignment, sectionID);
+}
+
+static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
+ unsigned alignment,
+ unsigned sectionID,
+ LLVMBool isReadOnly) {
+ return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
+ size, alignment, sectionID, isReadOnly);
+}
+
+static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
+ std::string errMsgString;
+ bool result =
+ static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
+ if (result) {
+ *errMsg = LLVMCreateMessage(errMsgString.c_str());
+ return 1;
+ }
+ return 0;
+}
+
+static void roundTripDestroy(void *object) {
+ delete static_cast<SectionMemoryManager*>(object);
+}
+
class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
protected:
MCJITCAPITest() {
@@ -46,60 +80,113 @@ protected:
// that they will fail the MCJIT C API tests.
UnsupportedOSs.push_back(Triple::Cygwin);
}
-};
-
-TEST_F(MCJITCAPITest, simple_function) {
- SKIP_UNSUPPORTED_PLATFORM;
- char *error = 0;
+ virtual void SetUp() {
+ didCallAllocateCodeSection = false;
+ Module = 0;
+ Function = 0;
+ Engine = 0;
+ Error = 0;
+ }
- // Creates a function that returns 42, compiles it, and runs it.
+ virtual void TearDown() {
+ if (Engine)
+ LLVMDisposeExecutionEngine(Engine);
+ else if (Module)
+ LLVMDisposeModule(Module);
+ }
- LLVMModuleRef module = LLVMModuleCreateWithName("simple_module");
-
- LLVMSetTarget(module, HostTriple.c_str());
+ void buildSimpleFunction() {
+ Module = LLVMModuleCreateWithName("simple_module");
+
+ LLVMSetTarget(Module, HostTriple.c_str());
+
+ Function = LLVMAddFunction(
+ Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
+ LLVMSetFunctionCallConv(Function, LLVMCCallConv);
+
+ LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
+ LLVMBuilderRef builder = LLVMCreateBuilder();
+ LLVMPositionBuilderAtEnd(builder, entry);
+ LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
+
+ LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
+ LLVMDisposeMessage(Error);
+
+ LLVMDisposeBuilder(builder);
+ }
- LLVMValueRef function = LLVMAddFunction(
- module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
- LLVMSetFunctionCallConv(function, LLVMCCallConv);
+ void buildMCJITOptions() {
+ LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
+ Options.OptLevel = 2;
+
+ // Just ensure that this field still exists.
+ Options.NoFramePointerElim = false;
+ }
- LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry");
- LLVMBuilderRef builder = LLVMCreateBuilder();
- LLVMPositionBuilderAtEnd(builder, entry);
- LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
+ void useRoundTripSectionMemoryManager() {
+ Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
+ new SectionMemoryManager(),
+ roundTripAllocateCodeSection,
+ roundTripAllocateDataSection,
+ roundTripFinalizeMemory,
+ roundTripDestroy);
+ }
- LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
- LLVMDisposeMessage(error);
+ void buildMCJITEngine() {
+ ASSERT_EQ(
+ 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
+ sizeof(Options), &Error));
+ }
- LLVMDisposeBuilder(builder);
+ void buildAndRunPasses() {
+ LLVMPassManagerRef pass = LLVMCreatePassManager();
+ LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
+ LLVMAddConstantPropagationPass(pass);
+ LLVMAddInstructionCombiningPass(pass);
+ LLVMRunPassManager(pass, Module);
+ LLVMDisposePassManager(pass);
+ }
- LLVMMCJITCompilerOptions options;
- LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
- options.OptLevel = 2;
+ LLVMModuleRef Module;
+ LLVMValueRef Function;
+ LLVMMCJITCompilerOptions Options;
+ LLVMExecutionEngineRef Engine;
+ char *Error;
+};
+
+TEST_F(MCJITCAPITest, simple_function) {
+ SKIP_UNSUPPORTED_PLATFORM;
- // Just ensure that this field still exists.
- options.NoFramePointerElim = false;
+ buildSimpleFunction();
+ buildMCJITOptions();
+ buildMCJITEngine();
+ buildAndRunPasses();
+
+ union {
+ void *raw;
+ int (*usable)();
+ } functionPointer;
+ functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
- LLVMExecutionEngineRef engine;
- ASSERT_EQ(
- 0, LLVMCreateMCJITCompilerForModule(&engine, module, &options,
- sizeof(options), &error));
+ EXPECT_EQ(42, functionPointer.usable());
+}
+
+TEST_F(MCJITCAPITest, custom_memory_manager) {
+ SKIP_UNSUPPORTED_PLATFORM;
- LLVMPassManagerRef pass = LLVMCreatePassManager();
- LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
- LLVMAddConstantPropagationPass(pass);
- LLVMAddInstructionCombiningPass(pass);
- LLVMRunPassManager(pass, module);
- LLVMDisposePassManager(pass);
+ buildSimpleFunction();
+ buildMCJITOptions();
+ useRoundTripSectionMemoryManager();
+ buildMCJITEngine();
+ buildAndRunPasses();
union {
void *raw;
int (*usable)();
} functionPointer;
- functionPointer.raw = LLVMGetPointerToGlobal(engine, function);
+ functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
EXPECT_EQ(42, functionPointer.usable());
-
- LLVMDisposeExecutionEngine(engine);
+ EXPECT_TRUE(didCallAllocateCodeSection);
}
-