1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 20:23:11 +01:00

[ORC] Make RuntimeDyldObjectLinkingLayer2 take memory managers by unique_ptr.

The existing memory manager API can not be shared between objects when linking
concurrently (since there is no way to know which concurrent allocations were
performed on behalf of which object, and hence which allocations would be safe
to finalize when finalizeMemory is called). For now, we can work around this by
requiring a new memory manager for each object.

This change only affects the concurrent version of the ORC APIs.

llvm-svn: 341579
This commit is contained in:
Lang Hames 2018-09-06 19:39:26 +00:00
parent 3468c2d4f3
commit ecf8dee5a3
4 changed files with 8 additions and 188 deletions

View File

@ -91,7 +91,7 @@ protected:
LLJIT(std::unique_ptr<ExecutionSession> ES, std::unique_ptr<TargetMachine> TM,
DataLayout DL);
std::shared_ptr<RuntimeDyld::MemoryManager> getMemoryManager(VModuleKey K);
std::unique_ptr<RuntimeDyld::MemoryManager> getMemoryManager(VModuleKey K);
std::string mangle(StringRef UnmangledName);

View File

@ -47,7 +47,7 @@ public:
using NotifyEmittedFunction = std::function<void(VModuleKey)>;
using GetMemoryManagerFunction =
std::function<std::shared_ptr<RuntimeDyld::MemoryManager>(VModuleKey)>;
std::function<std::unique_ptr<RuntimeDyld::MemoryManager>(VModuleKey)>;
/// Construct an ObjectLinkingLayer with the given NotifyLoaded,
/// and NotifyEmitted functors.

View File

@ -59,7 +59,7 @@ LLJIT::LLJIT(std::unique_ptr<ExecutionSession> ES,
CompileLayer(*this->ES, ObjLinkingLayer, SimpleCompiler(*this->TM)),
CtorRunner(Main), DtorRunner(Main) {}
std::shared_ptr<RuntimeDyld::MemoryManager>
std::unique_ptr<RuntimeDyld::MemoryManager>
LLJIT::getMemoryManager(VModuleKey K) {
return llvm::make_unique<SectionMemoryManager>();
}

View File

@ -28,22 +28,6 @@ namespace {
class RTDyldObjectLinkingLayer2ExecutionTest : public testing::Test,
public OrcExecutionTest {};
class SectionMemoryManagerWrapper : public SectionMemoryManager {
public:
int FinalizationCount = 0;
int NeedsToReserveAllocationSpaceCount = 0;
bool needsToReserveAllocationSpace() override {
++NeedsToReserveAllocationSpaceCount;
return SectionMemoryManager::needsToReserveAllocationSpace();
}
bool finalizeMemory(std::string *ErrMsg = nullptr) override {
++FinalizationCount;
return SectionMemoryManager::finalizeMemory(ErrMsg);
}
};
// Adds an object with a debug section to RuntimeDyld and then returns whether
// the debug section was passed to the memory manager.
static bool testSetProcessAllSections(std::unique_ptr<MemoryBuffer> Obj,
@ -65,13 +49,14 @@ static bool testSetProcessAllSections(std::unique_ptr<MemoryBuffer> Obj,
};
bool DebugSectionSeen = false;
auto MM = std::make_shared<MemoryManagerWrapper>(DebugSectionSeen);
ExecutionSession ES;
auto &JD = ES.createJITDylib("main");
auto Foo = ES.getSymbolStringPool().intern("foo");
RTDyldObjectLinkingLayer2 ObjLayer(ES, [&MM](VModuleKey) { return MM; });
RTDyldObjectLinkingLayer2 ObjLayer(ES, [&DebugSectionSeen](VModuleKey) {
return llvm::make_unique<MemoryManagerWrapper>(DebugSectionSeen);
});
auto OnResolveDoNothing = [](Expected<SymbolMap> R) {
cantFail(std::move(R));
@ -165,7 +150,7 @@ TEST(RTDyldObjectLinkingLayer2Test, TestOverrideObjectFlags) {
auto &JD = ES.createJITDylib("main");
auto Foo = ES.getSymbolStringPool().intern("foo");
RTDyldObjectLinkingLayer2 ObjLayer(
ES, [](VModuleKey) { return std::make_shared<SectionMemoryManager>(); });
ES, [](VModuleKey) { return llvm::make_unique<SectionMemoryManager>(); });
IRCompileLayer2 CompileLayer(ES, ObjLayer, FunkySimpleCompiler(*TM));
ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true);
@ -226,7 +211,7 @@ TEST(RTDyldObjectLinkingLayer2Test, TestAutoClaimResponsibilityForSymbols) {
auto &JD = ES.createJITDylib("main");
auto Foo = ES.getSymbolStringPool().intern("foo");
RTDyldObjectLinkingLayer2 ObjLayer(
ES, [](VModuleKey) { return std::make_shared<SectionMemoryManager>(); });
ES, [](VModuleKey) { return llvm::make_unique<SectionMemoryManager>(); });
IRCompileLayer2 CompileLayer(ES, ObjLayer, FunkySimpleCompiler(*TM));
ObjLayer.setAutoClaimResponsibilityForObjectSymbols(true);
@ -237,169 +222,4 @@ TEST(RTDyldObjectLinkingLayer2Test, TestAutoClaimResponsibilityForSymbols) {
NoDependenciesToRegister);
}
TEST(RTDyldObjectLinkingLayer2Test, NoDuplicateFinalization) {
// Create a pair of modules that will trigger recursive finalization:
// Module 1:
// int bar() { return 42; }
// Module 2:
// int bar();
// int foo() { return bar(); }
//
// Verify that the memory manager is only finalized once (for Module 2).
// Failure suggests that finalize is being called on the inner RTDyld
// instance (for Module 1) which is unsafe, as it will prevent relocation of
// Module 2.
// Initialize the native target in case this is the first unit test
// to try to build a TM.
OrcNativeTarget::initialize();
std::unique_ptr<TargetMachine> TM(
EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",
SmallVector<std::string, 1>()));
if (!TM)
return;
LLVMContext Context;
ExecutionSession ES;
auto &JD = ES.createJITDylib("main");
auto Foo = ES.getSymbolStringPool().intern("foo");
auto MM = std::make_shared<SectionMemoryManagerWrapper>();
RTDyldObjectLinkingLayer2 ObjLayer(ES, [&](VModuleKey K) { return MM; });
SimpleCompiler Compile(*TM);
ModuleBuilder MB1(Context, TM->getTargetTriple().str(), "dummy");
{
MB1.getModule()->setDataLayout(TM->createDataLayout());
Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar");
BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
IRBuilder<> Builder(BarEntry);
IntegerType *Int32Ty = IntegerType::get(Context, 32);
Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
Builder.CreateRet(FourtyTwo);
}
auto Obj1 = Compile(*MB1.getModule());
ModuleBuilder MB2(Context, TM->getTargetTriple().str(), "dummy");
{
MB2.getModule()->setDataLayout(TM->createDataLayout());
Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar");
Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo");
BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
IRBuilder<> Builder(FooEntry);
Builder.CreateRet(Builder.CreateCall(BarDecl));
}
auto Obj2 = Compile(*MB2.getModule());
auto K1 = ES.allocateVModule();
cantFail(ObjLayer.add(JD, K1, std::move(Obj1)));
auto K2 = ES.allocateVModule();
cantFail(ObjLayer.add(JD, K2, std::move(Obj2)));
auto OnResolve = [](Expected<SymbolMap> Symbols) {
cantFail(std::move(Symbols));
};
auto OnReady = [](Error Err) { cantFail(std::move(Err)); };
ES.lookup({&JD}, {Foo}, OnResolve, OnReady, NoDependenciesToRegister);
// Finalization of module 2 should trigger finalization of module 1.
// Verify that finalize on SMMW is only called once.
EXPECT_EQ(MM->FinalizationCount, 1) << "Extra call to finalize";
}
TEST(RTDyldObjectLinkingLayer2Test, NoPrematureAllocation) {
// Create a pair of unrelated modules:
//
// Module 1:
// int foo() { return 42; }
// Module 2:
// int bar() { return 7; }
//
// Both modules will share a memory manager. We want to verify that the
// second object is not loaded before the first one is finalized. To do this
// in a portable way, we abuse the
// RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
// called once per object before any sections are allocated.
// Initialize the native target in case this is the first unit test
// to try to build a TM.
OrcNativeTarget::initialize();
std::unique_ptr<TargetMachine> TM(
EngineBuilder().selectTarget(Triple("x86_64-unknown-linux-gnu"), "", "",
SmallVector<std::string, 1>()));
if (!TM)
return;
ExecutionSession ES;
auto &JD = ES.createJITDylib("main");
auto Foo = ES.getSymbolStringPool().intern("foo");
auto MM = std::make_shared<SectionMemoryManagerWrapper>();
RTDyldObjectLinkingLayer2 ObjLayer(ES, [&MM](VModuleKey K) { return MM; });
SimpleCompiler Compile(*TM);
LLVMContext Context;
ModuleBuilder MB1(Context, TM->getTargetTriple().str(), "dummy");
{
MB1.getModule()->setDataLayout(TM->createDataLayout());
Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo");
BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
IRBuilder<> Builder(BarEntry);
IntegerType *Int32Ty = IntegerType::get(Context, 32);
Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
Builder.CreateRet(FourtyTwo);
}
auto Obj1 = Compile(*MB1.getModule());
ModuleBuilder MB2(Context, TM->getTargetTriple().str(), "dummy");
{
MB2.getModule()->setDataLayout(TM->createDataLayout());
Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar");
BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
IRBuilder<> Builder(BarEntry);
IntegerType *Int32Ty = IntegerType::get(Context, 32);
Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
Builder.CreateRet(Seven);
}
auto Obj2 = Compile(*MB2.getModule());
cantFail(ObjLayer.add(JD, ES.allocateVModule(), std::move(Obj1)));
cantFail(ObjLayer.add(JD, ES.allocateVModule(), std::move(Obj2)));
auto OnResolve = [](Expected<SymbolMap> Result) {
cantFail(std::move(Result));
};
auto OnReady = [](Error Err) { cantFail(std::move(Err)); };
ES.lookup({&JD}, {Foo}, OnResolve, OnReady, NoDependenciesToRegister);
// Only one call to needsToReserveAllocationSpace should have been made.
EXPECT_EQ(MM->NeedsToReserveAllocationSpaceCount, 1)
<< "More than one call to needsToReserveAllocationSpace "
"(multiple unrelated objects loaded prior to finalization)";
}
TEST(RTDyldObjectLinkingLayer2Test, TestNotifyLoadedSignature) {
ExecutionSession ES;
RTDyldObjectLinkingLayer2 ObjLayer(
ES,
[](VModuleKey) -> std::shared_ptr<RuntimeDyld::MemoryManager> {
return nullptr;
},
[](VModuleKey, const object::ObjectFile &obj,
const RuntimeDyld::LoadedObjectInfo &info) {});
}
} // end anonymous namespace