mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-20 03:55:48 -04:00

A bug in the existing implementation meant that lazyReexports would not work if the aliased name differed from the alias's name, i.e. all lazy reexports had to be of the form (lib1, name) -> (lib2, name). This patch fixes the issue by capturing the alias's name in the NotifyResolved callback. To simplify this capture, and the LazyCallThroughManager code in general, the NotifyResolved callback is updated to use llvm::unique_function rather than a custom class. No test case yet: This can only be tested at runtime, and the only in-tree client (lli) always uses aliases with matching names. I will add a new LLJIT example shortly that will directly test the lazyReexports API and the non-trivial alias use case.
75 lines
2.5 KiB
C++
75 lines
2.5 KiB
C++
#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 = [&](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";
|
|
}
|