+class MonoLLVMJIT {
+public:
+ /* We use our own trampoline infrastructure instead of the Orc one */
+#if LLVM_API_VERSION >= 500
+ typedef RTDyldObjectLinkingLayer ObjLayerT;
+ typedef IRCompileLayer<ObjLayerT, SimpleCompiler> CompileLayerT;
+ typedef CompileLayerT::ModuleHandleT ModuleHandleT;
+#else
+ typedef ObjectLinkingLayer<> ObjLayerT;
+ typedef IRCompileLayer<ObjLayerT> CompileLayerT;
+ typedef CompileLayerT::ModuleSetHandleT ModuleHandleT;
+#endif
+
+ MonoLLVMJIT (TargetMachine *TM, MonoJitMemoryManager *mm)
+#if LLVM_API_VERSION >= 500
+ : TM(TM), ObjectLayer([=] { return std::shared_ptr<RuntimeDyld::MemoryManager> (mm); }),
+#else
+ : TM(TM),
+#endif
+ CompileLayer (ObjectLayer, SimpleCompiler (*TM)),
+ modules() {
+ }
+
+#if LLVM_API_VERSION >= 500
+ ModuleHandleT addModule(Function *F, std::shared_ptr<Module> M) {
+#else
+ ModuleHandleT addModule(Function *F, Module *M) {
+#endif
+ auto Resolver = createLambdaResolver(
+ [&](const std::string &Name) {
+ const char *name = Name.c_str ();
+#if LLVM_API_VERSION >= 500
+ JITSymbolFlags flags = JITSymbolFlags ();
+#else
+ JITSymbolFlags flags = (JITSymbolFlags)0;
+#endif
+ if (!strcmp (name, "___bzero")) {
+#if LLVM_API_VERSION >= 500
+ return JITSymbol((uint64_t)(gssize)(void*)bzero, flags);
+#else
+ return RuntimeDyld::SymbolInfo((uint64_t)(gssize)(void*)bzero, flags);
+#endif
+ }
+
+ MonoDl *current;
+ char *err;
+ void *symbol;
+ current = mono_dl_open (NULL, 0, NULL);
+ g_assert (current);
+ if (name [0] == '_')
+ err = mono_dl_symbol (current, name + 1, &symbol);
+ else
+ err = mono_dl_symbol (current, name, &symbol);
+ mono_dl_close (current);
+ if (!symbol)
+ outs () << "R: " << Name << "\n";
+ assert (symbol);
+#if LLVM_API_VERSION >= 500
+ return JITSymbol((uint64_t)(gssize)symbol, flags);
+#else
+ return RuntimeDyld::SymbolInfo((uint64_t)(gssize)symbol, flags);
+#endif
+ },
+ [](const std::string &S) {
+ outs () << "R2: " << S << "\n";
+ assert (0);
+ return nullptr;
+ } );
+
+#if LLVM_API_VERSION >= 500
+ ModuleHandleT m = CompileLayer.addModule(M,
+ std::move(Resolver));
+ return m;
+#else
+ return CompileLayer.addModuleSet(singletonSet(M),
+ make_unique<MonoJitMemoryManager>(),
+ std::move(Resolver));
+#endif
+ }
+
+ std::string mangle(const std::string &Name) {
+ std::string MangledName;
+ {
+ raw_string_ostream MangledNameStream(MangledName);
+ Mangler::getNameWithPrefix(MangledNameStream, Name,
+ TM->createDataLayout());
+ }
+ return MangledName;
+ }
+
+ std::string mangle(const GlobalValue *GV) {
+ std::string MangledName;
+ {
+ Mangler Mang;
+
+ raw_string_ostream MangledNameStream(MangledName);
+ Mang.getNameWithPrefix(MangledNameStream, GV, false);
+ }
+ return MangledName;
+ }
+
+ gpointer compile (Function *F, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame) {
+ F->getParent ()->setDataLayout (TM->createDataLayout ());
+#if LLVM_API_VERSION >= 500
+ // Orc uses a shared_ptr to refer to modules so we have to save them ourselves to keep a ref
+ std::shared_ptr<Module> m (F->getParent ());
+ modules.push_back (m);
+ auto ModuleHandle = addModule (F, m);
+#else
+ auto ModuleHandle = addModule (F, F->getParent ());
+#endif
+ auto BodySym = CompileLayer.findSymbolIn(ModuleHandle, mangle (F), false);
+ auto BodyAddr = BodySym.getAddress();
+ assert (BodyAddr);
+
+ for (int i = 0; i < nvars; ++i) {
+ GlobalVariable *var = unwrap<GlobalVariable>(callee_vars [i]);
+
+ auto sym = CompileLayer.findSymbolIn (ModuleHandle, mangle (var->getName ()), true);
+ auto addr = sym.getAddress ();
+ g_assert (addr);
+ callee_addrs [i] = (gpointer)addr;
+ }
+
+ auto ehsym = CompileLayer.findSymbolIn(ModuleHandle, "mono_eh_frame", false);
+ auto ehaddr = ehsym.getAddress ();
+ g_assert (ehaddr);
+ *eh_frame = (gpointer)ehaddr;
+
+ return (gpointer)BodyAddr;
+ }
+
+private:
+ TargetMachine *TM;
+ ObjLayerT ObjectLayer;
+ CompileLayerT CompileLayer;
+ std::vector<std::shared_ptr<Module>> modules;
+};
+
+static MonoLLVMJIT *jit;
+static MonoJitMemoryManager *mono_mm;
+