1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
#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);
}
|