| #include "OrcTestCommon.h" |
| #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" |
| #include "llvm/ExecutionEngine/Orc/LazyReexports.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()); |
| return; |
| } |
| |
| // Bail out if we can not build a local call-through manager. |
| auto LCTM = createLocalLazyCallThroughManager(JTMB->getTargetTriple(), ES, 0); |
| if (!LCTM) { |
| consumeError(LCTM.takeError()); |
| return; |
| } |
| |
| auto DummyTarget = ES.intern("DummyTarget"); |
| |
| bool DummyTargetMaterialized = false; |
| |
| cantFail(JD.define(llvm::make_unique<SimpleMaterializationUnit>( |
| SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}), |
| [&](MaterializationResponsibility R) { |
| DummyTargetMaterialized = true; |
| R.resolve( |
| {{DummyTarget, |
| JITEvaluatedSymbol(static_cast<JITTargetAddress>( |
| reinterpret_cast<uintptr_t>(&dummyTarget)), |
| JITSymbolFlags::Exported)}}); |
| R.emit(); |
| }))); |
| |
| unsigned NotifyResolvedCount = 0; |
| auto NotifyResolved = LazyCallThroughManager::createNotifyResolvedFunction( |
| [&](JITDylib &JD, const SymbolStringPtr &SymbolName, |
| JITTargetAddress ResolvedAddr) { |
| ++NotifyResolvedCount; |
| return Error::success(); |
| }); |
| |
| auto CallThroughTrampoline = cantFail((*LCTM)->getCallThroughTrampoline( |
| JD, DummyTarget, std::move(NotifyResolved))); |
| |
| auto CTTPtr = reinterpret_cast<int (*)()>( |
| static_cast<uintptr_t>(CallThroughTrampoline)); |
| |
| // 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"; |
| } |