2018-09-26 06:18:30 +02:00
|
|
|
#include "OrcTestCommon.h"
|
2018-09-30 21:12:23 +02:00
|
|
|
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
|
2018-09-26 06:18:30 +02:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2018-10-01 01:18:24 +02:00
|
|
|
auto DummyTarget = ES.intern("DummyTarget");
|
2018-09-26 06:18:30 +02:00
|
|
|
|
|
|
|
bool DummyTargetMaterialized = false;
|
|
|
|
|
2019-08-15 17:54:37 +02:00
|
|
|
cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
|
2018-09-26 06:18:30 +02:00
|
|
|
SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}),
|
2020-09-11 10:35:20 +02:00
|
|
|
[&](MaterializationResponsibility R) {
|
2018-09-26 06:18:30 +02:00
|
|
|
DummyTargetMaterialized = true;
|
2019-08-23 22:37:31 +02:00
|
|
|
// No dependencies registered, can't fail.
|
2020-09-11 10:35:20 +02:00
|
|
|
cantFail(R.notifyResolved(
|
2018-09-26 06:18:30 +02:00
|
|
|
{{DummyTarget,
|
|
|
|
JITEvaluatedSymbol(static_cast<JITTargetAddress>(
|
|
|
|
reinterpret_cast<uintptr_t>(&dummyTarget)),
|
2019-08-23 22:37:31 +02:00
|
|
|
JITSymbolFlags::Exported)}}));
|
2020-09-11 10:35:20 +02:00
|
|
|
cantFail(R.notifyEmitted());
|
2018-09-26 06:18:30 +02:00
|
|
|
})));
|
|
|
|
|
|
|
|
unsigned NotifyResolvedCount = 0;
|
2020-01-15 02:09:02 +01:00
|
|
|
auto NotifyResolved = [&](JITTargetAddress ResolvedAddr) {
|
|
|
|
++NotifyResolvedCount;
|
|
|
|
return Error::success();
|
|
|
|
};
|
2018-09-26 06:18:30 +02:00
|
|
|
|
|
|
|
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";
|
|
|
|
}
|