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 "llvm/ADT/STLExtras.h"
21 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
27 /// @brief Compile-on-demand layer.
29 /// Modules added to this layer have their calls indirected, and are then
30 /// broken up into a set of single-function modules, each of which is added
31 /// to the layer below in a singleton set. The lower layer can be any layer that
32 /// accepts IR module sets.
34 /// It is expected that this layer will frequently be used on top of a
35 /// LazyEmittingLayer. The combination of the two ensures that each function is
36 /// compiled only when it is first called.
37 template <typename BaseLayerT, typename CompileCallbackMgrT>
38 class CompileOnDemandLayer {
40 /// @brief Lookup helper that provides compatibility with the classic
41 /// static-compilation symbol resolution process.
43 /// The CompileOnDemand (COD) layer splits modules up into multiple
44 /// sub-modules, each held in its own llvm::Module instance, in order to
45 /// support lazy compilation. When a module that contains private symbols is
46 /// broken up symbol linkage changes may be required to enable access to
47 /// "private" data that now resides in a different llvm::Module instance. To
48 /// retain expected symbol resolution behavior for clients of the COD layer,
49 /// the CODScopedLookup class uses a two-tiered lookup system to resolve
50 /// symbols. Lookup first scans sibling modules that were split from the same
51 /// original module (logical-module scoped lookup), then scans all other
52 /// modules that have been added to the lookup scope (logical-dylib scoped
54 class CODScopedLookup {
56 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
57 typedef std::vector<BaseLayerModuleSetHandleT> SiblingHandlesList;
58 typedef std::list<SiblingHandlesList> PseudoDylibModuleSetHandlesList;
61 /// @brief Handle for a logical module.
62 typedef typename PseudoDylibModuleSetHandlesList::iterator LMHandle;
64 /// @brief Construct a scoped lookup.
65 CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
67 virtual ~CODScopedLookup() {}
69 /// @brief Start a new context for a single logical module.
70 LMHandle createLogicalModule() {
71 Handles.push_back(SiblingHandlesList());
72 return std::prev(Handles.end());
75 /// @brief Add a concrete Module's handle to the given logical Module's
77 void addToLogicalModule(LMHandle LMH, BaseLayerModuleSetHandleT H) {
81 /// @brief Remove a logical Module from the CODScopedLookup entirely.
82 void removeLogicalModule(LMHandle LMH) { Handles.erase(LMH); }
84 /// @brief Look up a symbol in this context.
85 JITSymbol findSymbol(LMHandle LMH, const std::string &Name) {
86 if (auto Symbol = findSymbolIn(LMH, Name))
89 for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I)
91 if (auto Symbol = findSymbolIn(I, Name))
97 /// @brief Find an external symbol (via the user supplied SymbolResolver).
98 virtual RuntimeDyld::SymbolInfo
99 externalLookup(const std::string &Name) const = 0;
103 JITSymbol findSymbolIn(LMHandle LMH, const std::string &Name) {
105 if (auto Symbol = BaseLayer.findSymbolIn(H, Name, false))
110 BaseLayerT &BaseLayer;
111 PseudoDylibModuleSetHandlesList Handles;
114 template <typename ResolverPtrT>
115 class CODScopedLookupImpl : public CODScopedLookup {
117 CODScopedLookupImpl(BaseLayerT &BaseLayer, ResolverPtrT Resolver)
118 : CODScopedLookup(BaseLayer), Resolver(std::move(Resolver)) {}
120 RuntimeDyld::SymbolInfo
121 externalLookup(const std::string &Name) const override {
122 return Resolver->findSymbol(Name);
126 ResolverPtrT Resolver;
129 template <typename ResolverPtrT>
130 static std::shared_ptr<CODScopedLookup>
131 createCODScopedLookup(BaseLayerT &BaseLayer,
132 ResolverPtrT Resolver) {
133 typedef CODScopedLookupImpl<ResolverPtrT> Impl;
134 return std::make_shared<Impl>(BaseLayer, std::move(Resolver));
137 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
138 typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT;
140 struct ModuleSetInfo {
141 // Symbol lookup - just one for the whole module set.
142 std::shared_ptr<CODScopedLookup> Lookup;
144 // Logical module handles.
145 std::vector<typename CODScopedLookup::LMHandle> LMHandles;
147 // List of vectors of module set handles:
148 // One vector per logical module - each vector holds the handles for the
149 // exploded modules for that logical module in the base layer.
150 BaseLayerModuleSetHandleListT BaseLayerModuleSetHandles;
152 ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup)
153 : Lookup(std::move(Lookup)) {}
155 void releaseResources(BaseLayerT &BaseLayer) {
156 for (auto LMH : LMHandles)
157 Lookup->removeLogicalModule(LMH);
158 for (auto H : BaseLayerModuleSetHandles)
159 BaseLayer.removeModuleSet(H);
163 typedef std::list<ModuleSetInfo> ModuleSetInfoListT;
166 /// @brief Handle to a set of loaded modules.
167 typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
169 /// @brief Construct a compile-on-demand layer instance.
170 CompileOnDemandLayer(BaseLayerT &BaseLayer, CompileCallbackMgrT &CallbackMgr)
171 : BaseLayer(BaseLayer), CompileCallbackMgr(CallbackMgr) {}
173 /// @brief Add a module to the compile-on-demand layer.
174 template <typename ModuleSetT, typename MemoryManagerPtrT,
175 typename SymbolResolverPtrT>
176 ModuleSetHandleT addModuleSet(ModuleSetT Ms,
177 MemoryManagerPtrT MemMgr,
178 SymbolResolverPtrT Resolver) {
180 assert(MemMgr == nullptr &&
181 "User supplied memory managers not supported with COD yet.");
183 // Create a lookup context and ModuleSetInfo for this module set.
184 // For the purposes of symbol resolution the set Ms will be treated as if
185 // the modules it contained had been linked together as a dylib.
186 auto DylibLookup = createCODScopedLookup(BaseLayer, std::move(Resolver));
188 ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));
189 ModuleSetInfo &MSI = ModuleSetInfos.back();
191 // Process each of the modules in this module set.
193 partitionAndAdd(*M, MSI);
198 /// @brief Remove the module represented by the given handle.
200 /// This will remove all modules in the layers below that were derived from
201 /// the module represented by H.
202 void removeModuleSet(ModuleSetHandleT H) {
203 H->releaseResources(BaseLayer);
204 ModuleSetInfos.erase(H);
207 /// @brief Search for the given named symbol.
208 /// @param Name The name of the symbol to search for.
209 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
210 /// @return A handle for the given named symbol, if it exists.
211 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
212 return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
215 /// @brief Get the address of a symbol provided by this layer, or some layer
217 JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
218 bool ExportedSymbolsOnly) {
220 for (auto &BH : H->BaseLayerModuleSetHandles) {
221 if (auto Symbol = BaseLayer.findSymbolIn(BH, Name, ExportedSymbolsOnly))
229 void partitionAndAdd(Module &M, ModuleSetInfo &MSI) {
230 const char *AddrSuffix = "$orc_addr";
231 const char *BodySuffix = "$orc_body";
233 // We're going to break M up into a bunch of sub-modules, but we want
234 // internal linkage symbols to still resolve sensibly. CODScopedLookup
235 // provides the "logical module" concept to make this work, so create a
236 // new logical module for M.
237 auto DylibLookup = MSI.Lookup;
238 auto LogicalModule = DylibLookup->createLogicalModule();
239 MSI.LMHandles.push_back(LogicalModule);
241 // Partition M into a "globals and stubs" module, a "common symbols" module,
242 // and a list of single-function modules.
243 auto PartitionedModule = fullyPartition(M);
244 auto StubsModule = std::move(PartitionedModule.GlobalVars);
245 auto CommonsModule = std::move(PartitionedModule.Commons);
246 auto FunctionModules = std::move(PartitionedModule.Functions);
248 // Emit the commons stright away.
249 auto CommonHandle = addModule(std::move(CommonsModule), MSI, LogicalModule);
250 BaseLayer.emitAndFinalize(CommonHandle);
252 // Map of definition names to callback-info data structures. We'll use
253 // this to build the compile actions for the stubs below.
254 typedef std::map<std::string,
255 typename CompileCallbackMgrT::CompileCallbackInfo>
257 StubInfoMap StubInfos;
259 // Now we need to take each of the extracted Modules and add them to
260 // base layer. Each Module will be added individually to make sure they
261 // can be compiled separately, and each will get its own lookaside
262 // memory manager that will resolve within this logical module first.
263 for (auto &SubM : FunctionModules) {
265 // Keep track of the stubs we create for this module so that we can set
266 // their compile actions.
267 std::vector<typename StubInfoMap::iterator> NewStubInfos;
269 // Search for function definitions and insert stubs into the stubs
271 for (auto &F : *SubM) {
272 if (F.isDeclaration())
275 std::string Name = F.getName();
276 Function *Proto = StubsModule->getFunction(Name);
277 assert(Proto && "Failed to clone function decl into stubs module.");
279 CompileCallbackMgr.getCompileCallback(Proto->getContext());
280 GlobalVariable *FunctionBodyPointer =
281 createImplPointer(*Proto->getType(), *Proto->getParent(),
283 createIRTypedAddress(*Proto->getFunctionType(),
284 CallbackInfo.getAddress()));
285 makeStub(*Proto, *FunctionBodyPointer);
287 F.setName(Name + BodySuffix);
288 F.setVisibility(GlobalValue::HiddenVisibility);
290 auto KV = std::make_pair(std::move(Name), std::move(CallbackInfo));
291 NewStubInfos.push_back(StubInfos.insert(StubInfos.begin(), KV));
294 auto H = addModule(std::move(SubM), MSI, LogicalModule);
296 // Set the compile actions for this module:
297 for (auto &KVPair : NewStubInfos) {
298 std::string BodyName = Mangle(KVPair->first + BodySuffix,
300 auto &CCInfo = KVPair->second;
301 CCInfo.setCompileAction(
303 return BaseLayer.findSymbolIn(H, BodyName, false).getAddress();
309 // Ok - we've processed all the partitioned modules. Now add the
310 // stubs/globals module and set the update actions.
312 addModule(std::move(StubsModule), MSI, LogicalModule);
314 for (auto &KVPair : StubInfos) {
315 std::string AddrName = Mangle(KVPair.first + AddrSuffix,
317 auto &CCInfo = KVPair.second;
318 CCInfo.setUpdateAction(
319 getLocalFPUpdater(BaseLayer, StubsH, AddrName));
323 // Add the given Module to the base layer using a memory manager that will
324 // perform the appropriate scoped lookup (i.e. will look first with in the
325 // module from which it was extracted, then into the set to which that module
326 // belonged, and finally externally).
327 BaseLayerModuleSetHandleT addModule(
328 std::unique_ptr<Module> M,
330 typename CODScopedLookup::LMHandle LogicalModule) {
332 // Add this module to the JIT with a memory manager that uses the
333 // DylibLookup to resolve symbols.
334 std::vector<std::unique_ptr<Module>> MSet;
335 MSet.push_back(std::move(M));
337 auto DylibLookup = MSI.Lookup;
339 createLambdaResolver(
340 [=](const std::string &Name) {
341 if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name))
342 return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
344 return DylibLookup->externalLookup(Name);
346 [=](const std::string &Name) -> RuntimeDyld::SymbolInfo {
347 if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name))
348 return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
353 BaseLayerModuleSetHandleT H =
354 BaseLayer.addModuleSet(std::move(MSet),
355 make_unique<SectionMemoryManager>(),
356 std::move(Resolver));
357 // Add this module to the logical module lookup.
358 DylibLookup->addToLogicalModule(LogicalModule, H);
359 MSI.BaseLayerModuleSetHandles.push_back(H);
364 static std::string Mangle(StringRef Name, const DataLayout &DL) {
366 std::string MangledName;
368 raw_string_ostream MangledNameStream(MangledName);
369 M.getNameWithPrefix(MangledNameStream, Name);
374 BaseLayerT &BaseLayer;
375 CompileCallbackMgrT &CompileCallbackMgr;
376 ModuleSetInfoListT ModuleSetInfos;
379 } // End namespace orc.
380 } // End namespace llvm.
382 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H