llvm-project/llvm/unittests/ExecutionEngine/Orc/LazyCallThroughAndReexportsTest.cpp
Lang Hames 300deebf41 [ORC] Make LazyReexportsManager implement ResourceManager.
This ensures that the reexports mappings are cleared when the resource tracker
associated with each mapping is removed.
2024-12-17 18:45:16 +11:00

147 lines
4.8 KiB
C++

#include "OrcTestCommon.h"
#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
#include "llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h"
#include "llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::orc;
class LazyReexportsTest : public CoreAPIsBasedStandardTest {};
static int dummyTarget() { return 42; }
TEST_F(LazyReexportsTest, BasicLocalCallThroughManagerOperation) {
// Create a callthrough manager for the host (if possible) and verify that
// a call to the lazy call-through:
// (1) Materializes the MU. This verifies that the symbol was looked up, and
// that we didn't arrive at the target via some other path
// (2) Returns the expected value (which we take as proof that the call
// reached the target).
auto JTMB = JITTargetMachineBuilder::detectHost();
// Bail out if we can not detect the host.
if (!JTMB) {
consumeError(JTMB.takeError());
GTEST_SKIP();
}
// Bail out if we can not build a local call-through manager.
auto LCTM = createLocalLazyCallThroughManager(JTMB->getTargetTriple(), ES,
ExecutorAddr());
if (!LCTM) {
consumeError(LCTM.takeError());
GTEST_SKIP();
}
auto DummyTarget = ES.intern("DummyTarget");
bool DummyTargetMaterialized = false;
cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}),
[&](std::unique_ptr<MaterializationResponsibility> R) {
DummyTargetMaterialized = true;
// No dependencies registered, can't fail.
cantFail(R->notifyResolved({{DummyTarget,
{ExecutorAddr::fromPtr(&dummyTarget),
JITSymbolFlags::Exported}}}));
cantFail(R->notifyEmitted({}));
})));
unsigned NotifyResolvedCount = 0;
auto NotifyResolved = [&](ExecutorAddr ResolvedAddr) {
++NotifyResolvedCount;
return Error::success();
};
auto CallThroughTrampoline = cantFail((*LCTM)->getCallThroughTrampoline(
JD, DummyTarget, std::move(NotifyResolved)));
auto CTTPtr = CallThroughTrampoline.toPtr<int (*)()>();
// Call twice to verify nothing unexpected happens on redundant calls.
auto Result = CTTPtr();
(void)CTTPtr();
EXPECT_TRUE(DummyTargetMaterialized)
<< "CallThrough did not materialize target";
EXPECT_EQ(NotifyResolvedCount, 1U)
<< "CallThrough should have generated exactly one 'NotifyResolved' call";
EXPECT_EQ(Result, 42) << "Failed to call through to target";
}
static void *noReentry(void *) { abort(); }
TEST(JITLinkLazyReexportsTest, Basics) {
OrcNativeTarget::initialize();
auto J = LLJITBuilder().create();
if (!J) {
dbgs() << toString(J.takeError()) << "\n";
// consumeError(J.takeError());
GTEST_SKIP();
}
if (!isa<ObjectLinkingLayer>((*J)->getObjLinkingLayer()))
GTEST_SKIP();
auto &OLL = cast<ObjectLinkingLayer>((*J)->getObjLinkingLayer());
auto RSMgr = JITLinkRedirectableSymbolManager::Create(OLL);
if (!RSMgr) {
dbgs() << "Boom for RSMgr\n";
consumeError(RSMgr.takeError());
GTEST_SKIP();
}
auto &ES = (*J)->getExecutionSession();
auto &JD = ES.createBareJITDylib("JD");
cantFail(JD.define(absoluteSymbols(
{{ES.intern("__orc_rt_reentry"),
{ExecutorAddr::fromPtr(&noReentry),
JITSymbolFlags::Exported | JITSymbolFlags::Callable}}})));
auto LRMgr = createJITLinkLazyReexportsManager(OLL, **RSMgr, JD);
if (!LRMgr) {
dbgs() << "Boom for LRMgr\n";
consumeError(LRMgr.takeError());
GTEST_SKIP();
}
auto Foo = ES.intern("foo");
auto Bar = ES.intern("bar");
auto RT = JD.createResourceTracker();
cantFail(JD.define(
lazyReexports(
**LRMgr,
{{Foo, {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Callable}}}),
RT));
// Check flags after adding Foo -> Bar lazy reexport.
auto SF = cantFail(
ES.lookupFlags(LookupKind::Static, makeJITDylibSearchOrder(&JD),
{{Foo, SymbolLookupFlags::WeaklyReferencedSymbol}}));
EXPECT_EQ(SF.size(), 1U);
EXPECT_TRUE(SF.count(Foo));
EXPECT_EQ(SF[Foo], JITSymbolFlags::Exported | JITSymbolFlags::Callable);
// Remove reexport without running it.
if (auto Err = RT->remove()) {
EXPECT_THAT_ERROR(std::move(Err), Succeeded());
return;
}
// Check flags after adding Foo -> Bar lazy reexport.
SF = cantFail(
ES.lookupFlags(LookupKind::Static, makeJITDylibSearchOrder(&JD),
{{Foo, SymbolLookupFlags::WeaklyReferencedSymbol}}));
EXPECT_EQ(SF.size(), 0U);
}