[ORC] Switch RTDyldObjectLinkingLayer to take a unique_ptr<MemoryBuffer> rather

than a shared ObjectFile/MemoryBuffer pair.

There's no need to pre-parse the buffer into an ObjectFile before passing it
down to the linking layer, and moving the parsing into the linking layer allows
us remove the parsing code at each call site.

llvm-svn: 325725
This commit is contained in:
Lang Hames 2018-02-21 21:55:49 +00:00
parent c1b46381db
commit 589eece132
10 changed files with 112 additions and 139 deletions

View File

@ -38,9 +38,23 @@ namespace orc {
/// @brief Simple compile functor: Takes a single IR module and returns an
/// ObjectFile.
class SimpleCompiler {
public:
private:
class SmallVectorMemoryBuffer : public MemoryBuffer {
public:
SmallVectorMemoryBuffer(SmallVector<char, 0> Buffer)
: Buffer(std::move(Buffer)) {
init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(),
false);
}
using CompileResult = object::OwningBinary<object::ObjectFile>;
BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
private:
SmallVector<char, 0> Buffer;
};
public:
using CompileResult = std::unique_ptr<MemoryBuffer>;
/// @brief Construct a simple compile functor with the given target.
SimpleCompiler(TargetMachine &TM, ObjectCache *ObjCache = nullptr)
@ -52,28 +66,34 @@ public:
/// @brief Compile a Module to an ObjectFile.
CompileResult operator()(Module &M) {
CompileResult CachedObject = tryToLoadFromObjectCache(M);
if (CachedObject.getBinary())
if (CachedObject)
return CachedObject;
SmallVector<char, 0> ObjBufferSV;
raw_svector_ostream ObjStream(ObjBufferSV);
legacy::PassManager PM;
MCContext *Ctx;
if (TM.addPassesToEmitMC(PM, Ctx, ObjStream))
llvm_unreachable("Target does not support MC emission.");
PM.run(M);
std::unique_ptr<MemoryBuffer> ObjBuffer(
new ObjectMemoryBuffer(std::move(ObjBufferSV)));
Expected<std::unique_ptr<object::ObjectFile>> Obj =
{
raw_svector_ostream ObjStream(ObjBufferSV);
legacy::PassManager PM;
MCContext *Ctx;
if (TM.addPassesToEmitMC(PM, Ctx, ObjStream))
llvm_unreachable("Target does not support MC emission.");
PM.run(M);
}
auto ObjBuffer =
llvm::make_unique<SmallVectorMemoryBuffer>(std::move(ObjBufferSV));
auto Obj =
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
if (Obj) {
notifyObjectCompiled(M, *ObjBuffer);
return CompileResult(std::move(*Obj), std::move(ObjBuffer));
return std::move(ObjBuffer);
}
// TODO: Actually report errors helpfully.
consumeError(Obj.takeError());
return CompileResult(nullptr, nullptr);
return nullptr;
}
private:
@ -82,19 +102,7 @@ private:
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));
return ObjCache->getObject(&M);
}
void notifyObjectCompiled(const Module &M, const MemoryBuffer &ObjBuffer) {

View File

@ -47,9 +47,7 @@ public:
/// @brief Compile the module, and add the resulting object to the base layer
/// along with the given memory manager and symbol resolver.
Error addModule(VModuleKey K, std::shared_ptr<Module> M) {
using CompileResult = decltype(Compile(*M));
auto Obj = std::make_shared<CompileResult>(Compile(*M));
return BaseLayer.addObject(std::move(K), std::move(Obj));
return BaseLayer.addObject(std::move(K), Compile(*M));
}
/// @brief Remove the module associated with the VModuleKey K.

View File

@ -37,9 +37,7 @@ namespace orc {
class RTDyldObjectLinkingLayerBase {
public:
using ObjectPtr =
std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
using ObjectPtr = std::unique_ptr<MemoryBuffer>;
protected:
@ -95,17 +93,20 @@ public:
using RTDyldObjectLinkingLayerBase::ObjectPtr;
/// @brief Functor for receiving object-loaded notifications.
using NotifyLoadedFtor = std::function<void(
VModuleKey, const ObjectPtr &Obj, const RuntimeDyld::LoadedObjectInfo &)>;
using NotifyLoadedFtor =
std::function<void(VModuleKey, const object::ObjectFile &Obj,
const RuntimeDyld::LoadedObjectInfo &)>;
/// @brief Functor for receiving finalization notifications.
using NotifyFinalizedFtor = std::function<void(VModuleKey)>;
private:
using OwnedObject = object::OwningBinary<object::ObjectFile>;
template <typename MemoryManagerPtrT, typename FinalizerFtor>
class ConcreteLinkedObject : public LinkedObject {
public:
ConcreteLinkedObject(ExecutionSession &ES, ObjectPtr Obj,
ConcreteLinkedObject(ExecutionSession &ES, OwnedObject Obj,
MemoryManagerPtrT MemMgr,
std::shared_ptr<SymbolResolver> Resolver,
FinalizerFtor Finalizer, bool ProcessAllSections)
@ -156,9 +157,8 @@ private:
}
private:
void buildInitialSymbolTable(const ObjectPtr &Obj) {
for (auto &Symbol : Obj->getBinary()->symbols()) {
void buildInitialSymbolTable(const OwnedObject &Obj) {
for (auto &Symbol : Obj.getBinary()->symbols()) {
if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
continue;
Expected<StringRef> SymbolName = Symbol.getName();
@ -181,7 +181,7 @@ private:
// Contains the information needed prior to finalization: the object files,
// memory manager, resolver, and flags needed for RuntimeDyld.
struct PreFinalizeContents {
PreFinalizeContents(ExecutionSession &ES, ObjectPtr Obj,
PreFinalizeContents(ExecutionSession &ES, OwnedObject Obj,
std::shared_ptr<SymbolResolver> Resolver,
FinalizerFtor Finalizer, bool ProcessAllSections)
: ES(ES), Obj(std::move(Obj)), Resolver(std::move(Resolver)),
@ -189,7 +189,7 @@ private:
ProcessAllSections(ProcessAllSections) {}
ExecutionSession &ES;
ObjectPtr Obj;
OwnedObject Obj;
std::shared_ptr<SymbolResolver> Resolver;
FinalizerFtor Finalizer;
bool ProcessAllSections;
@ -202,7 +202,7 @@ private:
template <typename MemoryManagerPtrT, typename FinalizerFtor>
std::unique_ptr<ConcreteLinkedObject<MemoryManagerPtrT, FinalizerFtor>>
createLinkedObject(ExecutionSession &ES, ObjectPtr Obj,
createLinkedObject(ExecutionSession &ES, OwnedObject Obj,
MemoryManagerPtrT MemMgr,
std::shared_ptr<SymbolResolver> Resolver,
FinalizerFtor Finalizer, bool ProcessAllSections) {
@ -242,16 +242,22 @@ public:
}
/// @brief Add an object to the JIT.
Error addObject(VModuleKey K, ObjectPtr Obj) {
auto Finalizer = [&, K](RuntimeDyld &RTDyld, const ObjectPtr &ObjToLoad,
Error addObject(VModuleKey K, ObjectPtr ObjBuffer) {
auto Obj =
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
if (!Obj)
return Obj.takeError();
auto Finalizer = [&, K](RuntimeDyld &RTDyld, const OwnedObject &ObjToLoad,
std::function<void()> LOSHandleLoad) -> Error {
std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info =
RTDyld.loadObject(*ObjToLoad->getBinary());
RTDyld.loadObject(*ObjToLoad.getBinary());
LOSHandleLoad();
if (this->NotifyLoaded)
this->NotifyLoaded(K, ObjToLoad, *Info);
this->NotifyLoaded(K, *ObjToLoad.getBinary(), *Info);
RTDyld.finalizeWithMemoryManagerLocking();
@ -270,8 +276,9 @@ public:
auto R = GetResources(K);
LinkedObjects[K] = createLinkedObject(
ES, std::move(Obj), std::move(R.MemMgr), std::move(R.Resolver),
std::move(Finalizer), ProcessAllSections);
ES, OwnedObject(std::move(*Obj), std::move(ObjBuffer)),
std::move(R.MemMgr), std::move(R.Resolver), std::move(Finalizer),
ProcessAllSections);
return Error::success();
}

View File

@ -306,8 +306,7 @@ public:
using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
using ObjectPtr =
std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
using ObjectPtr = std::unique_ptr<MemoryBuffer>;
/// Create a RemoteObjectClientLayer that communicates with a
/// RemoteObjectServerLayer instance via the given RPCEndpoint.
@ -328,11 +327,10 @@ public:
/// @return A handle that can be used to refer to the loaded object (for
/// symbol searching, finalization, freeing memory, etc.).
Expected<ObjHandleT>
addObject(ObjectPtr Object,
addObject(ObjectPtr ObjBuffer,
std::shared_ptr<LegacyJITSymbolResolver> Resolver) {
StringRef ObjBuffer = Object->getBinary()->getData();
if (auto HandleOrErr =
this->Remote.template callB<AddObject>(ObjBuffer)) {
this->Remote.template callB<AddObject>(ObjBuffer->getBuffer())) {
auto &Handle = *HandleOrErr;
// FIXME: Return an error for this:
assert(!Resolvers.count(Handle) && "Handle already in use?");
@ -461,30 +459,21 @@ private:
Expected<ObjHandleT> addObject(std::string ObjBuffer) {
auto Buffer = llvm::make_unique<StringMemoryBuffer>(std::move(ObjBuffer));
if (auto ObjectOrErr =
object::ObjectFile::createObjectFile(Buffer->getMemBufferRef())) {
auto Object =
std::make_shared<object::OwningBinary<object::ObjectFile>>(
std::move(*ObjectOrErr), std::move(Buffer));
auto Id = HandleIdMgr.getNext();
assert(!BaseLayerHandles.count(Id) && "Id already in use?");
auto Id = HandleIdMgr.getNext();
assert(!BaseLayerHandles.count(Id) && "Id already in use?");
auto Resolver = createLambdaResolver(
[this, Id](const std::string &Name) { return lookup(Id, Name); },
[this, Id](const std::string &Name) {
return lookupInLogicalDylib(Id, Name);
});
auto Resolver =
createLambdaResolver(
[this, Id](const std::string &Name) { return lookup(Id, Name); },
[this, Id](const std::string &Name) {
return lookupInLogicalDylib(Id, Name);
});
if (auto HandleOrErr =
BaseLayer.addObject(std::move(Object), std::move(Resolver))) {
BaseLayerHandles[Id] = std::move(*HandleOrErr);
return Id;
} else
return teeLog(HandleOrErr.takeError());
if (auto HandleOrErr =
BaseLayer.addObject(std::move(Buffer), std::move(Resolver))) {
BaseLayerHandles[Id] = std::move(*HandleOrErr);
return Id;
} else
return teeLog(ObjectOrErr.takeError());
return teeLog(HandleOrErr.takeError());
}
Error removeObject(ObjHandleT H) {

View File

@ -353,24 +353,21 @@ public:
std::unique_ptr<MemoryBuffer> ObjBuffer,
LLVMOrcSymbolResolverFn ExternalResolver,
void *ExternalResolverCtx) {
if (auto ObjOrErr =
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef())) {
auto &Obj = *ObjOrErr;
auto OwningObj =
std::make_shared<OwningObject>(std::move(Obj), std::move(ObjBuffer));
if (auto Obj = object::ObjectFile::createObjectFile(
ObjBuffer->getMemBufferRef())) {
RetKey = ES.allocateVModule();
Resolvers[RetKey] = std::make_shared<CBindingsResolver>(
*this, ExternalResolver, ExternalResolverCtx);
if (auto Err = ObjectLayer.addObject(RetKey, std::move(OwningObj)))
if (auto Err = ObjectLayer.addObject(RetKey, std::move(ObjBuffer)))
return mapError(std::move(Err));
KeyLayers[RetKey] = detail::createGenericLayer(ObjectLayer);
return LLVMOrcErrSuccess;
} else
return mapError(ObjOrErr.takeError());
return mapError(Obj.takeError());
}
JITSymbol findSymbol(const std::string &Name,

View File

@ -263,16 +263,15 @@ public:
}
void addObjectFile(std::unique_ptr<object::ObjectFile> O) override {
auto Obj =
std::make_shared<object::OwningBinary<object::ObjectFile>>(std::move(O),
nullptr);
cantFail(ObjectLayer.addObject(ES.allocateVModule(), std::move(Obj)));
cantFail(ObjectLayer.addObject(
ES.allocateVModule(), MemoryBuffer::getMemBufferCopy(O->getData())));
}
void addObjectFile(object::OwningBinary<object::ObjectFile> O) override {
auto Obj =
std::make_shared<object::OwningBinary<object::ObjectFile>>(std::move(O));
cantFail(ObjectLayer.addObject(ES.allocateVModule(), std::move(Obj)));
std::unique_ptr<object::ObjectFile> Obj;
std::unique_ptr<MemoryBuffer> ObjBuffer;
std::tie(Obj, ObjBuffer) = O.takeBinary();
cantFail(ObjectLayer.addObject(ES.allocateVModule(), std::move(ObjBuffer)));
}
void addArchive(object::OwningBinary<object::Archive> A) override {
@ -375,12 +374,9 @@ private:
}
std::unique_ptr<object::Binary> &ChildBin = ChildBinOrErr.get();
if (ChildBin->isObject()) {
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);
cantFail(ObjectLayer.addObject(ES.allocateVModule(), std::move(Obj)));
cantFail(ObjectLayer.addObject(
ES.allocateVModule(),
MemoryBuffer::getMemBufferCopy(ChildBin->getData())));
if (auto Sym = ObjectLayer.findSymbol(Name, true))
return Sym;
}
@ -396,12 +392,11 @@ private:
NotifyObjectLoadedT(OrcMCJITReplacement &M) : M(M) {}
void operator()(VModuleKey K,
const RTDyldObjectLinkingLayer::ObjectPtr &Obj,
void operator()(VModuleKey K, const object::ObjectFile &Obj,
const RuntimeDyld::LoadedObjectInfo &Info) const {
M.UnfinalizedSections[K] = std::move(M.SectionsAllocatedSinceLastLoad);
M.SectionsAllocatedSinceLastLoad = SectionAddrSet();
M.MemMgr->notifyObjectLoaded(&M, *Obj->getBinary());
M.MemMgr->notifyObjectLoaded(&M, Obj);
}
private:
OrcMCJITReplacement &M;

View File

@ -288,16 +288,13 @@ TEST(ObjectTransformLayerTest, Main) {
std::make_shared<NullResolver>()};
});
auto IdentityTransform =
[](std::shared_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
Obj) {
return Obj;
};
auto IdentityTransform = [](std::unique_ptr<llvm::MemoryBuffer> Obj) {
return Obj;
};
ObjectTransformLayer<decltype(BaseLayer), decltype(IdentityTransform)>
TransformLayer(BaseLayer, IdentityTransform);
auto NullCompiler = [](llvm::Module &) {
return llvm::object::OwningBinary<llvm::object::ObjectFile>(nullptr,
nullptr);
return std::unique_ptr<llvm::MemoryBuffer>(nullptr);
};
IRCompileLayer<decltype(TransformLayer), decltype(NullCompiler)>
CompileLayer(TransformLayer, NullCompiler);

View File

@ -38,13 +38,11 @@ protected:
return MB.takeModule();
}
std::shared_ptr<object::OwningBinary<object::ObjectFile>>
createTestObject() {
std::unique_ptr<MemoryBuffer> createTestObject() {
orc::SimpleCompiler IRCompiler(*TM);
auto M = createTestModule(TM->getTargetTriple());
M->setDataLayout(TM->createDataLayout());
return std::make_shared<object::OwningBinary<object::ObjectFile>>(
IRCompiler(*M));
return IRCompiler(*M);
}
typedef int (*MainFnTy)();
@ -148,12 +146,7 @@ TEST_F(OrcCAPIExecutionTest, TestAddObjectFile) {
if (!TM)
return;
std::unique_ptr<MemoryBuffer> ObjBuffer;
{
auto OwningObj = createTestObject();
auto ObjAndBuffer = OwningObj->takeBinary();
ObjBuffer = std::move(ObjAndBuffer.second);
}
auto ObjBuffer = createTestObject();
LLVMOrcJITStackRef JIT =
LLVMOrcCreateInstance(wrap(TM.get()));

View File

@ -95,14 +95,13 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
if (!TM)
return;
auto Obj =
std::make_shared<object::OwningBinary<object::ObjectFile>>(
SimpleCompiler(*TM)(*M));
auto Obj = SimpleCompiler(*TM)(*M);
{
// Test with ProcessAllSections = false (the default).
auto K = ES.allocateVModule();
cantFail(ObjLayer.addObject(K, Obj));
cantFail(ObjLayer.addObject(
K, MemoryBuffer::getMemBufferCopy(Obj->getBuffer())));
cantFail(ObjLayer.emitAndFinalize(K));
EXPECT_EQ(DebugSectionSeen, false)
<< "Unexpected debug info section";
@ -113,7 +112,7 @@ TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
// Test with ProcessAllSections = true.
ObjLayer.setProcessAllSections(true);
auto K = ES.allocateVModule();
cantFail(ObjLayer.addObject(K, Obj));
cantFail(ObjLayer.addObject(K, std::move(Obj)));
cantFail(ObjLayer.emitAndFinalize(K));
EXPECT_EQ(DebugSectionSeen, true)
<< "Expected debug info section not seen";
@ -164,9 +163,7 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
Builder.CreateRet(FourtyTwo);
}
auto Obj1 =
std::make_shared<object::OwningBinary<object::ObjectFile>>(
Compile(*MB1.getModule()));
auto Obj1 = Compile(*MB1.getModule());
ModuleBuilder MB2(Context, "", "dummy");
{
@ -177,9 +174,7 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
IRBuilder<> Builder(FooEntry);
Builder.CreateRet(Builder.CreateCall(BarDecl));
}
auto Obj2 =
std::make_shared<object::OwningBinary<object::ObjectFile>>(
Compile(*MB2.getModule()));
auto Obj2 = Compile(*MB2.getModule());
auto K1 = ES.allocateVModule();
Resolvers[K1] = std::make_shared<NullResolver>();
@ -249,9 +244,7 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
Builder.CreateRet(FourtyTwo);
}
auto Obj1 =
std::make_shared<object::OwningBinary<object::ObjectFile>>(
Compile(*MB1.getModule()));
auto Obj1 = Compile(*MB1.getModule());
ModuleBuilder MB2(Context, "", "dummy");
{
@ -263,9 +256,7 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
Builder.CreateRet(Seven);
}
auto Obj2 =
std::make_shared<object::OwningBinary<object::ObjectFile>>(
Compile(*MB2.getModule()));
auto Obj2 = Compile(*MB2.getModule());
auto K = ES.allocateVModule();
cantFail(ObjLayer.addObject(K, std::move(Obj1)));
@ -288,7 +279,7 @@ TEST_F(RTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) {
return RTDyldObjectLinkingLayer::Resources{
nullptr, std::make_shared<NullResolver>()};
},
[](VModuleKey, const RTDyldObjectLinkingLayer::ObjectPtr &obj,
[](VModuleKey, const object::ObjectFile &obj,
const RuntimeDyld::LoadedObjectInfo &info) {});
}

View File

@ -24,8 +24,7 @@ public:
using ObjHandleT = uint64_t;
using ObjectPtr =
std::shared_ptr<object::OwningBinary<object::ObjectFile>>;
using ObjectPtr = std::unique_ptr<MemoryBuffer>;
using LookupFn = std::function<JITSymbol(StringRef, bool)>;
using SymbolLookupTable = std::map<ObjHandleT, LookupFn>;
@ -43,7 +42,7 @@ public:
Expected<ObjHandleT> addObject(ObjectPtr Obj,
std::shared_ptr<JITSymbolResolver> Resolver) {
return AddObject(Obj, SymTab);
return AddObject(std::move(Obj), SymTab);
}
Error removeObject(ObjHandleT H) {
@ -102,8 +101,7 @@ MockObjectLayer::ObjectPtr createTestObject() {
B.CreateRet(ConstantInt::getSigned(Type::getInt32Ty(Ctx), 42));
SimpleCompiler IRCompiler(*TM);
return std::make_shared<object::OwningBinary<object::ObjectFile>>(
IRCompiler(*MB.getModule()));
return IRCompiler(*MB.getModule());
}
TEST(RemoteObjectLayer, AddObject) {
@ -121,7 +119,7 @@ TEST(RemoteObjectLayer, AddObject) {
// Copy the bytes out of the test object: the copy will be used to verify
// that the original is correctly transmitted over RPC to the mock layer.
StringRef ObjBytes = TestObject->getBinary()->getData();
StringRef ObjBytes = TestObject->getBuffer();
std::vector<char> ObjContents(ObjBytes.size());
std::copy(ObjBytes.begin(), ObjBytes.end(), ObjContents.begin());
@ -134,7 +132,7 @@ TEST(RemoteObjectLayer, AddObject) {
MockObjectLayer::SymbolLookupTable &SymTab) {
// Check that the received object file content matches the original.
StringRef RPCObjContents = Obj->getBinary()->getData();
StringRef RPCObjContents = Obj->getBuffer();
EXPECT_EQ(RPCObjContents.size(), ObjContents.size())
<< "RPC'd object file has incorrect size";
EXPECT_TRUE(std::equal(RPCObjContents.begin(), RPCObjContents.end(),