1 //===- CompileOnDemandLayer.h - Compile each function on demand -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // JIT layer for breaking up modules and inserting callbacks to allow
11 // individual functions to be compiled on demand.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
16 #define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
18 #include "IndirectionUtils.h"
19 #include "LambdaResolver.h"
20 #include "LogicalDylib.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
23 #include "llvm/Transforms/Utils/Cloning.h"
27 #include "llvm/Support/Debug.h"
32 /// @brief Compile-on-demand layer.
34 /// When a module is added to this layer a stub is created for each of its
35 /// function definitions. The stubs and other global values are immediately
36 /// added to the layer below. When a stub is called it triggers the extraction
37 /// of the function body from the original module. The extracted body is then
38 /// compiled and executed.
39 template <typename BaseLayerT, typename CompileCallbackMgrT,
40 typename PartitioningFtor =
41 std::function<std::set<Function*>(Function&)>>
42 class CompileOnDemandLayer {
45 // Utility class for MapValue. Only materializes declarations for global
47 class GlobalDeclMaterializer : public ValueMaterializer {
49 typedef std::set<const Function*> StubSet;
51 GlobalDeclMaterializer(Module &Dst, const StubSet *StubsToClone = nullptr)
52 : Dst(Dst), StubsToClone(StubsToClone) {}
54 Value* materializeValueFor(Value *V) final {
55 if (auto *GV = dyn_cast<GlobalVariable>(V))
56 return cloneGlobalVariableDecl(Dst, *GV);
57 else if (auto *F = dyn_cast<Function>(V)) {
58 auto *ClonedF = cloneFunctionDecl(Dst, *F);
59 if (StubsToClone && StubsToClone->count(F)) {
60 GlobalVariable *FnBodyPtr =
61 createImplPointer(*ClonedF->getType(), *ClonedF->getParent(),
62 ClonedF->getName() + "$orc_addr", nullptr);
63 makeStub(*ClonedF, *FnBodyPtr);
64 ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage);
65 ClonedF->addFnAttr(Attribute::AlwaysInline);
74 const StubSet *StubsToClone;
77 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
79 struct LogicalModuleResources {
80 std::shared_ptr<Module> SourceModule;
81 std::set<const Function*> StubsToClone;
84 struct LogicalDylibResources {
85 typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)>
87 SymbolResolverFtor ExternalSymbolResolver;
88 PartitioningFtor Partitioner;
91 typedef LogicalDylib<BaseLayerT, LogicalModuleResources,
92 LogicalDylibResources> CODLogicalDylib;
94 typedef typename CODLogicalDylib::LogicalModuleHandle LogicalModuleHandle;
95 typedef std::list<CODLogicalDylib> LogicalDylibList;
98 /// @brief Handle to a set of loaded modules.
99 typedef typename LogicalDylibList::iterator ModuleSetHandleT;
101 /// @brief Construct a compile-on-demand layer instance.
102 CompileOnDemandLayer(BaseLayerT &BaseLayer, CompileCallbackMgrT &CallbackMgr,
103 bool CloneStubsIntoPartitions)
104 : BaseLayer(BaseLayer), CompileCallbackMgr(CallbackMgr),
105 CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
107 /// @brief Add a module to the compile-on-demand layer.
108 template <typename ModuleSetT, typename MemoryManagerPtrT,
109 typename SymbolResolverPtrT>
110 ModuleSetHandleT addModuleSet(ModuleSetT Ms,
111 MemoryManagerPtrT MemMgr,
112 SymbolResolverPtrT Resolver) {
114 assert(MemMgr == nullptr &&
115 "User supplied memory managers not supported with COD yet.");
117 LogicalDylibs.push_back(CODLogicalDylib(BaseLayer));
118 auto &LDResources = LogicalDylibs.back().getDylibResources();
120 LDResources.ExternalSymbolResolver =
121 [Resolver](const std::string &Name) {
122 return Resolver->findSymbol(Name);
125 LDResources.Partitioner =
127 std::set<Function*> Partition;
128 Partition.insert(&F);
132 // Process each of the modules in this module set.
134 addLogicalModule(LogicalDylibs.back(),
135 std::shared_ptr<Module>(std::move(M)));
137 return std::prev(LogicalDylibs.end());
140 /// @brief Remove the module represented by the given handle.
142 /// This will remove all modules in the layers below that were derived from
143 /// the module represented by H.
144 void removeModuleSet(ModuleSetHandleT H) {
145 LogicalDylibs.erase(H);
148 /// @brief Search for the given named symbol.
149 /// @param Name The name of the symbol to search for.
150 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
151 /// @return A handle for the given named symbol, if it exists.
152 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
153 return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
156 /// @brief Get the address of a symbol provided by this layer, or some layer
158 JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
159 bool ExportedSymbolsOnly) {
160 return H->findSymbol(Name, ExportedSymbolsOnly);
165 void addLogicalModule(CODLogicalDylib &LD, std::shared_ptr<Module> SrcM) {
167 // Bump the linkage and rename any anonymous/privote members in SrcM to
168 // ensure that everything will resolve properly after we partition SrcM.
169 makeAllSymbolsExternallyAccessible(*SrcM);
171 // Create a logical module handle for SrcM within the logical dylib.
172 auto LMH = LD.createLogicalModule();
173 auto &LMResources = LD.getLogicalModuleResources(LMH);
174 LMResources.SourceModule = SrcM;
176 // Create the GVs-and-stubs module.
177 auto GVsAndStubsM = llvm::make_unique<Module>(
178 (SrcM->getName() + ".globals_and_stubs").str(),
180 GVsAndStubsM->setDataLayout(SrcM->getDataLayout());
181 ValueToValueMapTy VMap;
183 // Process module and create stubs.
184 // We create the stubs before copying the global variables as we know the
185 // stubs won't refer to any globals (they only refer to their implementation
186 // pointer) so there's no ordering/value-mapping issues.
187 for (auto &F : *SrcM) {
189 // Skip declarations.
190 if (F.isDeclaration())
193 // Record all functions defined by this module.
194 if (CloneStubsIntoPartitions)
195 LMResources.StubsToClone.insert(&F);
197 // For each definition: create a callback, a stub, and a function body
198 // pointer. Initialize the function body pointer to point at the callback,
199 // and set the callback to compile the function body.
200 auto CCInfo = CompileCallbackMgr.getCompileCallback(SrcM->getContext());
201 Function *StubF = cloneFunctionDecl(*GVsAndStubsM, F, &VMap);
202 GlobalVariable *FnBodyPtr =
203 createImplPointer(*StubF->getType(), *StubF->getParent(),
204 StubF->getName() + "$orc_addr",
205 createIRTypedAddress(*StubF->getFunctionType(),
206 CCInfo.getAddress()));
207 makeStub(*StubF, *FnBodyPtr);
208 CCInfo.setCompileAction(
209 [this, &LD, LMH, &F]() {
210 return this->extractAndCompile(LD, LMH, F);
214 // Now clone the global variable declarations.
215 GlobalDeclMaterializer GDMat(*GVsAndStubsM);
216 for (auto &GV : SrcM->globals())
217 if (!GV.isDeclaration())
218 cloneGlobalVariableDecl(*GVsAndStubsM, GV, &VMap);
221 for (auto &Alias : SrcM->aliases())
222 cloneGlobalAlias(*GVsAndStubsM, Alias, VMap, &GDMat);
224 // Then clone the initializers.
225 for (auto &GV : SrcM->globals())
226 if (!GV.isDeclaration())
227 moveGlobalVariableInitializer(GV, VMap, &GDMat);
229 // Build a resolver for the stubs module and add it to the base layer.
230 auto GVsAndStubsResolver = createLambdaResolver(
231 [&LD](const std::string &Name) {
232 return LD.getDylibResources().ExternalSymbolResolver(Name);
234 [](const std::string &Name) {
235 return RuntimeDyld::SymbolInfo(nullptr);
238 std::vector<std::unique_ptr<Module>> GVsAndStubsMSet;
239 GVsAndStubsMSet.push_back(std::move(GVsAndStubsM));
241 BaseLayer.addModuleSet(std::move(GVsAndStubsMSet),
242 llvm::make_unique<SectionMemoryManager>(),
243 std::move(GVsAndStubsResolver));
244 LD.addToLogicalModule(LMH, GVsAndStubsH);
247 static std::string Mangle(StringRef Name, const DataLayout &DL) {
248 std::string MangledName;
250 raw_string_ostream MangledNameStream(MangledName);
251 Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
256 TargetAddress extractAndCompile(CODLogicalDylib &LD,
257 LogicalModuleHandle LMH,
259 Module &SrcM = *LD.getLogicalModuleResources(LMH).SourceModule;
261 // If F is a declaration we must already have compiled it.
262 if (F.isDeclaration())
265 // Grab the name of the function being called here.
266 std::string CalledFnName = Mangle(F.getName(), SrcM.getDataLayout());
268 auto Partition = LD.getDylibResources().Partitioner(F);
269 auto PartitionH = emitPartition(LD, LMH, Partition);
271 TargetAddress CalledAddr = 0;
272 for (auto *SubF : Partition) {
273 std::string FName = SubF->getName();
275 BaseLayer.findSymbolIn(PartitionH, Mangle(FName, SrcM.getDataLayout()),
278 BaseLayer.findSymbolIn(*LD.moduleHandlesBegin(LMH),
279 Mangle(FName + "$orc_addr",
280 SrcM.getDataLayout()),
282 assert(FnBodySym && "Couldn't find function body.");
283 assert(FnPtrSym && "Couldn't find function body pointer.");
285 TargetAddress FnBodyAddr = FnBodySym.getAddress();
286 void *FnPtrAddr = reinterpret_cast<void*>(
287 static_cast<uintptr_t>(FnPtrSym.getAddress()));
289 // If this is the function we're calling record the address so we can
290 // return it from this function.
292 CalledAddr = FnBodyAddr;
294 memcpy(FnPtrAddr, &FnBodyAddr, sizeof(uintptr_t));
300 template <typename PartitionT>
301 BaseLayerModuleSetHandleT emitPartition(CODLogicalDylib &LD,
302 LogicalModuleHandle LMH,
303 const PartitionT &Partition) {
304 auto &LMResources = LD.getLogicalModuleResources(LMH);
305 Module &SrcM = *LMResources.SourceModule;
307 // Create the module.
308 std::string NewName = SrcM.getName();
309 for (auto *F : Partition) {
311 NewName += F->getName();
314 auto M = llvm::make_unique<Module>(NewName, SrcM.getContext());
315 M->setDataLayout(SrcM.getDataLayout());
316 ValueToValueMapTy VMap;
317 GlobalDeclMaterializer GDM(*M, &LMResources.StubsToClone);
319 // Create decls in the new module.
320 for (auto *F : Partition)
321 cloneFunctionDecl(*M, *F, &VMap);
323 // Move the function bodies.
324 for (auto *F : Partition)
325 moveFunctionBody(*F, VMap, &GDM);
327 // Create memory manager and symbol resolver.
328 auto MemMgr = llvm::make_unique<SectionMemoryManager>();
329 auto Resolver = createLambdaResolver(
330 [this, &LD, LMH](const std::string &Name) {
331 if (auto Symbol = LD.findSymbolInternally(LMH, Name))
332 return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
334 return LD.getDylibResources().ExternalSymbolResolver(Name);
336 [this, &LD, LMH](const std::string &Name) {
337 if (auto Symbol = LD.findSymbolInternally(LMH, Name))
338 return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
340 return RuntimeDyld::SymbolInfo(nullptr);
342 std::vector<std::unique_ptr<Module>> PartMSet;
343 PartMSet.push_back(std::move(M));
344 return BaseLayer.addModuleSet(std::move(PartMSet), std::move(MemMgr),
345 std::move(Resolver));
348 BaseLayerT &BaseLayer;
349 CompileCallbackMgrT &CompileCallbackMgr;
350 LogicalDylibList LogicalDylibs;
351 bool CloneStubsIntoPartitions;
354 } // End namespace orc.
355 } // End namespace llvm.
357 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H