blob: 2acfecfb94dcf4dacf7681e1940d0f91a0695a02 [file] [log] [blame]
//===- ObjectLinkingLayer.h - Add object files to a JIT process -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Contains the definition for the object layer of the JIT.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
#define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
#include "JITSymbol.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include <list>
#include <memory>
namespace llvm {
namespace orc {
class ObjectLinkingLayerBase {
protected:
/// @brief Holds a set of objects to be allocated/linked as a unit in the JIT.
///
/// An instance of this class will be created for each set of objects added
/// via JITObjectLayer::addObjectSet. Deleting the instance (via
/// removeObjectSet) frees its memory, removing all symbol definitions that
/// had been provided by this instance. Higher level layers are responsible
/// for taking any action required to handle the missing symbols.
class LinkedObjectSet {
LinkedObjectSet(const LinkedObjectSet&) = delete;
void operator=(const LinkedObjectSet&) = delete;
public:
LinkedObjectSet(RuntimeDyld::MemoryManager &MemMgr,
RuntimeDyld::SymbolResolver &Resolver,
bool ProcessAllSections)
: RTDyld(llvm::make_unique<RuntimeDyld>(MemMgr, Resolver)),
State(Raw) {
RTDyld->setProcessAllSections(ProcessAllSections);
}
virtual ~LinkedObjectSet() {}
std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
addObject(const object::ObjectFile &Obj) {
return RTDyld->loadObject(Obj);
}
RuntimeDyld::SymbolInfo getSymbol(StringRef Name) const {
return RTDyld->getSymbol(Name);
}
bool NeedsFinalization() const { return (State == Raw); }
virtual void Finalize() = 0;
void mapSectionAddress(const void *LocalAddress, TargetAddress TargetAddr) {
assert((State != Finalized) &&
"Attempting to remap sections for finalized objects.");
RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
}
protected:
std::unique_ptr<RuntimeDyld> RTDyld;
enum { Raw, Finalizing, Finalized } State;
};
typedef std::list<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT;
public:
/// @brief Handle to a set of loaded objects.
typedef LinkedObjectSetListT::iterator ObjSetHandleT;
};
/// @brief Default (no-op) action to perform when loading objects.
class DoNothingOnNotifyLoaded {
public:
template <typename ObjSetT, typename LoadResult>
void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &,
const LoadResult &) {}
};
/// @brief Bare bones object linking layer.
///
/// This class is intended to be used as the base layer for a JIT. It allows
/// object files to be loaded into memory, linked, and the addresses of their
/// symbols queried. All objects added to this layer can see each other's
/// symbols.
template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded>
class ObjectLinkingLayer : public ObjectLinkingLayerBase {
private:
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
class ConcreteLinkedObjectSet : public LinkedObjectSet {
public:
ConcreteLinkedObjectSet(MemoryManagerPtrT MemMgr,
SymbolResolverPtrT Resolver,
bool ProcessAllSections)
: LinkedObjectSet(*MemMgr, *Resolver, ProcessAllSections),
MemMgr(std::move(MemMgr)), Resolver(std::move(Resolver)) { }
void Finalize() override {
State = Finalizing;
RTDyld->resolveRelocations();
RTDyld->registerEHFrames();
MemMgr->finalizeMemory();
State = Finalized;
}
private:
MemoryManagerPtrT MemMgr;
SymbolResolverPtrT Resolver;
};
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
std::unique_ptr<LinkedObjectSet>
createLinkedObjectSet(MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver,
bool ProcessAllSections) {
typedef ConcreteLinkedObjectSet<MemoryManagerPtrT, SymbolResolverPtrT> LOS;
return llvm::make_unique<LOS>(std::move(MemMgr), std::move(Resolver),
ProcessAllSections);
}
public:
/// @brief LoadedObjectInfo list. Contains a list of owning pointers to
/// RuntimeDyld::LoadedObjectInfo instances.
typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>
LoadedObjInfoList;
/// @brief Functor for receiving finalization notifications.
typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor;
/// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
/// and NotifyFinalized functors.
ObjectLinkingLayer(
NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
: NotifyLoaded(std::move(NotifyLoaded)),
NotifyFinalized(std::move(NotifyFinalized)),
ProcessAllSections(false) {}
/// @brief Set the 'ProcessAllSections' flag.
///
/// If set to true, all sections in each object file will be allocated using
/// the memory manager, rather than just the sections required for execution.
///
/// This is kludgy, and may be removed in the future.
void setProcessAllSections(bool ProcessAllSections) {
this->ProcessAllSections = ProcessAllSections;
}
/// @brief Add a set of objects (or archives) that will be treated as a unit
/// for the purposes of symbol lookup and memory management.
///
/// @return A pair containing (1) A handle that can be used to free the memory
/// allocated for the objects, and (2) a LoadedObjInfoList containing
/// one LoadedObjInfo instance for each object at the corresponding
/// index in the Objects list.
///
/// This version of this method allows the client to pass in an
/// RTDyldMemoryManager instance that will be used to allocate memory and look
/// up external symbol addresses for the given objects.
template <typename ObjSetT,
typename MemoryManagerPtrT,
typename SymbolResolverPtrT>
ObjSetHandleT addObjectSet(const ObjSetT &Objects,
MemoryManagerPtrT MemMgr,
SymbolResolverPtrT Resolver) {
ObjSetHandleT Handle =
LinkedObjSetList.insert(
LinkedObjSetList.end(),
createLinkedObjectSet(std::move(MemMgr), std::move(Resolver),
ProcessAllSections));
LinkedObjectSet &LOS = **Handle;
LoadedObjInfoList LoadedObjInfos;
for (auto &Obj : Objects)
LoadedObjInfos.push_back(LOS.addObject(*Obj));
NotifyLoaded(Handle, Objects, LoadedObjInfos);
return Handle;
}
/// @brief Remove the set of objects associated with handle H.
///
/// All memory allocated for the objects will be freed, and the sections and
/// symbols they provided will no longer be available. No attempt is made to
/// re-emit the missing symbols, and any use of these symbols (directly or
/// indirectly) will result in undefined behavior. If dependence tracking is
/// required to detect or resolve such issues it should be added at a higher
/// layer.
void removeObjectSet(ObjSetHandleT H) {
// How do we invalidate the symbols in H?
LinkedObjSetList.erase(H);
}
/// @brief Search for the given named symbol.
/// @param Name The name of the symbol to search for.
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
/// @return A handle for the given named symbol, if it exists.
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E;
++I)
if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
return Symbol;
return nullptr;
}
/// @brief Search for the given named symbol in the context of the set of
/// loaded objects represented by the handle H.
/// @param H The handle for the object set to search in.
/// @param Name The name of the symbol to search for.
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
/// @return A handle for the given named symbol, if it is found in the
/// given object set.
JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name,
bool ExportedSymbolsOnly) {
if (auto Sym = (*H)->getSymbol(Name)) {
if (Sym.isExported() || !ExportedSymbolsOnly) {
auto Addr = Sym.getAddress();
auto Flags = Sym.getFlags();
if (!(*H)->NeedsFinalization()) {
// If this instance has already been finalized then we can just return
// the address.
return JITSymbol(Addr, Flags);
} else {
// If this instance needs finalization return a functor that will do
// it. The functor still needs to double-check whether finalization is
// required, in case someone else finalizes this set before the
// functor is called.
auto GetAddress =
[this, Addr, H]() {
if ((*H)->NeedsFinalization()) {
(*H)->Finalize();
if (NotifyFinalized)
NotifyFinalized(H);
}
return Addr;
};
return JITSymbol(std::move(GetAddress), Flags);
}
}
}
return nullptr;
}
/// @brief Map section addresses for the objects associated with the handle H.
void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
TargetAddress TargetAddr) {
(*H)->mapSectionAddress(LocalAddress, TargetAddr);
}
/// @brief Immediately emit and finalize the object set represented by the
/// given handle.
/// @param H Handle for object set to emit/finalize.
void emitAndFinalize(ObjSetHandleT H) {
(*H)->Finalize();
if (NotifyFinalized)
NotifyFinalized(H);
}
private:
LinkedObjectSetListT LinkedObjSetList;
NotifyLoadedFtor NotifyLoaded;
NotifyFinalizedFtor NotifyFinalized;
bool ProcessAllSections;
};
} // End namespace orc.
} // End namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H