LazyCallThroughAndReexportsTest.cpp
2.66 KB
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
#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(std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}),
[&](MaterializationResponsibility R) {
DummyTargetMaterialized = true;
// No dependencies registered, can't fail.
cantFail(R.notifyResolved(
{{DummyTarget,
JITEvaluatedSymbol(static_cast<JITTargetAddress>(
reinterpret_cast<uintptr_t>(&dummyTarget)),
JITSymbolFlags::Exported)}}));
cantFail(R.notifyEmitted());
})));
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";
}