1 #include "OrcTestCommon.h"
2 #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
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 
dummyTarget()11 static int dummyTarget() { return 42; }
12 
TEST_F(LazyReexportsTest,BasicLocalCallThroughManagerOperation)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 
36   auto DummyTarget = ES.intern("DummyTarget");
37 
38   bool DummyTargetMaterialized = false;
39 
40   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
41       SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}),
42       [&](std::unique_ptr<MaterializationResponsibility> R) {
43         DummyTargetMaterialized = true;
44         // No dependencies registered, can't fail.
45         cantFail(R->notifyResolved(
46             {{DummyTarget,
47               JITEvaluatedSymbol(static_cast<JITTargetAddress>(
48                                      reinterpret_cast<uintptr_t>(&dummyTarget)),
49                                  JITSymbolFlags::Exported)}}));
50         cantFail(R->notifyEmitted());
51       })));
52 
53   unsigned NotifyResolvedCount = 0;
54   auto NotifyResolved = [&](JITTargetAddress ResolvedAddr) {
55     ++NotifyResolvedCount;
56     return Error::success();
57   };
58 
59   auto CallThroughTrampoline = cantFail((*LCTM)->getCallThroughTrampoline(
60       JD, DummyTarget, std::move(NotifyResolved)));
61 
62   auto CTTPtr = reinterpret_cast<int (*)()>(
63       static_cast<uintptr_t>(CallThroughTrampoline));
64 
65   // Call twice to verify nothing unexpected happens on redundant calls.
66   auto Result = CTTPtr();
67   (void)CTTPtr();
68 
69   EXPECT_TRUE(DummyTargetMaterialized)
70       << "CallThrough did not materialize target";
71   EXPECT_EQ(NotifyResolvedCount, 1U)
72       << "CallThrough should have generated exactly one 'NotifyResolved' call";
73   EXPECT_EQ(Result, 42) << "Failed to call through to target";
74 }
75