LCOV - code coverage report
Current view: top level - include/llvm/ExecutionEngine/Orc - RTDyldObjectLinkingLayer.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 78 91 85.7 %
Date: 2018-10-16 05:50:02 Functions: 11 15 73.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking  ---*- 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             : // Contains the definition for an RTDyld-based, in-process object linking layer.
      11             : //
      12             : //===----------------------------------------------------------------------===//
      13             : 
      14             : #ifndef LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
      15             : #define LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H
      16             : 
      17             : #include "llvm/ADT/STLExtras.h"
      18             : #include "llvm/ADT/StringMap.h"
      19             : #include "llvm/ADT/StringRef.h"
      20             : #include "llvm/ExecutionEngine/JITSymbol.h"
      21             : #include "llvm/ExecutionEngine/Orc/Core.h"
      22             : #include "llvm/ExecutionEngine/Orc/Layer.h"
      23             : #include "llvm/ExecutionEngine/Orc/Legacy.h"
      24             : #include "llvm/ExecutionEngine/RuntimeDyld.h"
      25             : #include "llvm/Object/ObjectFile.h"
      26             : #include "llvm/Support/Error.h"
      27             : #include <algorithm>
      28             : #include <cassert>
      29             : #include <functional>
      30             : #include <list>
      31             : #include <memory>
      32             : #include <string>
      33             : #include <utility>
      34             : #include <vector>
      35             : 
      36             : namespace llvm {
      37             : namespace orc {
      38             : 
      39             : class RTDyldObjectLinkingLayer2 : public ObjectLayer {
      40             : public:
      41             :   /// Functor for receiving object-loaded notifications.
      42             :   using NotifyLoadedFunction =
      43             :       std::function<void(VModuleKey, const object::ObjectFile &Obj,
      44             :                          const RuntimeDyld::LoadedObjectInfo &)>;
      45             : 
      46             :   /// Functor for receiving finalization notifications.
      47             :   using NotifyEmittedFunction = std::function<void(VModuleKey)>;
      48             : 
      49             :   using GetMemoryManagerFunction =
      50             :       std::function<std::unique_ptr<RuntimeDyld::MemoryManager>(VModuleKey)>;
      51             : 
      52             :   /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
      53             :   ///        and NotifyEmitted functors.
      54             :   RTDyldObjectLinkingLayer2(
      55             :       ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager,
      56             :       NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(),
      57             :       NotifyEmittedFunction NotifyEmitted = NotifyEmittedFunction());
      58             : 
      59             :   /// Emit the object.
      60             :   void emit(MaterializationResponsibility R, VModuleKey K,
      61             :             std::unique_ptr<MemoryBuffer> O) override;
      62             : 
      63             :   /// Set the 'ProcessAllSections' flag.
      64             :   ///
      65             :   /// If set to true, all sections in each object file will be allocated using
      66             :   /// the memory manager, rather than just the sections required for execution.
      67             :   ///
      68             :   /// This is kludgy, and may be removed in the future.
      69             :   RTDyldObjectLinkingLayer2 &setProcessAllSections(bool ProcessAllSections) {
      70           2 :     this->ProcessAllSections = ProcessAllSections;
      71             :     return *this;
      72             :   }
      73             : 
      74             :   /// Instructs this RTDyldLinkingLayer2 instance to override the symbol flags
      75             :   /// returned by RuntimeDyld for any given object file with the flags supplied
      76             :   /// by the MaterializationResponsibility instance. This is a workaround to
      77             :   /// support symbol visibility in COFF, which does not use the libObject's
      78             :   /// SF_Exported flag. Use only when generating / adding COFF object files.
      79             :   ///
      80             :   /// FIXME: We should be able to remove this if/when COFF properly tracks
      81             :   /// exported symbols.
      82             :   RTDyldObjectLinkingLayer2 &
      83             :   setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) {
      84           1 :     this->OverrideObjectFlags = OverrideObjectFlags;
      85             :     return *this;
      86             :   }
      87             : 
      88             :   /// If set, this RTDyldObjectLinkingLayer2 instance will claim responsibility
      89             :   /// for any symbols provided by a given object file that were not already in
      90             :   /// the MaterializationResponsibility instance. Setting this flag allows
      91             :   /// higher-level program representations (e.g. LLVM IR) to be added based on
      92             :   /// only a subset of the symbols they provide, without having to write
      93             :   /// intervening layers to scan and add the additional symbols. This trades
      94             :   /// diagnostic quality for convenience however: If all symbols are enumerated
      95             :   /// up-front then clashes can be detected and reported early (and usually
      96             :   /// deterministically). If this option is set, clashes for the additional
      97             :   /// symbols may not be detected until late, and detection may depend on
      98             :   /// the flow of control through JIT'd code. Use with care.
      99             :   RTDyldObjectLinkingLayer2 &
     100             :   setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) {
     101           1 :     this->AutoClaimObjectSymbols = AutoClaimObjectSymbols;
     102             :     return *this;
     103             :   }
     104             : 
     105             : private:
     106             :   Error onObjLoad(VModuleKey K, MaterializationResponsibility &R,
     107             :                   object::ObjectFile &Obj,
     108             :                   std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,
     109             :                   std::map<StringRef, JITEvaluatedSymbol> Resolved,
     110             :                   std::set<StringRef> &InternalSymbols);
     111             : 
     112             :   void onObjEmit(VModuleKey K, MaterializationResponsibility &R, Error Err);
     113             : 
     114             :   mutable std::mutex RTDyldLayerMutex;
     115             :   GetMemoryManagerFunction GetMemoryManager;
     116             :   NotifyLoadedFunction NotifyLoaded;
     117             :   NotifyEmittedFunction NotifyEmitted;
     118             :   bool ProcessAllSections = false;
     119             :   bool OverrideObjectFlags = false;
     120             :   bool AutoClaimObjectSymbols = false;
     121             :   std::map<VModuleKey, std::shared_ptr<RuntimeDyld::MemoryManager>> MemMgrs;
     122             : };
     123             : 
     124             : class RTDyldObjectLinkingLayerBase {
     125             : public:
     126             :   using ObjectPtr = std::unique_ptr<MemoryBuffer>;
     127             : 
     128             : protected:
     129             : 
     130             :   /// Holds an object to be allocated/linked as a unit in the JIT.
     131             :   ///
     132             :   /// An instance of this class will be created for each object added
     133             :   /// via JITObjectLayer::addObject. Deleting the instance (via
     134             :   /// removeObject) frees its memory, removing all symbol definitions that
     135             :   /// had been provided by this instance. Higher level layers are responsible
     136             :   /// for taking any action required to handle the missing symbols.
     137             :   class LinkedObject {
     138             :   public:
     139         103 :     LinkedObject() = default;
     140             :     LinkedObject(const LinkedObject&) = delete;
     141             :     void operator=(const LinkedObject&) = delete;
     142          24 :     virtual ~LinkedObject() = default;
     143             : 
     144             :     virtual Error finalize() = 0;
     145             : 
     146             :     virtual JITSymbol::GetAddressFtor
     147             :     getSymbolMaterializer(std::string Name) = 0;
     148             : 
     149             :     virtual void mapSectionAddress(const void *LocalAddress,
     150             :                                    JITTargetAddress TargetAddr) const = 0;
     151             : 
     152         602 :     JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
     153         602 :       auto SymEntry = SymbolTable.find(Name);
     154        1204 :       if (SymEntry == SymbolTable.end())
     155             :         return nullptr;
     156         307 :       if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly)
     157             :         return nullptr;
     158         307 :       if (!Finalized)
     159         197 :         return JITSymbol(getSymbolMaterializer(Name),
     160             :                          SymEntry->second.getFlags());
     161         209 :       return JITSymbol(SymEntry->second);
     162             :     }
     163             : 
     164             :   protected:
     165             :     StringMap<JITEvaluatedSymbol> SymbolTable;
     166             :     bool Finalized = false;
     167             :   };
     168             : };
     169             : 
     170             : /// Bare bones object linking layer.
     171             : ///
     172             : ///   This class is intended to be used as the base layer for a JIT. It allows
     173             : /// object files to be loaded into memory, linked, and the addresses of their
     174             : /// symbols queried. All objects added to this layer can see each other's
     175             : /// symbols.
     176             : class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase {
     177             : public:
     178             : 
     179             :   using RTDyldObjectLinkingLayerBase::ObjectPtr;
     180             : 
     181             :   /// Functor for receiving object-loaded notifications.
     182             :   using NotifyLoadedFtor =
     183             :       std::function<void(VModuleKey, const object::ObjectFile &Obj,
     184             :                          const RuntimeDyld::LoadedObjectInfo &)>;
     185             : 
     186             :   /// Functor for receiving finalization notifications.
     187             :   using NotifyFinalizedFtor =
     188             :       std::function<void(VModuleKey, const object::ObjectFile &Obj,
     189             :                          const RuntimeDyld::LoadedObjectInfo &)>;
     190             : 
     191             :   /// Functor for receiving deallocation notifications.
     192             :   using NotifyFreedFtor = std::function<void(VModuleKey, const object::ObjectFile &Obj)>;
     193             : 
     194             : private:
     195             :   using OwnedObject = object::OwningBinary<object::ObjectFile>;
     196             : 
     197             :   template <typename MemoryManagerPtrT>
     198             :   class ConcreteLinkedObject : public LinkedObject {
     199             :   public:
     200         103 :     ConcreteLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
     201             :                          OwnedObject Obj, MemoryManagerPtrT MemMgr,
     202             :                          std::shared_ptr<SymbolResolver> Resolver,
     203             :                          bool ProcessAllSections)
     204             :         : K(std::move(K)),
     205             :           Parent(Parent),
     206             :           MemMgr(std::move(MemMgr)),
     207             :           PFC(llvm::make_unique<PreFinalizeContents>(
     208             :               std::move(Obj), std::move(Resolver),
     209         206 :               ProcessAllSections)) {
     210         103 :       buildInitialSymbolTable(PFC->Obj);
     211         103 :     }
     212             : 
     213          48 :     ~ConcreteLinkedObject() override {
     214          24 :       if (this->Parent.NotifyFreed && ObjForNotify.getBinary())
     215           4 :         this->Parent.NotifyFreed(K, *ObjForNotify.getBinary());
     216             : 
     217          24 :       MemMgr->deregisterEHFrames();
     218          72 :     }
     219          24 : 
     220             :     Error finalize() override {
     221             :       assert(PFC && "mapSectionAddress called on finalized LinkedObject");
     222             : 
     223             :       JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver,
     224          24 :                                                nullptr);
     225          24 :       PFC->RTDyld = llvm::make_unique<RuntimeDyld>(*MemMgr, ResolverAdapter);
     226          24 :       PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections);
     227           4 : 
     228             :       Finalized = true;
     229          24 : 
     230          48 :       std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
     231             :           PFC->RTDyld->loadObject(*PFC->Obj.getBinary());
     232         102 : 
     233             :       // Copy the symbol table out of the RuntimeDyld instance.
     234             :       {
     235         102 :         auto SymTab = PFC->RTDyld->getSymbolTable();
     236             :         for (auto &KV : SymTab)
     237         102 :           SymbolTable[KV.first] = KV.second;
     238         102 :       }
     239             : 
     240         102 :       if (Parent.NotifyLoaded)
     241             :         Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info);
     242         102 : 
     243             :       PFC->RTDyld->finalizeWithMemoryManagerLocking();
     244             : 
     245             :       if (PFC->RTDyld->hasError())
     246             :         return make_error<StringError>(PFC->RTDyld->getErrorString(),
     247         102 :                                        inconvertibleErrorCode());
     248         303 : 
     249         201 :       if (Parent.NotifyFinalized)
     250             :         Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info);
     251             : 
     252         204 :       // Release resources.
     253          93 :       if (this->Parent.NotifyFreed)
     254             :         ObjForNotify = std::move(PFC->Obj); // needed for callback
     255         102 :       PFC = nullptr;
     256             :       return Error::success();
     257         102 :     }
     258           0 : 
     259           0 :     JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
     260             :       return [this, Name]() -> Expected<JITTargetAddress> {
     261         204 :         // The symbol may be materialized between the creation of this lambda
     262          97 :         // and its execution, so we need to double check.
     263             :         if (!this->Finalized)
     264             :           if (auto Err = this->finalize())
     265         204 :             return std::move(Err);
     266           4 :         return this->getSymbol(Name, false).getAddress();
     267         102 :       };
     268             :     }
     269             : 
     270             :     void mapSectionAddress(const void *LocalAddress,
     271          98 :                            JITTargetAddress TargetAddr) const override {
     272             :       assert(PFC && "mapSectionAddress called on finalized LinkedObject");
     273             :       assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
     274             :       PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
     275             :     }
     276             : 
     277             :   private:
     278             :     void buildInitialSymbolTable(const OwnedObject &Obj) {
     279          98 :       for (auto &Symbol : Obj.getBinary()->symbols()) {
     280             :         if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
     281             :           continue;
     282           0 :         Expected<StringRef> SymbolName = Symbol.getName();
     283             :         // FIXME: Raise an error for bad symbols.
     284             :         if (!SymbolName) {
     285             :           consumeError(SymbolName.takeError());
     286           0 :           continue;
     287           0 :         }
     288             :         // FIXME: Raise an error for bad symbols.
     289             :         auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
     290         103 :         if (!Flags) {
     291         683 :           consumeError(Flags.takeError());
     292         580 :           continue;
     293         167 :         }
     294             :         SymbolTable.insert(
     295             :             std::make_pair(*SymbolName, JITEvaluatedSymbol(0, *Flags)));
     296         413 :       }
     297           0 :     }
     298           0 : 
     299             :     // Contains the information needed prior to finalization: the object files,
     300             :     // memory manager, resolver, and flags needed for RuntimeDyld.
     301         413 :     struct PreFinalizeContents {
     302         413 :       PreFinalizeContents(OwnedObject Obj,
     303           0 :                           std::shared_ptr<SymbolResolver> Resolver,
     304             :                           bool ProcessAllSections)
     305             :           : Obj(std::move(Obj)),
     306         413 :             Resolver(std::move(Resolver)),
     307             :             ProcessAllSections(ProcessAllSections) {}
     308             : 
     309         103 :       OwnedObject Obj;
     310             :       std::shared_ptr<SymbolResolver> Resolver;
     311             :       bool ProcessAllSections;
     312             :       std::unique_ptr<RuntimeDyld> RTDyld;
     313             :     };
     314           0 : 
     315             :     VModuleKey K;
     316             :     RTDyldObjectLinkingLayer &Parent;
     317             :     MemoryManagerPtrT MemMgr;
     318             :     OwnedObject ObjForNotify;
     319           0 :     std::unique_ptr<PreFinalizeContents> PFC;
     320             :   };
     321             : 
     322             :   template <typename MemoryManagerPtrT>
     323             :   std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT>>
     324             :   createLinkedObject(RTDyldObjectLinkingLayer &Parent, VModuleKey K,
     325             :                      OwnedObject Obj, MemoryManagerPtrT MemMgr,
     326             :                      std::shared_ptr<SymbolResolver> Resolver,
     327             :                      bool ProcessAllSections) {
     328             :     using LOS = ConcreteLinkedObject<MemoryManagerPtrT>;
     329             :     return llvm::make_unique<LOS>(Parent, std::move(K), std::move(Obj),
     330             :                                   std::move(MemMgr), std::move(Resolver),
     331             :                                   ProcessAllSections);
     332             :   }
     333             : 
     334             : public:
     335             :   struct Resources {
     336             :     std::shared_ptr<RuntimeDyld::MemoryManager> MemMgr;
     337             :     std::shared_ptr<SymbolResolver> Resolver;
     338             :   };
     339             : 
     340             :   using ResourcesGetter = std::function<Resources(VModuleKey)>;
     341             : 
     342             :   /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
     343         103 :   ///        and NotifyFinalized functors.
     344             :   RTDyldObjectLinkingLayer(
     345             :       ExecutionSession &ES, ResourcesGetter GetResources,
     346             :       NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
     347             :       NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(),
     348             :       NotifyFreedFtor NotifyFreed = NotifyFreedFtor())
     349             :       : ES(ES), GetResources(std::move(GetResources)),
     350             :         NotifyLoaded(std::move(NotifyLoaded)),
     351             :         NotifyFinalized(std::move(NotifyFinalized)),
     352             :         NotifyFreed(std::move(NotifyFreed)),
     353             :         ProcessAllSections(false) {
     354             :   }
     355             : 
     356          85 :   /// Set the 'ProcessAllSections' flag.
     357             :   ///
     358             :   /// If set to true, all sections in each object file will be allocated using
     359             :   /// the memory manager, rather than just the sections required for execution.
     360             :   ///
     361          85 :   /// This is kludgy, and may be removed in the future.
     362             :   void setProcessAllSections(bool ProcessAllSections) {
     363             :     this->ProcessAllSections = ProcessAllSections;
     364             :   }
     365         170 : 
     366          85 :   /// Add an object to the JIT.
     367             :   Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
     368             : 
     369             :     auto Obj =
     370             :         object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
     371             :     if (!Obj)
     372             :       return Obj.takeError();
     373             : 
     374             :     assert(!LinkedObjects.count(K) && "VModuleKey already in use");
     375           1 : 
     376             :     auto R = GetResources(K);
     377             : 
     378             :     LinkedObjects[K] = createLinkedObject(
     379         103 :         *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
     380             :         std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections);
     381             : 
     382         309 :     return Error::success();
     383         103 :   }
     384             : 
     385             :   /// Remove the object associated with VModuleKey K.
     386             :   ///
     387             :   ///   All memory allocated for the object will be freed, and the sections and
     388         206 :   /// symbols it provided will no longer be available. No attempt is made to
     389             :   /// re-emit the missing symbols, and any use of these symbols (directly or
     390         206 :   /// indirectly) will result in undefined behavior. If dependence tracking is
     391         103 :   /// required to detect or resolve such issues it should be added at a higher
     392         103 :   /// layer.
     393             :   Error removeObject(VModuleKey K) {
     394             :     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
     395             :     // How do we invalidate the symbols in H?
     396             :     LinkedObjects.erase(K);
     397             :     return Error::success();
     398             :   }
     399             : 
     400             :   /// Search for the given named symbol.
     401             :   /// @param Name The name of the symbol to search for.
     402             :   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
     403             :   /// @return A handle for the given named symbol, if it exists.
     404             :   JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
     405             :     for (auto &KV : LinkedObjects)
     406             :       if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly))
     407             :         return Sym;
     408             :       else if (auto Err = Sym.takeError())
     409             :         return std::move(Err);
     410             : 
     411             :     return nullptr;
     412             :   }
     413             : 
     414             :   /// Search for the given named symbol in the context of the loaded
     415             :   ///        object represented by the VModuleKey K.
     416         294 :   /// @param K The VModuleKey for the object to search in.
     417         469 :   /// @param Name The name of the symbol to search for.
     418         429 :   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
     419          79 :   /// @return A handle for the given named symbol, if it is found in the
     420         175 :   ///         given object.
     421             :   JITSymbol findSymbolIn(VModuleKey K, StringRef Name,
     422             :                          bool ExportedSymbolsOnly) {
     423             :     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
     424             :     return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly);
     425             :   }
     426             : 
     427             :   /// Map section addresses for the object associated with the
     428             :   ///        VModuleKey K.
     429             :   void mapSectionAddress(VModuleKey K, const void *LocalAddress,
     430             :                          JITTargetAddress TargetAddr) {
     431             :     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
     432             :     LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr);
     433             :   }
     434             : 
     435             :   /// Immediately emit and finalize the object represented by the given
     436         250 :   ///        VModuleKey.
     437             :   /// @param K VModuleKey for object to emit/finalize.
     438             :   Error emitAndFinalize(VModuleKey K) {
     439             :     assert(LinkedObjects.count(K) && "VModuleKey not associated with object");
     440             :     return LinkedObjects[K]->finalize();
     441           0 :   }
     442             : 
     443             : private:
     444           0 :   ExecutionSession &ES;
     445           0 : 
     446             :   std::map<VModuleKey, std::unique_ptr<LinkedObject>> LinkedObjects;
     447             :   ResourcesGetter GetResources;
     448             :   NotifyLoadedFtor NotifyLoaded;
     449             :   NotifyFinalizedFtor NotifyFinalized;
     450           4 :   NotifyFreedFtor NotifyFreed;
     451             :   bool ProcessAllSections = false;
     452           4 : };
     453             : 
     454             : } // end namespace orc
     455             : } // end namespace llvm
     456             : 
     457             : #endif // LLVM_EXECUTIONENGINE_ORC_RTDYLDOBJECTLINKINGLAYER_H

Generated by: LCOV version 1.13