Lang Hames | c1275e7 | 2018-09-26 04:18:30 +0000 | [diff] [blame] | 1 | #include "OrcTestCommon.h" |
Lang Hames | d435ce4 | 2018-09-30 19:12:23 +0000 | [diff] [blame] | 2 | #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" |
Lang Hames | c1275e7 | 2018-09-26 04:18:30 +0000 | [diff] [blame] | 3 | #include "llvm/ExecutionEngine/Orc/LazyReexports.h" |
| 4 | #include "gtest/gtest.h" |
| 5 | |
| 6 | using namespace llvm; |
| 7 | using namespace llvm::orc; |
| 8 | |
| 9 | class LazyReexportsTest : public CoreAPIsBasedStandardTest {}; |
| 10 | |
| 11 | static int dummyTarget() { return 42; } |
| 12 | |
| 13 | TEST_F(LazyReexportsTest, BasicLocalCallThroughManagerOperation) { |
| 14 | // Create a callthrough manager for the host (if possible) and verify that |
| 15 | // a call to the lazy call-through: |
| 16 | // (1) Materializes the MU. This verifies that the symbol was looked up, and |
| 17 | // that we didn't arrive at the target via some other path |
| 18 | // (2) Returns the expected value (which we take as proof that the call |
| 19 | // reached the target). |
| 20 | |
| 21 | auto JTMB = JITTargetMachineBuilder::detectHost(); |
| 22 | |
| 23 | // Bail out if we can not detect the host. |
| 24 | if (!JTMB) { |
| 25 | consumeError(JTMB.takeError()); |
| 26 | return; |
| 27 | } |
| 28 | |
| 29 | // Bail out if we can not build a local call-through manager. |
| 30 | auto LCTM = createLocalLazyCallThroughManager(JTMB->getTargetTriple(), ES, 0); |
| 31 | if (!LCTM) { |
| 32 | consumeError(LCTM.takeError()); |
| 33 | return; |
| 34 | } |
| 35 | |
Lang Hames | 71d781c | 2018-09-30 23:18:24 +0000 | [diff] [blame] | 36 | auto DummyTarget = ES.intern("DummyTarget"); |
Lang Hames | c1275e7 | 2018-09-26 04:18:30 +0000 | [diff] [blame] | 37 | |
| 38 | bool DummyTargetMaterialized = false; |
| 39 | |
| 40 | cantFail(JD.define(llvm::make_unique<SimpleMaterializationUnit>( |
| 41 | SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}), |
| 42 | [&](MaterializationResponsibility R) { |
| 43 | DummyTargetMaterialized = true; |
| 44 | R.resolve( |
| 45 | {{DummyTarget, |
| 46 | JITEvaluatedSymbol(static_cast<JITTargetAddress>( |
| 47 | reinterpret_cast<uintptr_t>(&dummyTarget)), |
| 48 | JITSymbolFlags::Exported)}}); |
| 49 | R.emit(); |
| 50 | }))); |
| 51 | |
| 52 | unsigned NotifyResolvedCount = 0; |
| 53 | auto NotifyResolved = LazyCallThroughManager::createNotifyResolvedFunction( |
| 54 | [&](JITDylib &JD, const SymbolStringPtr &SymbolName, |
| 55 | JITTargetAddress ResolvedAddr) { |
| 56 | ++NotifyResolvedCount; |
| 57 | return Error::success(); |
| 58 | }); |
| 59 | |
| 60 | auto CallThroughTrampoline = cantFail((*LCTM)->getCallThroughTrampoline( |
| 61 | JD, DummyTarget, std::move(NotifyResolved))); |
| 62 | |
| 63 | auto CTTPtr = reinterpret_cast<int (*)()>( |
| 64 | static_cast<uintptr_t>(CallThroughTrampoline)); |
| 65 | |
| 66 | // Call twice to verify nothing unexpected happens on redundant calls. |
| 67 | auto Result = CTTPtr(); |
| 68 | (void)CTTPtr(); |
| 69 | |
| 70 | EXPECT_TRUE(DummyTargetMaterialized) |
| 71 | << "CallThrough did not materialize target"; |
| 72 | EXPECT_EQ(NotifyResolvedCount, 1U) |
| 73 | << "CallThrough should have generated exactly one 'NotifyResolved' call"; |
| 74 | EXPECT_EQ(Result, 42) << "Failed to call through to target"; |
| 75 | } |