2 // jit-llvm.cpp: Support code for using LLVM as a JIT backend
4 // (C) 2009-2011 Novell, Inc.
5 // Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
7 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
9 // Mono's internal header files are not C++ clean, so avoid including them if
15 #include <llvm-c/Core.h>
16 #include <llvm-c/ExecutionEngine.h>
18 #include "mini-llvm-cpp.h"
21 #if defined(MONO_ARCH_LLVM_JIT_SUPPORTED) && !defined(MONO_CROSS_COMPILE) && LLVM_API_VERSION > 600
23 #include <llvm/Support/raw_ostream.h>
24 #include <llvm/Support/Host.h>
25 #include <llvm/Support/TargetSelect.h>
26 #include <llvm/IR/Mangler.h>
27 #include <llvm/ExecutionEngine/ExecutionEngine.h>
28 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
29 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
30 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
31 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
32 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
33 #include "llvm/ExecutionEngine/JITSymbol.h"
37 #include <mono/utils/mono-dl.h>
40 using namespace llvm::orc
;
42 extern cl::opt
<bool> EnableMonoEH
;
43 extern cl::opt
<std::string
> MonoEHFrameSymbol
;
46 mono_llvm_set_unhandled_exception_handler (void)
51 static std::vector
<T
> singletonSet(T t
) {
53 Vec
.push_back(std::move(t
));
60 extern void *memset(void *, int, size_t);
61 void bzero (void *to
, size_t count
) { memset (to
, 0, count
); }
65 static AllocCodeMemoryCb
*alloc_code_mem_cb
;
67 class MonoJitMemoryManager
: public RTDyldMemoryManager
70 ~MonoJitMemoryManager() override
;
72 uint8_t *allocateDataSection(uintptr_t Size
,
75 StringRef SectionName
,
76 bool IsReadOnly
) override
;
78 uint8_t *allocateCodeSection(uintptr_t Size
,
81 StringRef SectionName
) override
;
83 bool finalizeMemory(std::string
*ErrMsg
= nullptr) override
;
86 MonoJitMemoryManager::~MonoJitMemoryManager()
91 MonoJitMemoryManager::allocateDataSection(uintptr_t Size
,
94 StringRef SectionName
,
96 uint8_t *res
= (uint8_t*)malloc (Size
);
98 memset (res
, 0, Size
);
103 MonoJitMemoryManager::allocateCodeSection(uintptr_t Size
,
106 StringRef SectionName
)
108 return alloc_code_mem_cb (NULL
, Size
);
112 MonoJitMemoryManager::finalizeMemory(std::string
*ErrMsg
)
119 /* We use our own trampoline infrastructure instead of the Orc one */
120 typedef RTDyldObjectLinkingLayer ObjLayerT
;
121 typedef IRCompileLayer
<ObjLayerT
, SimpleCompiler
> CompileLayerT
;
122 typedef CompileLayerT::ModuleHandleT ModuleHandleT
;
124 MonoLLVMJIT (TargetMachine
*TM
, MonoJitMemoryManager
*mm
)
125 : TM(TM
), ObjectLayer([=] { return std::shared_ptr
<RuntimeDyld::MemoryManager
> (mm
); }),
126 CompileLayer (ObjectLayer
, SimpleCompiler (*TM
)),
130 ModuleHandleT
addModule(Function
*F
, std::shared_ptr
<Module
> M
) {
131 auto Resolver
= createLambdaResolver(
132 [&](const std::string
&Name
) {
133 const char *name
= Name
.c_str ();
134 JITSymbolFlags flags
= JITSymbolFlags ();
135 if (!strcmp (name
, "___bzero"))
136 return JITSymbol((uint64_t)(gssize
)(void*)bzero
, flags
);
141 current
= mono_dl_open (NULL
, 0, NULL
);
144 err
= mono_dl_symbol (current
, name
+ 1, &symbol
);
146 err
= mono_dl_symbol (current
, name
, &symbol
);
147 mono_dl_close (current
);
149 outs () << "R: " << Name
<< "\n";
151 return JITSymbol((uint64_t)(gssize
)symbol
, flags
);
153 [](const std::string
&S
) {
154 outs () << "R2: " << S
<< "\n";
159 auto m
= CompileLayer
.addModule(M
, std::move(Resolver
));
164 std::string
mangle(const std::string
&Name
) {
165 std::string MangledName
;
167 raw_string_ostream
MangledNameStream(MangledName
);
168 Mangler::getNameWithPrefix(MangledNameStream
, Name
,
169 TM
->createDataLayout());
174 std::string
mangle(const GlobalValue
*GV
) {
175 std::string MangledName
;
179 raw_string_ostream
MangledNameStream(MangledName
);
180 Mang
.getNameWithPrefix(MangledNameStream
, GV
, false);
185 gpointer
compile (Function
*F
, int nvars
, LLVMValueRef
*callee_vars
, gpointer
*callee_addrs
, gpointer
*eh_frame
) {
186 F
->getParent ()->setDataLayout (TM
->createDataLayout ());
187 // Orc uses a shared_ptr to refer to modules so we have to save them ourselves to keep a ref
188 std::shared_ptr
<Module
> m (F
->getParent ());
189 modules
.push_back (m
);
190 auto ModuleHandle
= addModule (F
, m
);
191 auto BodySym
= CompileLayer
.findSymbolIn(ModuleHandle
, mangle (F
), false);
192 auto BodyAddr
= BodySym
.getAddress();
195 for (int i
= 0; i
< nvars
; ++i
) {
196 GlobalVariable
*var
= unwrap
<GlobalVariable
>(callee_vars
[i
]);
198 auto sym
= CompileLayer
.findSymbolIn (ModuleHandle
, mangle (var
->getName ()), true);
199 auto addr
= sym
.getAddress ();
200 g_assert ((bool)addr
);
201 callee_addrs
[i
] = (gpointer
)addr
.get ();
204 auto ehsym
= CompileLayer
.findSymbolIn(ModuleHandle
, "mono_eh_frame", false);
205 auto ehaddr
= ehsym
.getAddress ();
206 g_assert ((bool)ehaddr
);
207 *eh_frame
= (gpointer
)ehaddr
.get ();
208 return (gpointer
)BodyAddr
.get ();
213 ObjLayerT ObjectLayer
;
214 CompileLayerT CompileLayer
;
215 std::vector
<std::shared_ptr
<Module
>> modules
;
218 static MonoLLVMJIT
*jit
;
219 static MonoJitMemoryManager
*mono_mm
;
222 mono_llvm_create_ee (LLVMModuleProviderRef MP
, AllocCodeMemoryCb
*alloc_cb
, FunctionEmittedCb
*emitted_cb
, ExceptionTableCb
*exception_cb
, LLVMExecutionEngineRef
*ee
)
224 alloc_code_mem_cb
= alloc_cb
;
226 InitializeNativeTarget ();
227 InitializeNativeTargetAsmPrinter();
230 MonoEHFrameSymbol
= "mono_eh_frame";
233 #if defined(TARGET_AMD64) || defined(TARGET_X86)
234 std::vector
<std::string
> attrs
;
235 // FIXME: Autodetect this
236 attrs
.push_back("sse3");
237 attrs
.push_back("sse4.1");
238 EB
.setMAttrs (attrs
);
240 auto TM
= EB
.selectTarget ();
243 mono_mm
= new MonoJitMemoryManager ();
244 jit
= new MonoLLVMJIT (TM
, mono_mm
);
250 * mono_llvm_compile_method:
252 * Compile METHOD to native code. Compute the addresses of the variables in CALLEE_VARS and store them into
253 * CALLEE_ADDRS. Return the EH frame address in EH_FRAME.
256 mono_llvm_compile_method (MonoEERef mono_ee
, LLVMValueRef method
, int nvars
, LLVMValueRef
*callee_vars
, gpointer
*callee_addrs
, gpointer
*eh_frame
)
258 return jit
->compile (unwrap
<Function
> (method
), nvars
, callee_vars
, callee_addrs
, eh_frame
);
262 mono_llvm_dispose_ee (MonoEERef
*eeref
)
266 #else /* MONO_CROSS_COMPILE or LLVM_API_VERSION < 600 */
269 mono_llvm_set_unhandled_exception_handler (void)
274 mono_llvm_create_ee (LLVMModuleProviderRef MP
, AllocCodeMemoryCb
*alloc_cb
, FunctionEmittedCb
*emitted_cb
, ExceptionTableCb
*exception_cb
, LLVMExecutionEngineRef
*ee
)
276 g_error ("LLVM JIT not supported on this platform.");
281 mono_llvm_compile_method (MonoEERef mono_ee
, LLVMValueRef method
, int nvars
, LLVMValueRef
*callee_vars
, gpointer
*callee_addrs
, gpointer
*eh_frame
)
283 g_assert_not_reached ();
288 mono_llvm_dispose_ee (MonoEERef
*eeref
)
290 g_assert_not_reached ();
293 #endif /* !MONO_CROSS_COMPILE */