147 lines · cpp
1#include "OrcTestCommon.h"2#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"3#include "llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h"4#include "llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h"5#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"6#include "llvm/ExecutionEngine/Orc/LLJIT.h"7#include "llvm/ExecutionEngine/Orc/LazyReexports.h"8#include "llvm/Testing/Support/Error.h"9#include "gtest/gtest.h"10 11using namespace llvm;12using namespace llvm::orc;13 14class LazyReexportsTest : public CoreAPIsBasedStandardTest {};15 16static int dummyTarget() { return 42; }17 18TEST_F(LazyReexportsTest, BasicLocalCallThroughManagerOperation) {19 // Create a callthrough manager for the host (if possible) and verify that20 // a call to the lazy call-through:21 // (1) Materializes the MU. This verifies that the symbol was looked up, and22 // that we didn't arrive at the target via some other path23 // (2) Returns the expected value (which we take as proof that the call24 // reached the target).25 26 auto JTMB = JITTargetMachineBuilder::detectHost();27 28 // Bail out if we can not detect the host.29 if (!JTMB) {30 consumeError(JTMB.takeError());31 GTEST_SKIP();32 }33 34 // Bail out if we can not build a local call-through manager.35 auto LCTM = createLocalLazyCallThroughManager(JTMB->getTargetTriple(), ES,36 ExecutorAddr());37 if (!LCTM) {38 consumeError(LCTM.takeError());39 GTEST_SKIP();40 }41 42 auto DummyTarget = ES.intern("DummyTarget");43 44 bool DummyTargetMaterialized = false;45 46 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(47 SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}),48 [&](std::unique_ptr<MaterializationResponsibility> R) {49 DummyTargetMaterialized = true;50 // No dependencies registered, can't fail.51 cantFail(R->notifyResolved({{DummyTarget,52 {ExecutorAddr::fromPtr(&dummyTarget),53 JITSymbolFlags::Exported}}}));54 cantFail(R->notifyEmitted({}));55 })));56 57 unsigned NotifyResolvedCount = 0;58 auto NotifyResolved = [&](ExecutorAddr ResolvedAddr) {59 ++NotifyResolvedCount;60 return Error::success();61 };62 63 auto CallThroughTrampoline = cantFail((*LCTM)->getCallThroughTrampoline(64 JD, DummyTarget, std::move(NotifyResolved)));65 66 auto CTTPtr = CallThroughTrampoline.toPtr<int (*)()>();67 68 // Call twice to verify nothing unexpected happens on redundant calls.69 auto Result = CTTPtr();70 (void)CTTPtr();71 72 EXPECT_TRUE(DummyTargetMaterialized)73 << "CallThrough did not materialize target";74 EXPECT_EQ(NotifyResolvedCount, 1U)75 << "CallThrough should have generated exactly one 'NotifyResolved' call";76 EXPECT_EQ(Result, 42) << "Failed to call through to target";77}78 79static void *noReentry(void *) { abort(); }80 81TEST(JITLinkLazyReexportsTest, Basics) {82 OrcNativeTarget::initialize();83 84 auto J = LLJITBuilder().create();85 if (!J) {86 dbgs() << toString(J.takeError()) << "\n";87 // consumeError(J.takeError());88 GTEST_SKIP();89 }90 if (!isa<ObjectLinkingLayer>((*J)->getObjLinkingLayer()))91 GTEST_SKIP();92 93 auto &OLL = cast<ObjectLinkingLayer>((*J)->getObjLinkingLayer());94 95 auto RSMgr = JITLinkRedirectableSymbolManager::Create(OLL);96 if (!RSMgr) {97 dbgs() << "Boom for RSMgr\n";98 consumeError(RSMgr.takeError());99 GTEST_SKIP();100 }101 102 auto &ES = (*J)->getExecutionSession();103 104 auto &JD = ES.createBareJITDylib("JD");105 cantFail(JD.define(absoluteSymbols(106 {{ES.intern("__orc_rt_reentry"),107 {ExecutorAddr::fromPtr(&noReentry),108 JITSymbolFlags::Exported | JITSymbolFlags::Callable}}})));109 110 auto LRMgr = createJITLinkLazyReexportsManager(OLL, **RSMgr, JD);111 if (!LRMgr) {112 dbgs() << "Boom for LRMgr\n";113 consumeError(LRMgr.takeError());114 GTEST_SKIP();115 }116 117 auto Foo = ES.intern("foo");118 auto Bar = ES.intern("bar");119 120 auto RT = JD.createResourceTracker();121 cantFail(JD.define(122 lazyReexports(123 **LRMgr,124 {{Foo, {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Callable}}}),125 RT));126 127 // Check flags after adding Foo -> Bar lazy reexport.128 auto SF = cantFail(129 ES.lookupFlags(LookupKind::Static, makeJITDylibSearchOrder(&JD),130 {{Foo, SymbolLookupFlags::WeaklyReferencedSymbol}}));131 EXPECT_EQ(SF.size(), 1U);132 EXPECT_TRUE(SF.count(Foo));133 EXPECT_EQ(SF[Foo], JITSymbolFlags::Exported | JITSymbolFlags::Callable);134 135 // Remove reexport without running it.136 if (auto Err = RT->remove()) {137 EXPECT_THAT_ERROR(std::move(Err), Succeeded());138 return;139 }140 141 // Check flags after adding Foo -> Bar lazy reexport.142 SF = cantFail(143 ES.lookupFlags(LookupKind::Static, makeJITDylibSearchOrder(&JD),144 {{Foo, SymbolLookupFlags::WeaklyReferencedSymbol}}));145 EXPECT_EQ(SF.size(), 0U);146}147