CompileOnDemandLayer.h revision 327952
1//===- CompileOnDemandLayer.h - Compile each function on demand -*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// JIT layer for breaking up modules and inserting callbacks to allow
11// individual functions to be compiled on demand.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
16#define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
17
18#include "llvm/ADT/APInt.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/ADT/Twine.h"
22#include "llvm/ExecutionEngine/JITSymbol.h"
23#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
24#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
25#include "llvm/ExecutionEngine/Orc/OrcError.h"
26#include "llvm/ExecutionEngine/RuntimeDyld.h"
27#include "llvm/IR/Attributes.h"
28#include "llvm/IR/Constant.h"
29#include "llvm/IR/Constants.h"
30#include "llvm/IR/DataLayout.h"
31#include "llvm/IR/Function.h"
32#include "llvm/IR/GlobalAlias.h"
33#include "llvm/IR/GlobalValue.h"
34#include "llvm/IR/GlobalVariable.h"
35#include "llvm/IR/Instruction.h"
36#include "llvm/IR/Mangler.h"
37#include "llvm/IR/Module.h"
38#include "llvm/IR/Type.h"
39#include "llvm/Support/Casting.h"
40#include "llvm/Support/raw_ostream.h"
41#include "llvm/Transforms/Utils/ValueMapper.h"
42#include <algorithm>
43#include <cassert>
44#include <functional>
45#include <iterator>
46#include <list>
47#include <memory>
48#include <set>
49#include <string>
50#include <utility>
51#include <vector>
52
53namespace llvm {
54
55class Value;
56
57namespace orc {
58
59/// @brief Compile-on-demand layer.
60///
61///   When a module is added to this layer a stub is created for each of its
62/// function definitions. The stubs and other global values are immediately
63/// added to the layer below. When a stub is called it triggers the extraction
64/// of the function body from the original module. The extracted body is then
65/// compiled and executed.
66template <typename BaseLayerT,
67          typename CompileCallbackMgrT = JITCompileCallbackManager,
68          typename IndirectStubsMgrT = IndirectStubsManager>
69class CompileOnDemandLayer {
70private:
71  template <typename MaterializerFtor>
72  class LambdaMaterializer final : public ValueMaterializer {
73  public:
74    LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {}
75
76    Value *materialize(Value *V) final { return M(V); }
77
78  private:
79    MaterializerFtor M;
80  };
81
82  template <typename MaterializerFtor>
83  LambdaMaterializer<MaterializerFtor>
84  createLambdaMaterializer(MaterializerFtor M) {
85    return LambdaMaterializer<MaterializerFtor>(std::move(M));
86  }
87
88  using BaseLayerModuleHandleT = typename BaseLayerT::ModuleHandleT;
89
90  // Provide type-erasure for the Modules and MemoryManagers.
91  template <typename ResourceT>
92  class ResourceOwner {
93  public:
94    ResourceOwner() = default;
95    ResourceOwner(const ResourceOwner &) = delete;
96    ResourceOwner &operator=(const ResourceOwner &) = delete;
97    virtual ~ResourceOwner() = default;
98
99    virtual ResourceT& getResource() const = 0;
100  };
101
102  template <typename ResourceT, typename ResourcePtrT>
103  class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
104  public:
105    ResourceOwnerImpl(ResourcePtrT ResourcePtr)
106      : ResourcePtr(std::move(ResourcePtr)) {}
107
108    ResourceT& getResource() const override { return *ResourcePtr; }
109
110  private:
111    ResourcePtrT ResourcePtr;
112  };
113
114  template <typename ResourceT, typename ResourcePtrT>
115  std::unique_ptr<ResourceOwner<ResourceT>>
116  wrapOwnership(ResourcePtrT ResourcePtr) {
117    using RO = ResourceOwnerImpl<ResourceT, ResourcePtrT>;
118    return llvm::make_unique<RO>(std::move(ResourcePtr));
119  }
120
121  class StaticGlobalRenamer {
122  public:
123    StaticGlobalRenamer() = default;
124    StaticGlobalRenamer(StaticGlobalRenamer &&) = default;
125    StaticGlobalRenamer &operator=(StaticGlobalRenamer &&) = default;
126
127    void rename(Module &M) {
128      for (auto &F : M)
129        if (F.hasLocalLinkage())
130          F.setName("$static." + Twine(NextId++));
131      for (auto &G : M.globals())
132        if (G.hasLocalLinkage())
133          G.setName("$static." + Twine(NextId++));
134    }
135
136  private:
137    unsigned NextId = 0;
138  };
139
140  struct LogicalDylib {
141    using SymbolResolverFtor = std::function<JITSymbol(const std::string&)>;
142
143    struct SourceModuleEntry {
144      std::shared_ptr<Module> SourceMod;
145      std::set<Function*> StubsToClone;
146    };
147
148    using SourceModulesList = std::vector<SourceModuleEntry>;
149    using SourceModuleHandle = typename SourceModulesList::size_type;
150
151    SourceModuleHandle
152    addSourceModule(std::shared_ptr<Module> M) {
153      SourceModuleHandle H = SourceModules.size();
154      SourceModules.push_back(SourceModuleEntry());
155      SourceModules.back().SourceMod = std::move(M);
156      return H;
157    }
158
159    Module& getSourceModule(SourceModuleHandle H) {
160      return *SourceModules[H].SourceMod;
161    }
162
163    std::set<Function*>& getStubsToClone(SourceModuleHandle H) {
164      return SourceModules[H].StubsToClone;
165    }
166
167    JITSymbol findSymbol(BaseLayerT &BaseLayer, const std::string &Name,
168                         bool ExportedSymbolsOnly) {
169      if (auto Sym = StubsMgr->findStub(Name, ExportedSymbolsOnly))
170        return Sym;
171      for (auto BLH : BaseLayerHandles)
172        if (auto Sym = BaseLayer.findSymbolIn(BLH, Name, ExportedSymbolsOnly))
173          return Sym;
174        else if (auto Err = Sym.takeError())
175          return std::move(Err);
176      return nullptr;
177    }
178
179    Error removeModulesFromBaseLayer(BaseLayerT &BaseLayer) {
180      for (auto &BLH : BaseLayerHandles)
181        if (auto Err = BaseLayer.removeModule(BLH))
182          return Err;
183      return Error::success();
184    }
185
186    std::shared_ptr<JITSymbolResolver> ExternalSymbolResolver;
187    std::unique_ptr<IndirectStubsMgrT> StubsMgr;
188    StaticGlobalRenamer StaticRenamer;
189    SourceModulesList SourceModules;
190    std::vector<BaseLayerModuleHandleT> BaseLayerHandles;
191  };
192
193  using LogicalDylibList = std::list<LogicalDylib>;
194
195public:
196
197  /// @brief Handle to loaded module.
198  using ModuleHandleT = typename LogicalDylibList::iterator;
199
200  /// @brief Module partitioning functor.
201  using PartitioningFtor = std::function<std::set<Function*>(Function&)>;
202
203  /// @brief Builder for IndirectStubsManagers.
204  using IndirectStubsManagerBuilderT =
205      std::function<std::unique_ptr<IndirectStubsMgrT>()>;
206
207  /// @brief Construct a compile-on-demand layer instance.
208  CompileOnDemandLayer(BaseLayerT &BaseLayer, PartitioningFtor Partition,
209                       CompileCallbackMgrT &CallbackMgr,
210                       IndirectStubsManagerBuilderT CreateIndirectStubsManager,
211                       bool CloneStubsIntoPartitions = true)
212      : BaseLayer(BaseLayer), Partition(std::move(Partition)),
213        CompileCallbackMgr(CallbackMgr),
214        CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)),
215        CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
216
217  ~CompileOnDemandLayer() {
218    // FIXME: Report error on log.
219    while (!LogicalDylibs.empty())
220      consumeError(removeModule(LogicalDylibs.begin()));
221  }
222
223  /// @brief Add a module to the compile-on-demand layer.
224  Expected<ModuleHandleT>
225  addModule(std::shared_ptr<Module> M,
226            std::shared_ptr<JITSymbolResolver> Resolver) {
227
228    LogicalDylibs.push_back(LogicalDylib());
229    auto &LD = LogicalDylibs.back();
230    LD.ExternalSymbolResolver = std::move(Resolver);
231    LD.StubsMgr = CreateIndirectStubsManager();
232
233    // Process each of the modules in this module set.
234    if (auto Err = addLogicalModule(LD, std::move(M)))
235      return std::move(Err);
236
237    return std::prev(LogicalDylibs.end());
238  }
239
240  /// @brief Add extra modules to an existing logical module.
241  Error addExtraModule(ModuleHandleT H, std::shared_ptr<Module> M) {
242    return addLogicalModule(*H, std::move(M));
243  }
244
245  /// @brief Remove the module represented by the given handle.
246  ///
247  ///   This will remove all modules in the layers below that were derived from
248  /// the module represented by H.
249  Error removeModule(ModuleHandleT H) {
250    auto Err = H->removeModulesFromBaseLayer(BaseLayer);
251    LogicalDylibs.erase(H);
252    return Err;
253  }
254
255  /// @brief Search for the given named symbol.
256  /// @param Name The name of the symbol to search for.
257  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
258  /// @return A handle for the given named symbol, if it exists.
259  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
260    for (auto LDI = LogicalDylibs.begin(), LDE = LogicalDylibs.end();
261         LDI != LDE; ++LDI) {
262      if (auto Sym = LDI->StubsMgr->findStub(Name, ExportedSymbolsOnly))
263        return Sym;
264      if (auto Sym = findSymbolIn(LDI, Name, ExportedSymbolsOnly))
265        return Sym;
266      else if (auto Err = Sym.takeError())
267        return std::move(Err);
268    }
269    return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
270  }
271
272  /// @brief Get the address of a symbol provided by this layer, or some layer
273  ///        below this one.
274  JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name,
275                         bool ExportedSymbolsOnly) {
276    return H->findSymbol(BaseLayer, Name, ExportedSymbolsOnly);
277  }
278
279  /// @brief Update the stub for the given function to point at FnBodyAddr.
280  /// This can be used to support re-optimization.
281  /// @return true if the function exists and the stub is updated, false
282  ///         otherwise.
283  //
284  // FIXME: We should track and free associated resources (unused compile
285  //        callbacks, uncompiled IR, and no-longer-needed/reachable function
286  //        implementations).
287  Error updatePointer(std::string FuncName, JITTargetAddress FnBodyAddr) {
288    //Find out which logical dylib contains our symbol
289    auto LDI = LogicalDylibs.begin();
290    for (auto LDE = LogicalDylibs.end(); LDI != LDE; ++LDI) {
291      if (auto LMResources =
292            LDI->getLogicalModuleResourcesForSymbol(FuncName, false)) {
293        Module &SrcM = LMResources->SourceModule->getResource();
294        std::string CalledFnName = mangle(FuncName, SrcM.getDataLayout());
295        if (auto Err = LMResources->StubsMgr->updatePointer(CalledFnName,
296                                                            FnBodyAddr))
297          return Err;
298        return Error::success();
299      }
300    }
301    return make_error<JITSymbolNotFound>(FuncName);
302  }
303
304private:
305
306  Error addLogicalModule(LogicalDylib &LD, std::shared_ptr<Module> SrcMPtr) {
307
308    // Rename all static functions / globals to $static.X :
309    // This will unique the names across all modules in the logical dylib,
310    // simplifying symbol lookup.
311    LD.StaticRenamer.rename(*SrcMPtr);
312
313    // Bump the linkage and rename any anonymous/privote members in SrcM to
314    // ensure that everything will resolve properly after we partition SrcM.
315    makeAllSymbolsExternallyAccessible(*SrcMPtr);
316
317    // Create a logical module handle for SrcM within the logical dylib.
318    Module &SrcM = *SrcMPtr;
319    auto LMId = LD.addSourceModule(std::move(SrcMPtr));
320
321    // Create stub functions.
322    const DataLayout &DL = SrcM.getDataLayout();
323    {
324      typename IndirectStubsMgrT::StubInitsMap StubInits;
325      for (auto &F : SrcM) {
326        // Skip declarations.
327        if (F.isDeclaration())
328          continue;
329
330        // Skip weak functions for which we already have definitions.
331        auto MangledName = mangle(F.getName(), DL);
332        if (F.hasWeakLinkage() || F.hasLinkOnceLinkage()) {
333          if (auto Sym = LD.findSymbol(BaseLayer, MangledName, false))
334            continue;
335          else if (auto Err = Sym.takeError())
336            return std::move(Err);
337        }
338
339        // Record all functions defined by this module.
340        if (CloneStubsIntoPartitions)
341          LD.getStubsToClone(LMId).insert(&F);
342
343        // Create a callback, associate it with the stub for the function,
344        // and set the compile action to compile the partition containing the
345        // function.
346        if (auto CCInfoOrErr = CompileCallbackMgr.getCompileCallback()) {
347          auto &CCInfo = *CCInfoOrErr;
348          StubInits[MangledName] =
349            std::make_pair(CCInfo.getAddress(),
350                           JITSymbolFlags::fromGlobalValue(F));
351          CCInfo.setCompileAction([this, &LD, LMId, &F]() -> JITTargetAddress {
352              if (auto FnImplAddrOrErr = this->extractAndCompile(LD, LMId, F))
353                return *FnImplAddrOrErr;
354              else {
355                // FIXME: Report error, return to 'abort' or something similar.
356                consumeError(FnImplAddrOrErr.takeError());
357                return 0;
358              }
359            });
360        } else
361          return CCInfoOrErr.takeError();
362      }
363
364      if (auto Err = LD.StubsMgr->createStubs(StubInits))
365        return Err;
366    }
367
368    // If this module doesn't contain any globals, aliases, or module flags then
369    // we can bail out early and avoid the overhead of creating and managing an
370    // empty globals module.
371    if (SrcM.global_empty() && SrcM.alias_empty() &&
372        !SrcM.getModuleFlagsMetadata())
373      return Error::success();
374
375    // Create the GlobalValues module.
376    auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(),
377                                          SrcM.getContext());
378    GVsM->setDataLayout(DL);
379
380    ValueToValueMapTy VMap;
381
382    // Clone global variable decls.
383    for (auto &GV : SrcM.globals())
384      if (!GV.isDeclaration() && !VMap.count(&GV))
385        cloneGlobalVariableDecl(*GVsM, GV, &VMap);
386
387    // And the aliases.
388    for (auto &A : SrcM.aliases())
389      if (!VMap.count(&A))
390        cloneGlobalAliasDecl(*GVsM, A, VMap);
391
392    // Clone the module flags.
393    cloneModuleFlagsMetadata(*GVsM, SrcM, VMap);
394
395    // Now we need to clone the GV and alias initializers.
396
397    // Initializers may refer to functions declared (but not defined) in this
398    // module. Build a materializer to clone decls on demand.
399    Error MaterializerErrors = Error::success();
400    auto Materializer = createLambdaMaterializer(
401      [&LD, &GVsM, &MaterializerErrors](Value *V) -> Value* {
402        if (auto *F = dyn_cast<Function>(V)) {
403          // Decls in the original module just get cloned.
404          if (F->isDeclaration())
405            return cloneFunctionDecl(*GVsM, *F);
406
407          // Definitions in the original module (which we have emitted stubs
408          // for at this point) get turned into a constant alias to the stub
409          // instead.
410          const DataLayout &DL = GVsM->getDataLayout();
411          std::string FName = mangle(F->getName(), DL);
412          unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType());
413          JITTargetAddress StubAddr = 0;
414
415          // Get the address for the stub. If we encounter an error while
416          // doing so, stash it in the MaterializerErrors variable and use a
417          // null address as a placeholder.
418          if (auto StubSym = LD.StubsMgr->findStub(FName, false)) {
419            if (auto StubAddrOrErr = StubSym.getAddress())
420              StubAddr = *StubAddrOrErr;
421            else
422              MaterializerErrors = joinErrors(std::move(MaterializerErrors),
423                                              StubAddrOrErr.takeError());
424          }
425
426          ConstantInt *StubAddrCI =
427            ConstantInt::get(GVsM->getContext(), APInt(PtrBitWidth, StubAddr));
428          Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr,
429                                                 StubAddrCI, F->getType());
430          return GlobalAlias::create(F->getFunctionType(),
431                                     F->getType()->getAddressSpace(),
432                                     F->getLinkage(), F->getName(),
433                                     Init, GVsM.get());
434        }
435        // else....
436        return nullptr;
437      });
438
439    // Clone the global variable initializers.
440    for (auto &GV : SrcM.globals())
441      if (!GV.isDeclaration())
442        moveGlobalVariableInitializer(GV, VMap, &Materializer);
443
444    // Clone the global alias initializers.
445    for (auto &A : SrcM.aliases()) {
446      auto *NewA = cast<GlobalAlias>(VMap[&A]);
447      assert(NewA && "Alias not cloned?");
448      Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr,
449                             &Materializer);
450      NewA->setAliasee(cast<Constant>(Init));
451    }
452
453    if (MaterializerErrors)
454      return MaterializerErrors;
455
456    // Build a resolver for the globals module and add it to the base layer.
457    auto GVsResolver = createLambdaResolver(
458        [this, &LD](const std::string &Name) -> JITSymbol {
459          if (auto Sym = LD.StubsMgr->findStub(Name, false))
460            return Sym;
461          if (auto Sym = LD.findSymbol(BaseLayer, Name, false))
462            return Sym;
463          else if (auto Err = Sym.takeError())
464            return std::move(Err);
465          return LD.ExternalSymbolResolver->findSymbolInLogicalDylib(Name);
466        },
467        [&LD](const std::string &Name) {
468          return LD.ExternalSymbolResolver->findSymbol(Name);
469        });
470
471    if (auto GVsHOrErr =
472          BaseLayer.addModule(std::move(GVsM), std::move(GVsResolver)))
473      LD.BaseLayerHandles.push_back(*GVsHOrErr);
474    else
475      return GVsHOrErr.takeError();
476
477    return Error::success();
478  }
479
480  static std::string mangle(StringRef Name, const DataLayout &DL) {
481    std::string MangledName;
482    {
483      raw_string_ostream MangledNameStream(MangledName);
484      Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
485    }
486    return MangledName;
487  }
488
489  Expected<JITTargetAddress>
490  extractAndCompile(LogicalDylib &LD,
491                    typename LogicalDylib::SourceModuleHandle LMId,
492                    Function &F) {
493    Module &SrcM = LD.getSourceModule(LMId);
494
495    // If F is a declaration we must already have compiled it.
496    if (F.isDeclaration())
497      return 0;
498
499    // Grab the name of the function being called here.
500    std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout());
501
502    JITTargetAddress CalledAddr = 0;
503    auto Part = Partition(F);
504    if (auto PartHOrErr = emitPartition(LD, LMId, Part)) {
505      auto &PartH = *PartHOrErr;
506      for (auto *SubF : Part) {
507        std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout());
508        if (auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false)) {
509          if (auto FnBodyAddrOrErr = FnBodySym.getAddress()) {
510            JITTargetAddress FnBodyAddr = *FnBodyAddrOrErr;
511
512            // If this is the function we're calling record the address so we can
513            // return it from this function.
514            if (SubF == &F)
515              CalledAddr = FnBodyAddr;
516
517            // Update the function body pointer for the stub.
518            if (auto EC = LD.StubsMgr->updatePointer(FnName, FnBodyAddr))
519              return 0;
520
521          } else
522            return FnBodyAddrOrErr.takeError();
523        } else if (auto Err = FnBodySym.takeError())
524          return std::move(Err);
525        else
526          llvm_unreachable("Function not emitted for partition");
527      }
528
529      LD.BaseLayerHandles.push_back(PartH);
530    } else
531      return PartHOrErr.takeError();
532
533    return CalledAddr;
534  }
535
536  template <typename PartitionT>
537  Expected<BaseLayerModuleHandleT>
538  emitPartition(LogicalDylib &LD,
539                typename LogicalDylib::SourceModuleHandle LMId,
540                const PartitionT &Part) {
541    Module &SrcM = LD.getSourceModule(LMId);
542
543    // Create the module.
544    std::string NewName = SrcM.getName();
545    for (auto *F : Part) {
546      NewName += ".";
547      NewName += F->getName();
548    }
549
550    auto M = llvm::make_unique<Module>(NewName, SrcM.getContext());
551    M->setDataLayout(SrcM.getDataLayout());
552    ValueToValueMapTy VMap;
553
554    auto Materializer = createLambdaMaterializer([&LD, &LMId,
555                                                  &M](Value *V) -> Value * {
556      if (auto *GV = dyn_cast<GlobalVariable>(V))
557        return cloneGlobalVariableDecl(*M, *GV);
558
559      if (auto *F = dyn_cast<Function>(V)) {
560        // Check whether we want to clone an available_externally definition.
561        if (!LD.getStubsToClone(LMId).count(F))
562          return cloneFunctionDecl(*M, *F);
563
564        // Ok - we want an inlinable stub. For that to work we need a decl
565        // for the stub pointer.
566        auto *StubPtr = createImplPointer(*F->getType(), *M,
567                                          F->getName() + "$stub_ptr", nullptr);
568        auto *ClonedF = cloneFunctionDecl(*M, *F);
569        makeStub(*ClonedF, *StubPtr);
570        ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage);
571        ClonedF->addFnAttr(Attribute::AlwaysInline);
572        return ClonedF;
573      }
574
575      if (auto *A = dyn_cast<GlobalAlias>(V)) {
576        auto *Ty = A->getValueType();
577        if (Ty->isFunctionTy())
578          return Function::Create(cast<FunctionType>(Ty),
579                                  GlobalValue::ExternalLinkage, A->getName(),
580                                  M.get());
581
582        return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage,
583                                  nullptr, A->getName(), nullptr,
584                                  GlobalValue::NotThreadLocal,
585                                  A->getType()->getAddressSpace());
586      }
587
588      return nullptr;
589    });
590
591    // Create decls in the new module.
592    for (auto *F : Part)
593      cloneFunctionDecl(*M, *F, &VMap);
594
595    // Move the function bodies.
596    for (auto *F : Part)
597      moveFunctionBody(*F, VMap, &Materializer);
598
599    // Create memory manager and symbol resolver.
600    auto Resolver = createLambdaResolver(
601        [this, &LD](const std::string &Name) -> JITSymbol {
602          if (auto Sym = LD.findSymbol(BaseLayer, Name, false))
603            return Sym;
604          else if (auto Err = Sym.takeError())
605            return std::move(Err);
606          return LD.ExternalSymbolResolver->findSymbolInLogicalDylib(Name);
607        },
608        [&LD](const std::string &Name) {
609          return LD.ExternalSymbolResolver->findSymbol(Name);
610        });
611
612    return BaseLayer.addModule(std::move(M), std::move(Resolver));
613  }
614
615  BaseLayerT &BaseLayer;
616  PartitioningFtor Partition;
617  CompileCallbackMgrT &CompileCallbackMgr;
618  IndirectStubsManagerBuilderT CreateIndirectStubsManager;
619
620  LogicalDylibList LogicalDylibs;
621  bool CloneStubsIntoPartitions;
622};
623
624} // end namespace orc
625
626} // end namespace llvm
627
628#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
629