mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[ORC] Switch the object layer API from addObjectSet to addObject (singular), and
move the ObjectCache from the IRCompileLayer to SimpleCompiler. This is the first in a series of patches aimed at cleaning up and improving the robustness and performance of the ORC APIs. llvm-svn: 306058
This commit is contained in:
parent
1ad2576dfe
commit
efe8bd1023
@ -40,8 +40,8 @@ class KaleidoscopeJIT {
|
||||
private:
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
const DataLayout DL;
|
||||
RTDyldObjectLinkingLayer<> ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
|
||||
RTDyldObjectLinkingLayer ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
|
||||
|
||||
public:
|
||||
using ModuleHandle = decltype(CompileLayer)::ModuleSetHandleT;
|
||||
|
@ -44,8 +44,8 @@ class KaleidoscopeJIT {
|
||||
private:
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
const DataLayout DL;
|
||||
RTDyldObjectLinkingLayer<> ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
|
||||
RTDyldObjectLinkingLayer ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
|
||||
|
||||
using OptimizeFunction =
|
||||
std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>;
|
||||
|
@ -47,8 +47,8 @@ class KaleidoscopeJIT {
|
||||
private:
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
const DataLayout DL;
|
||||
RTDyldObjectLinkingLayer<> ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
|
||||
RTDyldObjectLinkingLayer ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
|
||||
|
||||
using OptimizeFunction =
|
||||
std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>;
|
||||
|
@ -73,8 +73,8 @@ class KaleidoscopeJIT {
|
||||
private:
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
const DataLayout DL;
|
||||
RTDyldObjectLinkingLayer<> ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
|
||||
RTDyldObjectLinkingLayer ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
|
||||
|
||||
using OptimizeFunction =
|
||||
std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>;
|
||||
|
@ -78,8 +78,8 @@ class KaleidoscopeJIT {
|
||||
private:
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
const DataLayout DL;
|
||||
RTDyldObjectLinkingLayer<> ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
|
||||
RTDyldObjectLinkingLayer ObjectLayer;
|
||||
IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
|
||||
|
||||
using OptimizeFunction =
|
||||
std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>;
|
||||
|
@ -39,8 +39,8 @@ namespace orc {
|
||||
|
||||
class KaleidoscopeJIT {
|
||||
public:
|
||||
using ObjLayerT = RTDyldObjectLinkingLayer<>;
|
||||
using CompileLayerT = IRCompileLayer<ObjLayerT>;
|
||||
using ObjLayerT = RTDyldObjectLinkingLayer;
|
||||
using CompileLayerT = IRCompileLayer<ObjLayerT, SimpleCompiler>;
|
||||
using ModuleHandleT = CompileLayerT::ModuleSetHandleT;
|
||||
|
||||
KaleidoscopeJIT()
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ExecutionEngine/ObjectCache.h"
|
||||
#include "llvm/ExecutionEngine/ObjectMemoryBuffer.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
@ -38,11 +39,22 @@ namespace orc {
|
||||
/// ObjectFile.
|
||||
class SimpleCompiler {
|
||||
public:
|
||||
|
||||
using CompileResult = object::OwningBinary<object::ObjectFile>;
|
||||
|
||||
/// @brief Construct a simple compile functor with the given target.
|
||||
SimpleCompiler(TargetMachine &TM) : TM(TM) {}
|
||||
SimpleCompiler(TargetMachine &TM, ObjectCache *ObjCache = nullptr)
|
||||
: TM(TM), ObjCache(ObjCache) {}
|
||||
|
||||
/// @brief Set an ObjectCache to query before compiling.
|
||||
void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; }
|
||||
|
||||
/// @brief Compile a Module to an ObjectFile.
|
||||
object::OwningBinary<object::ObjectFile> operator()(Module &M) const {
|
||||
CompileResult operator()(Module &M) {
|
||||
CompileResult CachedObject = tryToLoadFromObjectCache(M);
|
||||
if (CachedObject.getBinary())
|
||||
return CachedObject;
|
||||
|
||||
SmallVector<char, 0> ObjBufferSV;
|
||||
raw_svector_ostream ObjStream(ObjBufferSV);
|
||||
|
||||
@ -55,16 +67,43 @@ public:
|
||||
new ObjectMemoryBuffer(std::move(ObjBufferSV)));
|
||||
Expected<std::unique_ptr<object::ObjectFile>> Obj =
|
||||
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
|
||||
using OwningObj = object::OwningBinary<object::ObjectFile>;
|
||||
if (Obj)
|
||||
return OwningObj(std::move(*Obj), std::move(ObjBuffer));
|
||||
if (Obj) {
|
||||
notifyObjectCompiled(M, *ObjBuffer);
|
||||
return CompileResult(std::move(*Obj), std::move(ObjBuffer));
|
||||
}
|
||||
// TODO: Actually report errors helpfully.
|
||||
consumeError(Obj.takeError());
|
||||
return OwningObj(nullptr, nullptr);
|
||||
return CompileResult(nullptr, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
CompileResult tryToLoadFromObjectCache(const Module &M) {
|
||||
if (!ObjCache)
|
||||
return CompileResult();
|
||||
|
||||
std::unique_ptr<MemoryBuffer> ObjBuffer = ObjCache->getObject(&M);
|
||||
if (!ObjBuffer)
|
||||
return CompileResult();
|
||||
|
||||
Expected<std::unique_ptr<object::ObjectFile>> Obj =
|
||||
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
|
||||
if (!Obj) {
|
||||
// TODO: Actually report errors helpfully.
|
||||
consumeError(Obj.takeError());
|
||||
return CompileResult();
|
||||
}
|
||||
|
||||
return CompileResult(std::move(*Obj), std::move(ObjBuffer));
|
||||
}
|
||||
|
||||
void notifyObjectCompiled(const Module &M, const MemoryBuffer &ObjBuffer) {
|
||||
if (ObjCache)
|
||||
ObjCache->notifyObjectCompiled(&M, ObjBuffer.getMemBufferRef());
|
||||
}
|
||||
|
||||
TargetMachine &TM;
|
||||
ObjectCache *ObjCache = nullptr;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
|
@ -16,16 +16,9 @@
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/ObjectCache.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -39,25 +32,19 @@ namespace orc {
|
||||
/// immediately compiles each IR module to an object file (each IR Module is
|
||||
/// compiled separately). The resulting set of object files is then added to
|
||||
/// the layer below, which must implement the object layer concept.
|
||||
template <typename BaseLayerT> class IRCompileLayer {
|
||||
public:
|
||||
using CompileFtor =
|
||||
std::function<object::OwningBinary<object::ObjectFile>(Module &)>;
|
||||
|
||||
private:
|
||||
using ObjSetHandleT = typename BaseLayerT::ObjSetHandleT;
|
||||
|
||||
template <typename BaseLayerT, typename CompileFtor>
|
||||
class IRCompileLayer {
|
||||
public:
|
||||
/// @brief Handle to a set of compiled modules.
|
||||
using ModuleSetHandleT = ObjSetHandleT;
|
||||
using ModuleSetHandleT = typename BaseLayerT::ObjHandleT;
|
||||
|
||||
/// @brief Construct an IRCompileLayer with the given BaseLayer, which must
|
||||
/// implement the ObjectLayer concept.
|
||||
IRCompileLayer(BaseLayerT &BaseLayer, CompileFtor Compile)
|
||||
: BaseLayer(BaseLayer), Compile(std::move(Compile)) {}
|
||||
|
||||
/// @brief Set an ObjectCache to query before compiling.
|
||||
void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; }
|
||||
/// @brief Get a reference to the compiler functor.
|
||||
CompileFtor& getCompiler() { return Compile; }
|
||||
|
||||
/// @brief Compile each module in the given module set, then add the resulting
|
||||
/// set of objects to the base layer along with the memory manager and
|
||||
@ -69,35 +56,15 @@ public:
|
||||
ModuleSetHandleT addModuleSet(ModuleSetT Ms,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
std::vector<std::unique_ptr<object::OwningBinary<object::ObjectFile>>>
|
||||
Objects;
|
||||
|
||||
for (const auto &M : Ms) {
|
||||
auto Object =
|
||||
llvm::make_unique<object::OwningBinary<object::ObjectFile>>();
|
||||
|
||||
if (ObjCache)
|
||||
*Object = tryToLoadFromObjectCache(*M);
|
||||
|
||||
if (!Object->getBinary()) {
|
||||
*Object = Compile(*M);
|
||||
if (ObjCache)
|
||||
ObjCache->notifyObjectCompiled(&*M,
|
||||
Object->getBinary()->getMemoryBufferRef());
|
||||
}
|
||||
|
||||
Objects.push_back(std::move(Object));
|
||||
}
|
||||
|
||||
ModuleSetHandleT H =
|
||||
BaseLayer.addObjectSet(std::move(Objects), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
|
||||
return H;
|
||||
assert(Ms.size() == 1);
|
||||
using CompileResult = decltype(Compile(*Ms.front()));
|
||||
auto Obj = std::make_shared<CompileResult>(Compile(*Ms.front()));
|
||||
return BaseLayer.addObject(std::move(Obj), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
}
|
||||
|
||||
/// @brief Remove the module set associated with the handle H.
|
||||
void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeObjectSet(H); }
|
||||
void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeObject(H); }
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
@ -128,27 +95,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
object::OwningBinary<object::ObjectFile>
|
||||
tryToLoadFromObjectCache(const Module &M) {
|
||||
std::unique_ptr<MemoryBuffer> ObjBuffer = ObjCache->getObject(&M);
|
||||
if (!ObjBuffer)
|
||||
return object::OwningBinary<object::ObjectFile>();
|
||||
|
||||
Expected<std::unique_ptr<object::ObjectFile>> Obj =
|
||||
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
|
||||
if (!Obj) {
|
||||
// TODO: Actually report errors helpfully.
|
||||
consumeError(Obj.takeError());
|
||||
return object::OwningBinary<object::ObjectFile>();
|
||||
}
|
||||
|
||||
return object::OwningBinary<object::ObjectFile>(std::move(*Obj),
|
||||
std::move(ObjBuffer));
|
||||
}
|
||||
|
||||
BaseLayerT &BaseLayer;
|
||||
CompileFtor Compile;
|
||||
ObjectCache *ObjCache = nullptr;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
|
@ -23,14 +23,14 @@ namespace orc {
|
||||
|
||||
/// @brief Object mutating layer.
|
||||
///
|
||||
/// This layer accepts sets of ObjectFiles (via addObjectSet). It
|
||||
/// This layer accepts sets of ObjectFiles (via addObject). It
|
||||
/// immediately applies the user supplied functor to each object, then adds
|
||||
/// the set of transformed objects to the layer below.
|
||||
template <typename BaseLayerT, typename TransformFtor>
|
||||
class ObjectTransformLayer {
|
||||
public:
|
||||
/// @brief Handle to a set of added objects.
|
||||
using ObjSetHandleT = typename BaseLayerT::ObjSetHandleT;
|
||||
using ObjHandleT = typename BaseLayerT::ObjHandleT;
|
||||
|
||||
/// @brief Construct an ObjectTransformLayer with the given BaseLayer
|
||||
ObjectTransformLayer(BaseLayerT &BaseLayer,
|
||||
@ -42,19 +42,16 @@ public:
|
||||
/// memory manager and symbol resolver.
|
||||
///
|
||||
/// @return A handle for the added objects.
|
||||
template <typename ObjSetT, typename MemoryManagerPtrT,
|
||||
template <typename ObjPtrT, typename MemoryManagerPtrT,
|
||||
typename SymbolResolverPtrT>
|
||||
ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
for (auto I = Objects.begin(), E = Objects.end(); I != E; ++I)
|
||||
*I = Transform(std::move(*I));
|
||||
|
||||
return BaseLayer.addObjectSet(std::move(Objects), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
ObjHandleT addObject(ObjPtrT Obj, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
return BaseLayer.addObject(Transform(std::move(Obj)), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
}
|
||||
|
||||
/// @brief Remove the object set associated with the handle H.
|
||||
void removeObjectSet(ObjSetHandleT H) { BaseLayer.removeObjectSet(H); }
|
||||
void removeObject(ObjHandleT H) { BaseLayer.removeObject(H); }
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
@ -72,7 +69,7 @@ public:
|
||||
/// @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, const std::string &Name,
|
||||
JITSymbol findSymbolIn(ObjHandleT H, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
@ -80,10 +77,10 @@ public:
|
||||
/// @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) { BaseLayer.emitAndFinalize(H); }
|
||||
void emitAndFinalize(ObjHandleT H) { BaseLayer.emitAndFinalize(H); }
|
||||
|
||||
/// @brief Map section addresses for the objects associated with the handle H.
|
||||
void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
|
||||
void mapSectionAddress(ObjHandleT H, const void *LocalAddress,
|
||||
JITTargetAddress TargetAddr) {
|
||||
BaseLayer.mapSectionAddress(H, LocalAddress, TargetAddr);
|
||||
}
|
||||
|
@ -174,6 +174,12 @@ private:
|
||||
ArgV[0] = "<jit process>";
|
||||
for (auto &Arg : Args)
|
||||
ArgV[Idx++] = Arg.c_str();
|
||||
ArgV[ArgC] = 0;
|
||||
DEBUG(
|
||||
for (int Idx = 0; Idx < ArgC; ++Idx) {
|
||||
llvm::dbgs() << "Arg " << Idx << ": " << ArgV[Idx] << "\n";
|
||||
}
|
||||
);
|
||||
|
||||
DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
|
||||
int Result = Fn(ArgC, ArgV.get());
|
||||
|
@ -35,19 +35,23 @@ namespace orc {
|
||||
|
||||
class RTDyldObjectLinkingLayerBase {
|
||||
protected:
|
||||
|
||||
using ObjectPtr =
|
||||
std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
|
||||
|
||||
/// @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
|
||||
/// via JITObjectLayer::addObject. Deleting the instance (via
|
||||
/// removeObject) 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 {
|
||||
class LinkedObject {
|
||||
public:
|
||||
LinkedObjectSet() = default;
|
||||
LinkedObjectSet(const LinkedObjectSet&) = delete;
|
||||
void operator=(const LinkedObjectSet&) = delete;
|
||||
virtual ~LinkedObjectSet() = default;
|
||||
LinkedObject() = default;
|
||||
LinkedObject(const LinkedObject&) = delete;
|
||||
void operator=(const LinkedObject&) = delete;
|
||||
virtual ~LinkedObject() = default;
|
||||
|
||||
virtual void finalize() = 0;
|
||||
|
||||
@ -74,19 +78,11 @@ protected:
|
||||
bool Finalized = false;
|
||||
};
|
||||
|
||||
using LinkedObjectSetListT = std::list<std::unique_ptr<LinkedObjectSet>>;
|
||||
using LinkedObjectListT = std::list<std::unique_ptr<LinkedObject>>;
|
||||
|
||||
public:
|
||||
/// @brief Handle to a set of loaded objects.
|
||||
using ObjSetHandleT = LinkedObjectSetListT::iterator;
|
||||
};
|
||||
|
||||
/// @brief Default (no-op) action to perform when loading objects.
|
||||
class DoNothingOnNotifyLoaded {
|
||||
public:
|
||||
template <typename ObjSetT, typename LoadResult>
|
||||
void operator()(RTDyldObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &,
|
||||
const LoadResult &) {}
|
||||
using ObjHandleT = LinkedObjectListT::iterator;
|
||||
};
|
||||
|
||||
/// @brief Bare bones object linking layer.
|
||||
@ -95,46 +91,54 @@ public:
|
||||
/// 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 RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase {
|
||||
public:
|
||||
|
||||
using RTDyldObjectLinkingLayerBase::ObjectPtr;
|
||||
|
||||
/// @brief Functor for receiving object-loaded notifications.
|
||||
using NotifyLoadedFtor = std::function<void(ObjHandleT, const ObjectPtr &Obj,
|
||||
const LoadedObjectInfo &)>;
|
||||
|
||||
/// @brief Functor for receiving finalization notifications.
|
||||
using NotifyFinalizedFtor = std::function<void(ObjSetHandleT)>;
|
||||
using NotifyFinalizedFtor = std::function<void(ObjHandleT)>;
|
||||
|
||||
private:
|
||||
template <typename ObjSetT, typename MemoryManagerPtrT,
|
||||
typename SymbolResolverPtrT, typename FinalizerFtor>
|
||||
class ConcreteLinkedObjectSet : public LinkedObjectSet {
|
||||
|
||||
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT,
|
||||
typename FinalizerFtor>
|
||||
class ConcreteLinkedObject : public LinkedObject {
|
||||
public:
|
||||
ConcreteLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver,
|
||||
FinalizerFtor Finalizer,
|
||||
bool ProcessAllSections)
|
||||
ConcreteLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver,
|
||||
FinalizerFtor Finalizer,
|
||||
bool ProcessAllSections)
|
||||
: MemMgr(std::move(MemMgr)),
|
||||
PFC(llvm::make_unique<PreFinalizeContents>(std::move(Objects),
|
||||
PFC(llvm::make_unique<PreFinalizeContents>(std::move(Obj),
|
||||
std::move(Resolver),
|
||||
std::move(Finalizer),
|
||||
ProcessAllSections)) {
|
||||
buildInitialSymbolTable(PFC->Objects);
|
||||
buildInitialSymbolTable(PFC->Obj);
|
||||
}
|
||||
|
||||
~ConcreteLinkedObjectSet() override {
|
||||
~ConcreteLinkedObject() override {
|
||||
MemMgr->deregisterEHFrames();
|
||||
}
|
||||
|
||||
void setHandle(ObjSetHandleT H) {
|
||||
|
||||
void setHandle(ObjHandleT H) {
|
||||
PFC->Handle = H;
|
||||
}
|
||||
|
||||
void finalize() override {
|
||||
assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet");
|
||||
assert(PFC && "mapSectionAddress called on finalized LinkedObject");
|
||||
|
||||
RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver);
|
||||
RTDyld.setProcessAllSections(PFC->ProcessAllSections);
|
||||
PFC->RTDyld = &RTDyld;
|
||||
|
||||
this->Finalized = true;
|
||||
PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Objects),
|
||||
PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Obj),
|
||||
[&]() {
|
||||
this->updateSymbolTable(RTDyld);
|
||||
});
|
||||
@ -156,27 +160,27 @@ private:
|
||||
|
||||
void mapSectionAddress(const void *LocalAddress,
|
||||
JITTargetAddress TargetAddr) const override {
|
||||
assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet");
|
||||
assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObjectSet");
|
||||
assert(PFC && "mapSectionAddress called on finalized LinkedObject");
|
||||
assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject");
|
||||
PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
|
||||
}
|
||||
|
||||
private:
|
||||
void buildInitialSymbolTable(const ObjSetT &Objects) {
|
||||
for (const auto &Obj : Objects)
|
||||
for (auto &Symbol : getObject(*Obj).symbols()) {
|
||||
if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
|
||||
continue;
|
||||
Expected<StringRef> SymbolName = Symbol.getName();
|
||||
// FIXME: Raise an error for bad symbols.
|
||||
if (!SymbolName) {
|
||||
consumeError(SymbolName.takeError());
|
||||
continue;
|
||||
}
|
||||
auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
|
||||
SymbolTable.insert(
|
||||
std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
|
||||
|
||||
void buildInitialSymbolTable(const ObjectPtr &Obj) {
|
||||
for (auto &Symbol : Obj->getBinary()->symbols()) {
|
||||
if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
|
||||
continue;
|
||||
Expected<StringRef> SymbolName = Symbol.getName();
|
||||
// FIXME: Raise an error for bad symbols.
|
||||
if (!SymbolName) {
|
||||
consumeError(SymbolName.takeError());
|
||||
continue;
|
||||
}
|
||||
auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol);
|
||||
SymbolTable.insert(
|
||||
std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags)));
|
||||
}
|
||||
}
|
||||
|
||||
void updateSymbolTable(const RuntimeDyld &RTDyld) {
|
||||
@ -187,17 +191,17 @@ private:
|
||||
// Contains the information needed prior to finalization: the object files,
|
||||
// memory manager, resolver, and flags needed for RuntimeDyld.
|
||||
struct PreFinalizeContents {
|
||||
PreFinalizeContents(ObjSetT Objects, SymbolResolverPtrT Resolver,
|
||||
PreFinalizeContents(ObjectPtr Obj, SymbolResolverPtrT Resolver,
|
||||
FinalizerFtor Finalizer, bool ProcessAllSections)
|
||||
: Objects(std::move(Objects)), Resolver(std::move(Resolver)),
|
||||
: Obj(std::move(Obj)), Resolver(std::move(Resolver)),
|
||||
Finalizer(std::move(Finalizer)),
|
||||
ProcessAllSections(ProcessAllSections) {}
|
||||
|
||||
ObjSetT Objects;
|
||||
ObjectPtr Obj;
|
||||
SymbolResolverPtrT Resolver;
|
||||
FinalizerFtor Finalizer;
|
||||
bool ProcessAllSections;
|
||||
ObjSetHandleT Handle;
|
||||
ObjHandleT Handle;
|
||||
RuntimeDyld *RTDyld;
|
||||
};
|
||||
|
||||
@ -205,27 +209,22 @@ private:
|
||||
std::unique_ptr<PreFinalizeContents> PFC;
|
||||
};
|
||||
|
||||
template <typename ObjSetT, typename MemoryManagerPtrT,
|
||||
typename SymbolResolverPtrT, typename FinalizerFtor>
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT,
|
||||
typename FinalizerFtor>
|
||||
std::unique_ptr<
|
||||
ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT,
|
||||
SymbolResolverPtrT, FinalizerFtor>>
|
||||
createLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver,
|
||||
FinalizerFtor Finalizer,
|
||||
bool ProcessAllSections) {
|
||||
using LOS = ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT,
|
||||
SymbolResolverPtrT, FinalizerFtor>;
|
||||
return llvm::make_unique<LOS>(std::move(Objects), std::move(MemMgr),
|
||||
ConcreteLinkedObject<MemoryManagerPtrT, SymbolResolverPtrT, FinalizerFtor>>
|
||||
createLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver,
|
||||
FinalizerFtor Finalizer,
|
||||
bool ProcessAllSections) {
|
||||
using LOS = ConcreteLinkedObject<MemoryManagerPtrT, SymbolResolverPtrT,
|
||||
FinalizerFtor>;
|
||||
return llvm::make_unique<LOS>(std::move(Obj), std::move(MemMgr),
|
||||
std::move(Resolver), std::move(Finalizer),
|
||||
ProcessAllSections);
|
||||
}
|
||||
|
||||
public:
|
||||
/// @brief LoadedObjectInfo list. Contains a list of owning pointers to
|
||||
/// RuntimeDyld::LoadedObjectInfo instances.
|
||||
using LoadedObjInfoList =
|
||||
std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>;
|
||||
|
||||
/// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
|
||||
/// and NotifyFinalized functors.
|
||||
@ -250,23 +249,22 @@ public:
|
||||
///
|
||||
/// @return A handle that can be used to refer to the loaded objects (for
|
||||
/// symbol searching, finalization, freeing memory, etc.).
|
||||
template <typename ObjSetT,
|
||||
typename MemoryManagerPtrT,
|
||||
template <typename MemoryManagerPtrT,
|
||||
typename SymbolResolverPtrT>
|
||||
ObjSetHandleT addObjectSet(ObjSetT Objects,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
auto Finalizer = [&](ObjSetHandleT H, RuntimeDyld &RTDyld,
|
||||
const ObjSetT &Objs,
|
||||
std::function<void()> LOSHandleLoad) {
|
||||
LoadedObjInfoList LoadedObjInfos;
|
||||
ObjHandleT addObject(ObjectPtr Obj,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
|
||||
for (auto &Obj : Objs)
|
||||
LoadedObjInfos.push_back(RTDyld.loadObject(this->getObject(*Obj)));
|
||||
auto Finalizer = [&](ObjHandleT H, RuntimeDyld &RTDyld,
|
||||
const ObjectPtr &ObjToLoad,
|
||||
std::function<void()> LOSHandleLoad) {
|
||||
std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
|
||||
RTDyld.loadObject(*ObjToLoad->getBinary());
|
||||
|
||||
LOSHandleLoad();
|
||||
|
||||
this->NotifyLoaded(H, Objs, LoadedObjInfos);
|
||||
if (this->NotifyLoaded)
|
||||
this->NotifyLoaded(H, ObjToLoad, *Info);
|
||||
|
||||
RTDyld.finalizeWithMemoryManagerLocking();
|
||||
|
||||
@ -274,17 +272,15 @@ public:
|
||||
this->NotifyFinalized(H);
|
||||
};
|
||||
|
||||
auto LOS =
|
||||
createLinkedObjectSet(std::move(Objects), std::move(MemMgr),
|
||||
std::move(Resolver), std::move(Finalizer),
|
||||
ProcessAllSections);
|
||||
auto LO =
|
||||
createLinkedObject(std::move(Obj), std::move(MemMgr), std::move(Resolver),
|
||||
std::move(Finalizer), ProcessAllSections);
|
||||
// LOS is an owning-ptr. Keep a non-owning one so that we can set the handle
|
||||
// below.
|
||||
auto *LOSPtr = LOS.get();
|
||||
auto *LOPtr = LO.get();
|
||||
|
||||
ObjSetHandleT Handle = LinkedObjSetList.insert(LinkedObjSetList.end(),
|
||||
std::move(LOS));
|
||||
LOSPtr->setHandle(Handle);
|
||||
ObjHandleT Handle = LinkedObjList.insert(LinkedObjList.end(), std::move(LO));
|
||||
LOPtr->setHandle(Handle);
|
||||
|
||||
return Handle;
|
||||
}
|
||||
@ -297,9 +293,9 @@ public:
|
||||
/// 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) {
|
||||
void removeObject(ObjHandleT H) {
|
||||
// How do we invalidate the symbols in H?
|
||||
LinkedObjSetList.erase(H);
|
||||
LinkedObjList.erase(H);
|
||||
}
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
@ -307,7 +303,7 @@ public:
|
||||
/// @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;
|
||||
for (auto I = LinkedObjList.begin(), E = LinkedObjList.end(); I != E;
|
||||
++I)
|
||||
if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
|
||||
return Symbol;
|
||||
@ -322,13 +318,13 @@ public:
|
||||
/// @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,
|
||||
JITSymbol findSymbolIn(ObjHandleT H, StringRef Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
return (*H)->getSymbol(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// @brief Map section addresses for the objects associated with the handle H.
|
||||
void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
|
||||
void mapSectionAddress(ObjHandleT H, const void *LocalAddress,
|
||||
JITTargetAddress TargetAddr) {
|
||||
(*H)->mapSectionAddress(LocalAddress, TargetAddr);
|
||||
}
|
||||
@ -336,22 +332,13 @@ public:
|
||||
/// @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) {
|
||||
void emitAndFinalize(ObjHandleT H) {
|
||||
(*H)->finalize();
|
||||
}
|
||||
|
||||
private:
|
||||
static const object::ObjectFile& getObject(const object::ObjectFile &Obj) {
|
||||
return Obj;
|
||||
}
|
||||
|
||||
template <typename ObjT>
|
||||
static const object::ObjectFile&
|
||||
getObject(const object::OwningBinary<ObjT> &Obj) {
|
||||
return *Obj.getBinary();
|
||||
}
|
||||
|
||||
LinkedObjectSetListT LinkedObjSetList;
|
||||
LinkedObjectListT LinkedObjList;
|
||||
NotifyLoadedFtor NotifyLoaded;
|
||||
NotifyFinalizedFtor NotifyFinalized;
|
||||
bool ProcessAllSections = false;
|
||||
|
@ -47,11 +47,12 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
|
||||
|
||||
class OrcCBindingsStack {
|
||||
public:
|
||||
|
||||
using CompileCallbackMgr = orc::JITCompileCallbackManager;
|
||||
using ObjLayerT = orc::RTDyldObjectLinkingLayer<>;
|
||||
using CompileLayerT = orc::IRCompileLayer<ObjLayerT>;
|
||||
using ObjLayerT = orc::RTDyldObjectLinkingLayer;
|
||||
using CompileLayerT = orc::IRCompileLayer<ObjLayerT, orc::SimpleCompiler>;
|
||||
using CODLayerT =
|
||||
orc::CompileOnDemandLayer<CompileLayerT, CompileCallbackMgr>;
|
||||
orc::CompileOnDemandLayer<CompileLayerT, CompileCallbackMgr>;
|
||||
|
||||
using CallbackManagerBuilder =
|
||||
std::function<std::unique_ptr<CompileCallbackMgr>()>;
|
||||
|
@ -198,17 +198,16 @@ public:
|
||||
}
|
||||
|
||||
void addObjectFile(std::unique_ptr<object::ObjectFile> O) override {
|
||||
std::vector<std::unique_ptr<object::ObjectFile>> Objs;
|
||||
Objs.push_back(std::move(O));
|
||||
ObjectLayer.addObjectSet(std::move(Objs), &MemMgr, &Resolver);
|
||||
auto Obj =
|
||||
std::make_shared<object::OwningBinary<object::ObjectFile>>(std::move(O),
|
||||
nullptr);
|
||||
ObjectLayer.addObject(std::move(Obj), &MemMgr, &Resolver);
|
||||
}
|
||||
|
||||
void addObjectFile(object::OwningBinary<object::ObjectFile> O) override {
|
||||
std::vector<std::unique_ptr<object::OwningBinary<object::ObjectFile>>> Objs;
|
||||
Objs.push_back(
|
||||
llvm::make_unique<object::OwningBinary<object::ObjectFile>>(
|
||||
std::move(O)));
|
||||
ObjectLayer.addObjectSet(std::move(Objs), &MemMgr, &Resolver);
|
||||
auto Obj =
|
||||
std::make_shared<object::OwningBinary<object::ObjectFile>>(std::move(O));
|
||||
ObjectLayer.addObject(std::move(Obj), &MemMgr, &Resolver);
|
||||
}
|
||||
|
||||
void addArchive(object::OwningBinary<object::Archive> A) override {
|
||||
@ -260,7 +259,7 @@ public:
|
||||
ArrayRef<GenericValue> ArgValues) override;
|
||||
|
||||
void setObjectCache(ObjectCache *NewCache) override {
|
||||
CompileLayer.setObjectCache(NewCache);
|
||||
CompileLayer.getCompiler().setObjectCache(NewCache);
|
||||
}
|
||||
|
||||
void setProcessAllSections(bool ProcessAllSections) override {
|
||||
@ -298,10 +297,12 @@ private:
|
||||
}
|
||||
std::unique_ptr<object::Binary> &ChildBin = ChildBinOrErr.get();
|
||||
if (ChildBin->isObject()) {
|
||||
std::vector<std::unique_ptr<object::ObjectFile>> ObjSet;
|
||||
ObjSet.push_back(std::unique_ptr<object::ObjectFile>(
|
||||
static_cast<object::ObjectFile *>(ChildBin.release())));
|
||||
ObjectLayer.addObjectSet(std::move(ObjSet), &MemMgr, &Resolver);
|
||||
std::unique_ptr<object::ObjectFile> ChildObj(
|
||||
static_cast<object::ObjectFile*>(ChildBinOrErr->release()));
|
||||
auto Obj =
|
||||
std::make_shared<object::OwningBinary<object::ObjectFile>>(
|
||||
std::move(ChildObj), nullptr);
|
||||
ObjectLayer.addObject(std::move(Obj), &MemMgr, &Resolver);
|
||||
if (auto Sym = ObjectLayer.findSymbol(Name, true))
|
||||
return Sym;
|
||||
}
|
||||
@ -317,29 +318,14 @@ private:
|
||||
|
||||
NotifyObjectLoadedT(OrcMCJITReplacement &M) : M(M) {}
|
||||
|
||||
template <typename ObjListT>
|
||||
void operator()(RTDyldObjectLinkingLayerBase::ObjSetHandleT H,
|
||||
const ObjListT &Objects,
|
||||
const LoadedObjInfoListT &Infos) const {
|
||||
void operator()(RTDyldObjectLinkingLayerBase::ObjHandleT H,
|
||||
const RTDyldObjectLinkingLayer::ObjectPtr &Obj,
|
||||
const LoadedObjectInfo &Info) const {
|
||||
M.UnfinalizedSections[H] = std::move(M.SectionsAllocatedSinceLastLoad);
|
||||
M.SectionsAllocatedSinceLastLoad = SectionAddrSet();
|
||||
assert(Objects.size() == Infos.size() &&
|
||||
"Incorrect number of Infos for Objects.");
|
||||
for (unsigned I = 0; I < Objects.size(); ++I)
|
||||
M.MemMgr.notifyObjectLoaded(&M, getObject(*Objects[I]));
|
||||
M.MemMgr.notifyObjectLoaded(&M, *Obj->getBinary());
|
||||
}
|
||||
|
||||
private:
|
||||
static const object::ObjectFile& getObject(const object::ObjectFile &Obj) {
|
||||
return Obj;
|
||||
}
|
||||
|
||||
template <typename ObjT>
|
||||
static const object::ObjectFile&
|
||||
getObject(const object::OwningBinary<ObjT> &Obj) {
|
||||
return *Obj.getBinary();
|
||||
}
|
||||
|
||||
OrcMCJITReplacement &M;
|
||||
};
|
||||
|
||||
@ -347,7 +333,7 @@ private:
|
||||
public:
|
||||
NotifyFinalizedT(OrcMCJITReplacement &M) : M(M) {}
|
||||
|
||||
void operator()(RTDyldObjectLinkingLayerBase::ObjSetHandleT H) {
|
||||
void operator()(RTDyldObjectLinkingLayerBase::ObjHandleT H) {
|
||||
M.UnfinalizedSections.erase(H);
|
||||
}
|
||||
|
||||
@ -364,8 +350,8 @@ private:
|
||||
return MangledName;
|
||||
}
|
||||
|
||||
using ObjectLayerT = RTDyldObjectLinkingLayer<NotifyObjectLoadedT>;
|
||||
using CompileLayerT = IRCompileLayer<ObjectLayerT>;
|
||||
using ObjectLayerT = RTDyldObjectLinkingLayer;
|
||||
using CompileLayerT = IRCompileLayer<ObjectLayerT, orc::SimpleCompiler>;
|
||||
using LazyEmitLayerT = LazyEmittingLayer<CompileLayerT>;
|
||||
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
@ -385,14 +371,14 @@ private:
|
||||
// that have been emitted but not yet finalized so that we can forward the
|
||||
// mapSectionAddress calls appropriately.
|
||||
using SectionAddrSet = std::set<const void *>;
|
||||
struct ObjSetHandleCompare {
|
||||
bool operator()(ObjectLayerT::ObjSetHandleT H1,
|
||||
ObjectLayerT::ObjSetHandleT H2) const {
|
||||
struct ObjHandleCompare {
|
||||
bool operator()(ObjectLayerT::ObjHandleT H1,
|
||||
ObjectLayerT::ObjHandleT H2) const {
|
||||
return &*H1 < &*H2;
|
||||
}
|
||||
};
|
||||
SectionAddrSet SectionsAllocatedSinceLastLoad;
|
||||
std::map<ObjectLayerT::ObjSetHandleT, SectionAddrSet, ObjSetHandleCompare>
|
||||
std::map<ObjectLayerT::ObjHandleT, SectionAddrSet, ObjHandleCompare>
|
||||
UnfinalizedSections;
|
||||
|
||||
std::vector<object::OwningBinary<object::Archive>> Archives;
|
||||
|
@ -45,11 +45,12 @@ namespace llvm {
|
||||
|
||||
class OrcLazyJIT {
|
||||
public:
|
||||
|
||||
using CompileCallbackMgr = orc::JITCompileCallbackManager;
|
||||
using ObjLayerT = orc::RTDyldObjectLinkingLayer<>;
|
||||
using CompileLayerT = orc::IRCompileLayer<ObjLayerT>;
|
||||
using ObjLayerT = orc::RTDyldObjectLinkingLayer;
|
||||
using CompileLayerT = orc::IRCompileLayer<ObjLayerT, orc::SimpleCompiler>;
|
||||
using TransformFtor =
|
||||
std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>;
|
||||
std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>;
|
||||
using IRDumpLayerT = orc::IRTransformLayer<CompileLayerT, TransformFtor>;
|
||||
using CODLayerT = orc::CompileOnDemandLayer<IRDumpLayerT, CompileCallbackMgr>;
|
||||
using IndirectStubsManagerBuilder = CODLayerT::IndirectStubsManagerBuilderT;
|
||||
|
@ -31,14 +31,14 @@ typedef int MockSymbolResolver;
|
||||
typedef int MockObjectFile;
|
||||
|
||||
// stand-in for llvm::MemoryBuffer set
|
||||
typedef int MockMemoryBufferSet;
|
||||
typedef int MockMemoryBuffer;
|
||||
|
||||
// Mock transform that operates on unique pointers to object files, and
|
||||
// allocates new object files rather than mutating the given ones.
|
||||
struct AllocatingTransform {
|
||||
std::unique_ptr<MockObjectFile>
|
||||
operator()(std::unique_ptr<MockObjectFile> Obj) const {
|
||||
return llvm::make_unique<MockObjectFile>(*Obj + 1);
|
||||
std::shared_ptr<MockObjectFile>
|
||||
operator()(std::shared_ptr<MockObjectFile> Obj) const {
|
||||
return std::make_shared<MockObjectFile>(*Obj + 1);
|
||||
}
|
||||
};
|
||||
|
||||
@ -50,48 +50,41 @@ struct AllocatingTransform {
|
||||
// transform layer called the base layer and forwarded any return value.
|
||||
class MockBaseLayer {
|
||||
public:
|
||||
typedef int ObjSetHandleT;
|
||||
typedef int ObjHandleT;
|
||||
|
||||
MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
|
||||
|
||||
template <typename ObjSetT, typename MemoryManagerPtrT,
|
||||
template <typename ObjPtrT, typename MemoryManagerPtrT,
|
||||
typename SymbolResolverPtrT>
|
||||
ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
ObjHandleT addObject(ObjPtrT Obj, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through";
|
||||
EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through";
|
||||
size_t I = 0;
|
||||
for (auto &ObjPtr : Objects) {
|
||||
EXPECT_EQ(MockObjects[I] + 1, *ObjPtr) << "Transform should be applied";
|
||||
I++;
|
||||
}
|
||||
EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match";
|
||||
LastCalled = "addObjectSet";
|
||||
MockObjSetHandle = 111;
|
||||
return MockObjSetHandle;
|
||||
EXPECT_EQ(MockObject + 1, *Obj) << "Transform should be applied";
|
||||
LastCalled = "addObject";
|
||||
MockObjHandle = 111;
|
||||
return MockObjHandle;
|
||||
}
|
||||
template <typename ObjSetT>
|
||||
void expectAddObjectSet(ObjSetT &Objects, MockMemoryManager *MemMgr,
|
||||
MockSymbolResolver *Resolver) {
|
||||
template <typename ObjPtrT>
|
||||
void expectAddObject(ObjPtrT Obj, MockMemoryManager *MemMgr,
|
||||
MockSymbolResolver *Resolver) {
|
||||
MockManager = *MemMgr;
|
||||
MockResolver = *Resolver;
|
||||
for (auto &ObjPtr : Objects) {
|
||||
MockObjects.push_back(*ObjPtr);
|
||||
}
|
||||
MockObject = *Obj;
|
||||
}
|
||||
void verifyAddObjectSet(ObjSetHandleT Returned) {
|
||||
EXPECT_EQ("addObjectSet", LastCalled);
|
||||
EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through";
|
||||
void verifyAddObject(ObjHandleT Returned) {
|
||||
EXPECT_EQ("addObject", LastCalled);
|
||||
EXPECT_EQ(MockObjHandle, Returned) << "Return should pass through";
|
||||
resetExpectations();
|
||||
}
|
||||
|
||||
void removeObjectSet(ObjSetHandleT H) {
|
||||
EXPECT_EQ(MockObjSetHandle, H);
|
||||
LastCalled = "removeObjectSet";
|
||||
void removeObject(ObjHandleT H) {
|
||||
EXPECT_EQ(MockObjHandle, H);
|
||||
LastCalled = "removeObject";
|
||||
}
|
||||
void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; }
|
||||
void verifyRemoveObjectSet() {
|
||||
EXPECT_EQ("removeObjectSet", LastCalled);
|
||||
void expectRemoveObject(ObjHandleT H) { MockObjHandle = H; }
|
||||
void verifyRemoveObject() {
|
||||
EXPECT_EQ("removeObject", LastCalled);
|
||||
resetExpectations();
|
||||
}
|
||||
|
||||
@ -114,18 +107,18 @@ public:
|
||||
resetExpectations();
|
||||
}
|
||||
|
||||
llvm::JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
|
||||
llvm::JITSymbol findSymbolIn(ObjHandleT H, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
|
||||
EXPECT_EQ(MockObjHandle, H) << "Handle should pass through";
|
||||
EXPECT_EQ(MockName, Name) << "Name should pass through";
|
||||
EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
|
||||
LastCalled = "findSymbolIn";
|
||||
MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
|
||||
return MockSymbol;
|
||||
}
|
||||
void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
|
||||
void expectFindSymbolIn(ObjHandleT H, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
MockObjSetHandle = H;
|
||||
MockObjHandle = H;
|
||||
MockName = Name;
|
||||
MockBool = ExportedSymbolsOnly;
|
||||
}
|
||||
@ -136,26 +129,26 @@ public:
|
||||
resetExpectations();
|
||||
}
|
||||
|
||||
void emitAndFinalize(ObjSetHandleT H) {
|
||||
EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
|
||||
void emitAndFinalize(ObjHandleT H) {
|
||||
EXPECT_EQ(MockObjHandle, H) << "Handle should pass through";
|
||||
LastCalled = "emitAndFinalize";
|
||||
}
|
||||
void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; }
|
||||
void expectEmitAndFinalize(ObjHandleT H) { MockObjHandle = H; }
|
||||
void verifyEmitAndFinalize() {
|
||||
EXPECT_EQ("emitAndFinalize", LastCalled);
|
||||
resetExpectations();
|
||||
}
|
||||
|
||||
void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
|
||||
void mapSectionAddress(ObjHandleT H, const void *LocalAddress,
|
||||
llvm::JITTargetAddress TargetAddr) {
|
||||
EXPECT_EQ(MockObjSetHandle, H);
|
||||
EXPECT_EQ(MockObjHandle, H);
|
||||
EXPECT_EQ(MockLocalAddress, LocalAddress);
|
||||
EXPECT_EQ(MockTargetAddress, TargetAddr);
|
||||
LastCalled = "mapSectionAddress";
|
||||
}
|
||||
void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
|
||||
void expectMapSectionAddress(ObjHandleT H, const void *LocalAddress,
|
||||
llvm::JITTargetAddress TargetAddr) {
|
||||
MockObjSetHandle = H;
|
||||
MockObjHandle = H;
|
||||
MockLocalAddress = LocalAddress;
|
||||
MockTargetAddress = TargetAddr;
|
||||
}
|
||||
@ -169,27 +162,27 @@ private:
|
||||
std::string LastCalled;
|
||||
MockMemoryManager MockManager;
|
||||
MockSymbolResolver MockResolver;
|
||||
std::vector<MockObjectFile> MockObjects;
|
||||
ObjSetHandleT MockObjSetHandle;
|
||||
MockObjectFile MockObject;
|
||||
ObjHandleT MockObjHandle;
|
||||
std::string MockName;
|
||||
bool MockBool;
|
||||
llvm::JITSymbol MockSymbol;
|
||||
const void *MockLocalAddress;
|
||||
llvm::JITTargetAddress MockTargetAddress;
|
||||
MockMemoryBufferSet MockBufferSet;
|
||||
MockMemoryBuffer MockBuffer;
|
||||
|
||||
// Clear remembered parameters between calls
|
||||
void resetExpectations() {
|
||||
LastCalled = "nothing";
|
||||
MockManager = 0;
|
||||
MockResolver = 0;
|
||||
MockObjects.clear();
|
||||
MockObjSetHandle = 0;
|
||||
MockObject = 0;
|
||||
MockObjHandle = 0;
|
||||
MockName = "bogus";
|
||||
MockSymbol = llvm::JITSymbol(nullptr);
|
||||
MockLocalAddress = nullptr;
|
||||
MockTargetAddress = 0;
|
||||
MockBufferSet = 0;
|
||||
MockBuffer = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -204,43 +197,36 @@ TEST(ObjectTransformLayerTest, Main) {
|
||||
// Create a second object transform layer using a transform (as a lambda)
|
||||
// that mutates objects in place, and deals in naked pointers
|
||||
ObjectTransformLayer<MockBaseLayer,
|
||||
std::function<MockObjectFile *(MockObjectFile *)>>
|
||||
T2(M, [](MockObjectFile *Obj) {
|
||||
std::function<std::shared_ptr<MockObjectFile>(
|
||||
std::shared_ptr<MockObjectFile>)>>
|
||||
T2(M, [](std::shared_ptr<MockObjectFile> Obj) {
|
||||
++(*Obj);
|
||||
return Obj;
|
||||
});
|
||||
|
||||
// Instantiate some mock objects to use below
|
||||
MockObjectFile MockObject1 = 211;
|
||||
MockObjectFile MockObject2 = 222;
|
||||
MockMemoryManager MockManager = 233;
|
||||
MockSymbolResolver MockResolver = 244;
|
||||
|
||||
// Test addObjectSet with T1 (allocating, unique pointers)
|
||||
std::vector<std::unique_ptr<MockObjectFile>> Objs1;
|
||||
Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject1));
|
||||
Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject2));
|
||||
// Test addObject with T1 (allocating)
|
||||
auto Obj1 = std::make_shared<MockObjectFile>(211);
|
||||
auto MM = llvm::make_unique<MockMemoryManager>(MockManager);
|
||||
auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver);
|
||||
M.expectAddObjectSet(Objs1, MM.get(), SR.get());
|
||||
auto H = T1.addObjectSet(std::move(Objs1), std::move(MM), std::move(SR));
|
||||
M.verifyAddObjectSet(H);
|
||||
M.expectAddObject(Obj1, MM.get(), SR.get());
|
||||
auto H = T1.addObject(std::move(Obj1), std::move(MM), std::move(SR));
|
||||
M.verifyAddObject(H);
|
||||
|
||||
// Test addObjectSet with T2 (mutating, naked pointers)
|
||||
llvm::SmallVector<MockObjectFile *, 2> Objs2Vec;
|
||||
Objs2Vec.push_back(&MockObject1);
|
||||
Objs2Vec.push_back(&MockObject2);
|
||||
llvm::MutableArrayRef<MockObjectFile *> Objs2(Objs2Vec);
|
||||
M.expectAddObjectSet(Objs2, &MockManager, &MockResolver);
|
||||
H = T2.addObjectSet(Objs2, &MockManager, &MockResolver);
|
||||
M.verifyAddObjectSet(H);
|
||||
EXPECT_EQ(212, MockObject1) << "Expected mutation";
|
||||
EXPECT_EQ(223, MockObject2) << "Expected mutation";
|
||||
// Test addObjectSet with T2 (mutating)
|
||||
auto Obj2 = std::make_shared<MockObjectFile>(222);
|
||||
M.expectAddObject(Obj2, &MockManager, &MockResolver);
|
||||
H = T2.addObject(Obj2, &MockManager, &MockResolver);
|
||||
M.verifyAddObject(H);
|
||||
EXPECT_EQ(223, *Obj2) << "Expected mutation";
|
||||
|
||||
// Test removeObjectSet
|
||||
M.expectRemoveObjectSet(H);
|
||||
T1.removeObjectSet(H);
|
||||
M.verifyRemoveObjectSet();
|
||||
M.expectRemoveObject(H);
|
||||
T1.removeObject(H);
|
||||
M.verifyRemoveObject();
|
||||
|
||||
// Test findSymbol
|
||||
std::string Name = "foo";
|
||||
@ -269,13 +255,13 @@ TEST(ObjectTransformLayerTest, Main) {
|
||||
M.verifyMapSectionAddress();
|
||||
|
||||
// Verify transform getter (non-const)
|
||||
MockObjectFile Mutatee = 277;
|
||||
MockObjectFile *Out = T2.getTransform()(&Mutatee);
|
||||
EXPECT_EQ(&Mutatee, Out) << "Expected in-place transform";
|
||||
EXPECT_EQ(278, Mutatee) << "Expected incrementing transform";
|
||||
auto Mutatee = std::make_shared<MockObjectFile>(277);
|
||||
auto Out = T2.getTransform()(Mutatee);
|
||||
EXPECT_EQ(*Mutatee, *Out) << "Expected in-place transform";
|
||||
EXPECT_EQ(278, *Mutatee) << "Expected incrementing transform";
|
||||
|
||||
// Verify transform getter (const)
|
||||
auto OwnedObj = llvm::make_unique<MockObjectFile>(288);
|
||||
auto OwnedObj = std::make_shared<MockObjectFile>(288);
|
||||
const auto &T1C = T1;
|
||||
OwnedObj = T1C.getTransform()(std::move(OwnedObj));
|
||||
EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
|
||||
@ -287,8 +273,8 @@ TEST(ObjectTransformLayerTest, Main) {
|
||||
// Make sure that ObjectTransformLayer implements the object layer concept
|
||||
// correctly by sandwitching one between an ObjectLinkingLayer and an
|
||||
// IRCompileLayer, verifying that it compiles if we have a call to the
|
||||
// IRComileLayer's addModuleSet that should call the transform layer's
|
||||
// addObjectSet, and also calling the other public transform layer methods
|
||||
// IRComileLayer's addModule that should call the transform layer's
|
||||
// addObject, and also calling the other public transform layer methods
|
||||
// directly to make sure the methods they intend to forward to exist on
|
||||
// the ObjectLinkingLayer.
|
||||
|
||||
@ -309,17 +295,20 @@ TEST(ObjectTransformLayerTest, Main) {
|
||||
};
|
||||
|
||||
// Construct the jit layers.
|
||||
RTDyldObjectLinkingLayer<> BaseLayer;
|
||||
auto IdentityTransform = [](
|
||||
std::unique_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
|
||||
Obj) { return Obj; };
|
||||
RTDyldObjectLinkingLayer BaseLayer;
|
||||
auto IdentityTransform =
|
||||
[](std::shared_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
|
||||
Obj) {
|
||||
return Obj;
|
||||
};
|
||||
ObjectTransformLayer<decltype(BaseLayer), decltype(IdentityTransform)>
|
||||
TransformLayer(BaseLayer, IdentityTransform);
|
||||
auto NullCompiler = [](llvm::Module &) {
|
||||
return llvm::object::OwningBinary<llvm::object::ObjectFile>();
|
||||
return llvm::object::OwningBinary<llvm::object::ObjectFile>(nullptr,
|
||||
nullptr);
|
||||
};
|
||||
IRCompileLayer<decltype(TransformLayer)> CompileLayer(TransformLayer,
|
||||
NullCompiler);
|
||||
IRCompileLayer<decltype(TransformLayer), decltype(NullCompiler)>
|
||||
CompileLayer(TransformLayer, NullCompiler);
|
||||
|
||||
// Make sure that the calls from IRCompileLayer to ObjectTransformLayer
|
||||
// compile.
|
||||
@ -329,11 +318,11 @@ TEST(ObjectTransformLayerTest, Main) {
|
||||
|
||||
// Make sure that the calls from ObjectTransformLayer to ObjectLinkingLayer
|
||||
// compile.
|
||||
decltype(TransformLayer)::ObjSetHandleT ObjSet;
|
||||
TransformLayer.emitAndFinalize(ObjSet);
|
||||
TransformLayer.findSymbolIn(ObjSet, Name, false);
|
||||
decltype(TransformLayer)::ObjHandleT H2;
|
||||
TransformLayer.emitAndFinalize(H2);
|
||||
TransformLayer.findSymbolIn(H2, Name, false);
|
||||
TransformLayer.findSymbol(Name, true);
|
||||
TransformLayer.mapSectionAddress(ObjSet, nullptr, 0);
|
||||
TransformLayer.removeObjectSet(ObjSet);
|
||||
TransformLayer.mapSectionAddress(H2, nullptr, 0);
|
||||
TransformLayer.removeObject(H2);
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
|
||||
bool &DebugSeen;
|
||||
};
|
||||
|
||||
RTDyldObjectLinkingLayer<> ObjLayer;
|
||||
RTDyldObjectLinkingLayer ObjLayer;
|
||||
|
||||
LLVMContext Context;
|
||||
auto M = llvm::make_unique<Module>("", Context);
|
||||
@ -85,9 +85,9 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
auto OwningObj = SimpleCompiler(*TM)(*M);
|
||||
std::vector<object::ObjectFile*> Objs;
|
||||
Objs.push_back(OwningObj.getBinary());
|
||||
auto Obj =
|
||||
std::make_shared<object::OwningBinary<object::ObjectFile>>(
|
||||
SimpleCompiler(*TM)(*M));
|
||||
|
||||
bool DebugSectionSeen = false;
|
||||
auto SMMW =
|
||||
@ -103,21 +103,21 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
|
||||
|
||||
{
|
||||
// Test with ProcessAllSections = false (the default).
|
||||
auto H = ObjLayer.addObjectSet(Objs, SMMW, &*Resolver);
|
||||
auto H = ObjLayer.addObject(Obj, SMMW, &*Resolver);
|
||||
ObjLayer.emitAndFinalize(H);
|
||||
EXPECT_EQ(DebugSectionSeen, false)
|
||||
<< "Unexpected debug info section";
|
||||
ObjLayer.removeObjectSet(H);
|
||||
ObjLayer.removeObject(H);
|
||||
}
|
||||
|
||||
{
|
||||
// Test with ProcessAllSections = true.
|
||||
ObjLayer.setProcessAllSections(true);
|
||||
auto H = ObjLayer.addObjectSet(Objs, SMMW, &*Resolver);
|
||||
auto H = ObjLayer.addObject(Obj, SMMW, &*Resolver);
|
||||
ObjLayer.emitAndFinalize(H);
|
||||
EXPECT_EQ(DebugSectionSeen, true)
|
||||
<< "Expected debug info section not seen";
|
||||
ObjLayer.removeObjectSet(H);
|
||||
ObjLayer.removeObject(H);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
RTDyldObjectLinkingLayer<> ObjLayer;
|
||||
RTDyldObjectLinkingLayer ObjLayer;
|
||||
SimpleCompiler Compile(*TM);
|
||||
|
||||
// Create a pair of modules that will trigger recursive finalization:
|
||||
@ -151,9 +151,9 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
|
||||
Builder.CreateRet(FourtyTwo);
|
||||
}
|
||||
|
||||
auto Obj1 = Compile(*MB1.getModule());
|
||||
std::vector<object::ObjectFile*> Obj1Set;
|
||||
Obj1Set.push_back(Obj1.getBinary());
|
||||
auto Obj1 =
|
||||
std::make_shared<object::OwningBinary<object::ObjectFile>>(
|
||||
Compile(*MB1.getModule()));
|
||||
|
||||
ModuleBuilder MB2(Context, "", "dummy");
|
||||
{
|
||||
@ -164,9 +164,9 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
|
||||
IRBuilder<> Builder(FooEntry);
|
||||
Builder.CreateRet(Builder.CreateCall(BarDecl));
|
||||
}
|
||||
auto Obj2 = Compile(*MB2.getModule());
|
||||
std::vector<object::ObjectFile*> Obj2Set;
|
||||
Obj2Set.push_back(Obj2.getBinary());
|
||||
auto Obj2 =
|
||||
std::make_shared<object::OwningBinary<object::ObjectFile>>(
|
||||
Compile(*MB2.getModule()));
|
||||
|
||||
auto Resolver =
|
||||
createLambdaResolver(
|
||||
@ -180,10 +180,10 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
|
||||
});
|
||||
|
||||
auto SMMW = std::make_shared<SectionMemoryManagerWrapper>();
|
||||
ObjLayer.addObjectSet(std::move(Obj1Set), SMMW, &*Resolver);
|
||||
auto H = ObjLayer.addObjectSet(std::move(Obj2Set), SMMW, &*Resolver);
|
||||
ObjLayer.addObject(std::move(Obj1), SMMW, &*Resolver);
|
||||
auto H = ObjLayer.addObject(std::move(Obj2), SMMW, &*Resolver);
|
||||
ObjLayer.emitAndFinalize(H);
|
||||
ObjLayer.removeObjectSet(H);
|
||||
ObjLayer.removeObject(H);
|
||||
|
||||
// Finalization of module 2 should trigger finalization of module 1.
|
||||
// Verify that finalize on SMMW is only called once.
|
||||
@ -195,7 +195,7 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
RTDyldObjectLinkingLayer<> ObjLayer;
|
||||
RTDyldObjectLinkingLayer ObjLayer;
|
||||
SimpleCompiler Compile(*TM);
|
||||
|
||||
// Create a pair of unrelated modules:
|
||||
@ -222,9 +222,9 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
|
||||
Builder.CreateRet(FourtyTwo);
|
||||
}
|
||||
|
||||
auto Obj1 = Compile(*MB1.getModule());
|
||||
std::vector<object::ObjectFile*> Obj1Set;
|
||||
Obj1Set.push_back(Obj1.getBinary());
|
||||
auto Obj1 =
|
||||
std::make_shared<object::OwningBinary<object::ObjectFile>>(
|
||||
Compile(*MB1.getModule()));
|
||||
|
||||
ModuleBuilder MB2(Context, "", "dummy");
|
||||
{
|
||||
@ -236,16 +236,16 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
|
||||
Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
|
||||
Builder.CreateRet(Seven);
|
||||
}
|
||||
auto Obj2 = Compile(*MB2.getModule());
|
||||
std::vector<object::ObjectFile*> Obj2Set;
|
||||
Obj2Set.push_back(Obj2.getBinary());
|
||||
auto Obj2 =
|
||||
std::make_shared<object::OwningBinary<object::ObjectFile>>(
|
||||
Compile(*MB2.getModule()));
|
||||
|
||||
auto SMMW = std::make_shared<SectionMemoryManagerWrapper>();
|
||||
NullResolver NR;
|
||||
auto H = ObjLayer.addObjectSet(std::move(Obj1Set), SMMW, &NR);
|
||||
ObjLayer.addObjectSet(std::move(Obj2Set), SMMW, &NR);
|
||||
auto H = ObjLayer.addObject(std::move(Obj1), SMMW, &NR);
|
||||
ObjLayer.addObject(std::move(Obj2), SMMW, &NR);
|
||||
ObjLayer.emitAndFinalize(H);
|
||||
ObjLayer.removeObjectSet(H);
|
||||
ObjLayer.removeObject(H);
|
||||
|
||||
// Only one call to needsToReserveAllocationSpace should have been made.
|
||||
EXPECT_EQ(SMMW->NeedsToReserveAllocationSpaceCount, 1)
|
||||
|
Loading…
Reference in New Issue
Block a user