2018-01-10 08:09:38 +08:00
|
|
|
//===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "OrcTestCommon.h"
|
|
|
|
#include "llvm/ExecutionEngine/Orc/Core.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
#include <set>
|
2018-03-14 12:18:04 +08:00
|
|
|
#include <thread>
|
2018-01-10 08:09:38 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::orc;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
class SimpleMaterializationUnit : public MaterializationUnit {
|
2018-01-10 08:09:38 +08:00
|
|
|
public:
|
2018-03-20 11:49:29 +08:00
|
|
|
using GetSymbolsFunction = std::function<SymbolFlagsMap()>;
|
2018-04-17 02:05:24 +08:00
|
|
|
using MaterializeFunction =
|
|
|
|
std::function<void(MaterializationResponsibility)>;
|
|
|
|
using DiscardFunction = std::function<void(const VSO &, SymbolStringPtr)>;
|
2018-04-13 02:35:08 +08:00
|
|
|
using DestructorFunction = std::function<void()>;
|
2018-01-10 08:09:38 +08:00
|
|
|
|
2018-04-13 02:35:08 +08:00
|
|
|
SimpleMaterializationUnit(
|
|
|
|
GetSymbolsFunction GetSymbols, MaterializeFunction Materialize,
|
|
|
|
DiscardFunction Discard,
|
|
|
|
DestructorFunction Destructor = DestructorFunction())
|
2018-03-20 11:49:29 +08:00
|
|
|
: GetSymbols(std::move(GetSymbols)), Materialize(std::move(Materialize)),
|
2018-04-13 02:35:08 +08:00
|
|
|
Discard(std::move(Discard)), Destructor(std::move(Destructor)) {}
|
|
|
|
|
|
|
|
~SimpleMaterializationUnit() override {
|
|
|
|
if (Destructor)
|
|
|
|
Destructor();
|
|
|
|
}
|
2018-01-10 08:09:38 +08:00
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
SymbolFlagsMap getSymbols() override { return GetSymbols(); }
|
|
|
|
|
2018-04-17 02:05:24 +08:00
|
|
|
void materialize(MaterializationResponsibility R) override {
|
|
|
|
Materialize(std::move(R));
|
|
|
|
}
|
2018-01-10 08:09:38 +08:00
|
|
|
|
2018-04-17 02:05:24 +08:00
|
|
|
void discard(const VSO &V, SymbolStringPtr Name) override {
|
2018-01-10 08:09:38 +08:00
|
|
|
Discard(V, std::move(Name));
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-03-20 11:49:29 +08:00
|
|
|
GetSymbolsFunction GetSymbols;
|
2018-01-10 08:09:38 +08:00
|
|
|
MaterializeFunction Materialize;
|
|
|
|
DiscardFunction Discard;
|
2018-04-13 02:35:08 +08:00
|
|
|
DestructorFunction Destructor;
|
2018-01-10 08:09:38 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) {
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
|
|
|
|
SymbolNameSet Names({Foo});
|
|
|
|
|
|
|
|
bool OnResolutionRun = false;
|
|
|
|
bool OnReadyRun = false;
|
|
|
|
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
|
|
|
EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
|
|
|
|
auto I = Result->find(Foo);
|
|
|
|
EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
|
|
|
|
EXPECT_EQ(I->second.getAddress(), FakeAddr)
|
|
|
|
<< "Resolution returned incorrect result";
|
|
|
|
OnResolutionRun = true;
|
|
|
|
};
|
|
|
|
auto OnReady = [&](Error Err) {
|
|
|
|
cantFail(std::move(Err));
|
|
|
|
OnReadyRun = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
|
|
|
|
|
2018-04-13 02:35:08 +08:00
|
|
|
Q.resolve(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
|
2018-01-10 08:09:38 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
|
|
|
EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CoreAPIsTest, AsynchronousSymbolQueryResolutionErrorOnly) {
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
SymbolNameSet Names({Foo});
|
|
|
|
|
|
|
|
bool OnResolutionRun = false;
|
|
|
|
bool OnReadyRun = false;
|
|
|
|
|
|
|
|
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
|
|
|
EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
|
|
|
|
auto Msg = toString(Result.takeError());
|
|
|
|
EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
|
|
|
|
OnResolutionRun = true;
|
|
|
|
};
|
|
|
|
auto OnReady = [&](Error Err) {
|
|
|
|
cantFail(std::move(Err));
|
|
|
|
OnReadyRun = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
|
|
|
|
|
2018-04-17 02:05:24 +08:00
|
|
|
Q.notifyMaterializationFailed(
|
|
|
|
make_error<StringError>("xyz", inconvertibleErrorCode()));
|
2018-01-10 08:09:38 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
|
|
|
EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CoreAPIsTest, SimpleAsynchronousSymbolQueryAgainstVSO) {
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
|
|
|
|
SymbolNameSet Names({Foo});
|
|
|
|
|
|
|
|
bool OnResolutionRun = false;
|
|
|
|
bool OnReadyRun = false;
|
|
|
|
|
|
|
|
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
|
|
|
EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
|
|
|
|
auto I = Result->find(Foo);
|
|
|
|
EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
|
|
|
|
EXPECT_EQ(I->second.getAddress(), FakeAddr)
|
|
|
|
<< "Resolution returned incorrect result";
|
|
|
|
OnResolutionRun = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto OnReady = [&](Error Err) {
|
|
|
|
cantFail(std::move(Err));
|
|
|
|
OnReadyRun = true;
|
|
|
|
};
|
|
|
|
|
2018-02-15 06:12:56 +08:00
|
|
|
auto Q =
|
|
|
|
std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
|
2018-01-10 08:09:38 +08:00
|
|
|
VSO V;
|
|
|
|
|
|
|
|
SymbolMap Defs;
|
|
|
|
Defs[Foo] = JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported);
|
|
|
|
cantFail(V.define(std::move(Defs)));
|
|
|
|
V.lookup(Q, Names);
|
|
|
|
|
|
|
|
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
|
|
|
EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
|
|
|
|
}
|
|
|
|
|
2018-01-21 11:20:39 +08:00
|
|
|
TEST(CoreAPIsTest, LookupFlagsTest) {
|
|
|
|
|
|
|
|
// Test that lookupFlags works on a predefined symbol, and does not trigger
|
|
|
|
// materialization of a lazy symbol.
|
|
|
|
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
auto Bar = SP.intern("bar");
|
|
|
|
auto Baz = SP.intern("baz");
|
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
|
|
|
|
JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>(
|
|
|
|
JITSymbolFlags::Exported | JITSymbolFlags::Weak);
|
|
|
|
|
2018-01-21 11:20:39 +08:00
|
|
|
VSO V;
|
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
|
|
|
[=]() {
|
|
|
|
return SymbolFlagsMap({{Bar, BarFlags}});
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[](MaterializationResponsibility R) {
|
2018-01-21 11:20:39 +08:00
|
|
|
llvm_unreachable("Symbol materialized on flags lookup");
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[](const VSO &V, SymbolStringPtr Name) {
|
2018-01-21 11:20:39 +08:00
|
|
|
llvm_unreachable("Symbol finalized on flags lookup");
|
|
|
|
});
|
|
|
|
|
|
|
|
SymbolMap InitialDefs;
|
|
|
|
InitialDefs[Foo] = JITEvaluatedSymbol(0xdeadbeef, FooFlags);
|
|
|
|
cantFail(V.define(std::move(InitialDefs)));
|
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
cantFail(V.defineLazy(std::move(MU)));
|
2018-01-21 11:20:39 +08:00
|
|
|
|
|
|
|
SymbolNameSet Names({Foo, Bar, Baz});
|
|
|
|
|
2018-01-25 09:43:00 +08:00
|
|
|
SymbolFlagsMap SymbolFlags;
|
|
|
|
auto SymbolsNotFound = V.lookupFlags(SymbolFlags, Names);
|
2018-01-21 11:20:39 +08:00
|
|
|
|
2018-01-25 09:43:00 +08:00
|
|
|
EXPECT_EQ(SymbolsNotFound.size(), 1U) << "Expected one not-found symbol";
|
|
|
|
EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) << "Expected Baz to be not-found";
|
|
|
|
EXPECT_EQ(SymbolFlags.size(), 2U)
|
2018-01-21 11:20:39 +08:00
|
|
|
<< "Returned symbol flags contains unexpected results";
|
2018-01-25 09:43:00 +08:00
|
|
|
EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo";
|
|
|
|
EXPECT_EQ(SymbolFlags[Foo], FooFlags) << "Incorrect flags returned for Foo";
|
|
|
|
EXPECT_EQ(SymbolFlags.count(Bar), 1U)
|
2018-01-21 11:20:39 +08:00
|
|
|
<< "Missing lookupFlags result for Bar";
|
2018-01-25 09:43:00 +08:00
|
|
|
EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
|
2018-01-21 11:20:39 +08:00
|
|
|
}
|
|
|
|
|
2018-04-13 02:35:08 +08:00
|
|
|
TEST(CoreAPIsTest, DropMaterializerWhenEmpty) {
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
auto Bar = SP.intern("bar");
|
|
|
|
|
|
|
|
bool DestructorRun = false;
|
|
|
|
|
|
|
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
|
|
|
[=]() {
|
|
|
|
return SymbolFlagsMap(
|
|
|
|
{{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[](MaterializationResponsibility R) {
|
2018-04-13 02:35:08 +08:00
|
|
|
llvm_unreachable("Unexpected call to materialize");
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[&](const VSO &V, SymbolStringPtr Name) {
|
2018-04-13 02:35:08 +08:00
|
|
|
EXPECT_TRUE(Name == Foo || Name == Bar)
|
|
|
|
<< "Discard of unexpected symbol?";
|
|
|
|
},
|
|
|
|
[&]() { DestructorRun = true; });
|
|
|
|
|
|
|
|
VSO V;
|
|
|
|
|
|
|
|
cantFail(V.defineLazy(std::move(MU)));
|
|
|
|
|
|
|
|
auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
|
|
|
|
auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
|
|
|
|
cantFail(V.define(SymbolMap({{Foo, FooSym}})));
|
|
|
|
|
|
|
|
EXPECT_FALSE(DestructorRun)
|
|
|
|
<< "MaterializationUnit should not have been destroyed yet";
|
|
|
|
|
|
|
|
cantFail(V.define(SymbolMap({{Bar, BarSym}})));
|
|
|
|
|
|
|
|
EXPECT_TRUE(DestructorRun)
|
|
|
|
<< "MaterializationUnit should have been destroyed";
|
|
|
|
}
|
|
|
|
|
2018-01-10 08:09:38 +08:00
|
|
|
TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
|
|
|
|
|
|
|
|
constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
|
|
|
|
constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
|
|
|
|
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
auto Bar = SP.intern("bar");
|
|
|
|
|
|
|
|
bool FooMaterialized = false;
|
|
|
|
bool BarDiscarded = false;
|
|
|
|
|
|
|
|
VSO V;
|
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
|
|
|
[=]() {
|
|
|
|
return SymbolFlagsMap(
|
|
|
|
{{Foo, JITSymbolFlags::Exported},
|
|
|
|
{Bar, static_cast<JITSymbolFlags::FlagNames>(
|
|
|
|
JITSymbolFlags::Exported | JITSymbolFlags::Weak)}});
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[&](MaterializationResponsibility R) {
|
2018-03-20 11:49:29 +08:00
|
|
|
assert(BarDiscarded && "Bar should have been discarded by this point");
|
2018-01-10 08:09:38 +08:00
|
|
|
SymbolMap SymbolsToResolve;
|
|
|
|
SymbolsToResolve[Foo] =
|
|
|
|
JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
|
2018-04-17 02:05:24 +08:00
|
|
|
R.resolve(std::move(SymbolsToResolve));
|
|
|
|
R.finalize();
|
2018-01-10 08:09:38 +08:00
|
|
|
FooMaterialized = true;
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[&](const VSO &V, SymbolStringPtr Name) {
|
2018-01-10 08:09:38 +08:00
|
|
|
EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
|
|
|
|
BarDiscarded = true;
|
|
|
|
});
|
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
cantFail(V.defineLazy(std::move(MU)));
|
2018-01-10 08:09:38 +08:00
|
|
|
|
|
|
|
SymbolMap BarOverride;
|
|
|
|
BarOverride[Bar] = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
|
|
|
|
cantFail(V.define(std::move(BarOverride)));
|
|
|
|
|
|
|
|
SymbolNameSet Names({Foo});
|
|
|
|
|
|
|
|
bool OnResolutionRun = false;
|
|
|
|
bool OnReadyRun = false;
|
|
|
|
|
|
|
|
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
|
|
|
EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
|
|
|
|
auto I = Result->find(Foo);
|
|
|
|
EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
|
|
|
|
EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
|
|
|
|
<< "Resolution returned incorrect result";
|
|
|
|
OnResolutionRun = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto OnReady = [&](Error Err) {
|
|
|
|
cantFail(std::move(Err));
|
|
|
|
OnReadyRun = true;
|
|
|
|
};
|
|
|
|
|
2018-02-15 06:12:56 +08:00
|
|
|
auto Q =
|
|
|
|
std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
|
2018-01-10 08:09:38 +08:00
|
|
|
|
2018-02-15 06:12:56 +08:00
|
|
|
auto LR = V.lookup(std::move(Q), Names);
|
2018-01-10 08:09:38 +08:00
|
|
|
|
2018-04-17 02:05:24 +08:00
|
|
|
for (auto &M : LR.Materializers)
|
|
|
|
M();
|
2018-01-10 08:09:38 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib";
|
|
|
|
EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
|
|
|
|
EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
|
|
|
|
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
|
|
|
EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
|
|
|
|
}
|
|
|
|
|
2018-04-13 02:35:08 +08:00
|
|
|
TEST(CoreAPIsTest, FailResolution) {
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
auto Bar = SP.intern("bar");
|
|
|
|
|
|
|
|
SymbolNameSet Names({Foo, Bar});
|
|
|
|
|
|
|
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
|
|
|
[=]() {
|
|
|
|
return SymbolFlagsMap(
|
|
|
|
{{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}});
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[&](MaterializationResponsibility R) { R.notifyMaterializationFailed(); },
|
|
|
|
[&](const VSO &V, SymbolStringPtr Name) {
|
2018-04-13 02:35:08 +08:00
|
|
|
llvm_unreachable("Unexpected call to discard");
|
|
|
|
});
|
|
|
|
|
|
|
|
VSO V;
|
|
|
|
|
|
|
|
cantFail(V.defineLazy(std::move(MU)));
|
|
|
|
|
|
|
|
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
|
|
|
handleAllErrors(Result.takeError(),
|
|
|
|
[&](FailedToResolve &F) {
|
|
|
|
EXPECT_EQ(F.getSymbols(), Names)
|
|
|
|
<< "Expected to fail on symbols in Names";
|
|
|
|
},
|
|
|
|
[](ErrorInfoBase &EIB) {
|
|
|
|
std::string ErrMsg;
|
|
|
|
{
|
|
|
|
raw_string_ostream ErrOut(ErrMsg);
|
|
|
|
EIB.log(ErrOut);
|
|
|
|
}
|
|
|
|
ADD_FAILURE()
|
|
|
|
<< "Expected a FailedToResolve error. Got:\n"
|
|
|
|
<< ErrMsg;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
auto OnReady = [](Error Err) {
|
|
|
|
cantFail(std::move(Err));
|
|
|
|
ADD_FAILURE() << "OnReady should never be called";
|
|
|
|
};
|
|
|
|
|
|
|
|
auto Q =
|
|
|
|
std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
|
|
|
|
|
|
|
|
auto LR = V.lookup(std::move(Q), Names);
|
2018-04-17 02:05:24 +08:00
|
|
|
for (auto &M : LR.Materializers)
|
|
|
|
M();
|
2018-04-13 02:35:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CoreAPIsTest, FailFinalization) {
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
auto Bar = SP.intern("bar");
|
|
|
|
|
|
|
|
SymbolNameSet Names({Foo, Bar});
|
|
|
|
|
|
|
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
|
|
|
[=]() {
|
|
|
|
return SymbolFlagsMap(
|
2018-04-17 02:05:24 +08:00
|
|
|
{{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}});
|
2018-04-13 02:35:08 +08:00
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[&](MaterializationResponsibility R) {
|
2018-04-13 02:35:08 +08:00
|
|
|
constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
|
|
|
|
constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
|
|
|
|
|
|
|
|
auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
|
|
|
|
auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
|
2018-04-17 02:05:24 +08:00
|
|
|
R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
|
|
|
|
R.notifyMaterializationFailed();
|
2018-04-13 02:35:08 +08:00
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[&](const VSO &V, SymbolStringPtr Name) {
|
2018-04-13 02:35:08 +08:00
|
|
|
llvm_unreachable("Unexpected call to discard");
|
|
|
|
});
|
|
|
|
|
|
|
|
VSO V;
|
|
|
|
|
|
|
|
cantFail(V.defineLazy(std::move(MU)));
|
|
|
|
|
|
|
|
auto OnResolution = [](Expected<SymbolMap> Result) {
|
|
|
|
cantFail(std::move(Result));
|
|
|
|
};
|
|
|
|
|
|
|
|
auto OnReady = [&](Error Err) {
|
|
|
|
handleAllErrors(std::move(Err),
|
|
|
|
[&](FailedToFinalize &F) {
|
|
|
|
EXPECT_EQ(F.getSymbols(), Names)
|
|
|
|
<< "Expected to fail on symbols in Names";
|
|
|
|
},
|
|
|
|
[](ErrorInfoBase &EIB) {
|
|
|
|
std::string ErrMsg;
|
|
|
|
{
|
|
|
|
raw_string_ostream ErrOut(ErrMsg);
|
|
|
|
EIB.log(ErrOut);
|
|
|
|
}
|
|
|
|
ADD_FAILURE()
|
|
|
|
<< "Expected a FailedToFinalize error. Got:\n"
|
|
|
|
<< ErrMsg;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
auto Q =
|
|
|
|
std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
|
|
|
|
|
|
|
|
auto LR = V.lookup(std::move(Q), Names);
|
2018-04-17 02:05:24 +08:00
|
|
|
for (auto &M : LR.Materializers)
|
|
|
|
M();
|
2018-04-13 02:35:08 +08:00
|
|
|
}
|
|
|
|
|
2018-01-25 05:21:10 +08:00
|
|
|
TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
|
|
|
|
JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
|
|
|
|
JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
|
|
|
|
|
|
|
|
SymbolStringPool SP;
|
|
|
|
auto Foo = SP.intern("foo");
|
|
|
|
auto Bar = SP.intern("bar");
|
|
|
|
auto Baz = SP.intern("baz");
|
|
|
|
|
|
|
|
VSO V;
|
|
|
|
cantFail(V.define({{Foo, FooSym}, {Bar, BarSym}}));
|
|
|
|
|
|
|
|
auto Resolver = createSymbolResolver(
|
2018-01-25 09:43:00 +08:00
|
|
|
[&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) {
|
|
|
|
return V.lookupFlags(SymbolFlags, Symbols);
|
|
|
|
},
|
2018-02-15 06:12:56 +08:00
|
|
|
[&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) {
|
|
|
|
auto LR = V.lookup(std::move(Q), Symbols);
|
2018-04-17 02:05:24 +08:00
|
|
|
assert(LR.Materializers.empty() &&
|
2018-03-20 11:49:29 +08:00
|
|
|
"Test generated unexpected materialization work?");
|
2018-01-25 05:21:10 +08:00
|
|
|
return std::move(LR.UnresolvedSymbols);
|
|
|
|
});
|
|
|
|
|
|
|
|
SymbolNameSet Symbols({Foo, Bar, Baz});
|
|
|
|
|
2018-01-25 09:43:00 +08:00
|
|
|
SymbolFlagsMap SymbolFlags;
|
|
|
|
SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols);
|
2018-01-25 05:21:10 +08:00
|
|
|
|
2018-01-25 09:43:00 +08:00
|
|
|
EXPECT_EQ(SymbolFlags.size(), 2U)
|
2018-01-25 05:21:10 +08:00
|
|
|
<< "lookupFlags returned the wrong number of results";
|
2018-01-25 09:43:00 +08:00
|
|
|
EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo";
|
|
|
|
EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar";
|
|
|
|
EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags())
|
2018-01-25 05:21:10 +08:00
|
|
|
<< "Incorrect lookupFlags result for Foo";
|
2018-01-25 09:43:00 +08:00
|
|
|
EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags())
|
2018-01-25 05:21:10 +08:00
|
|
|
<< "Incorrect lookupFlags result for Bar";
|
2018-01-25 09:43:00 +08:00
|
|
|
EXPECT_EQ(SymbolsNotFound.size(), 1U)
|
2018-01-25 05:21:10 +08:00
|
|
|
<< "Expected one symbol not found in lookupFlags";
|
2018-01-25 09:43:00 +08:00
|
|
|
EXPECT_EQ(SymbolsNotFound.count(Baz), 1U)
|
2018-01-25 05:21:10 +08:00
|
|
|
<< "Expected baz not to be found in lookupFlags";
|
|
|
|
|
|
|
|
bool OnResolvedRun = false;
|
|
|
|
|
|
|
|
auto OnResolved = [&](Expected<SymbolMap> Result) {
|
|
|
|
OnResolvedRun = true;
|
|
|
|
EXPECT_TRUE(!!Result) << "Unexpected error";
|
|
|
|
EXPECT_EQ(Result->size(), 2U) << "Unexpected number of resolved symbols";
|
|
|
|
EXPECT_EQ(Result->count(Foo), 1U) << "Missing lookup result for foo";
|
|
|
|
EXPECT_EQ(Result->count(Bar), 1U) << "Missing lookup result for bar";
|
|
|
|
EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
|
|
|
|
<< "Incorrect address for foo";
|
|
|
|
EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress())
|
|
|
|
<< "Incorrect address for bar";
|
|
|
|
};
|
|
|
|
auto OnReady = [&](Error Err) {
|
|
|
|
EXPECT_FALSE(!!Err) << "Finalization should never fail in this test";
|
|
|
|
};
|
|
|
|
|
2018-02-15 06:12:56 +08:00
|
|
|
auto Q = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo, Bar}),
|
|
|
|
OnResolved, OnReady);
|
|
|
|
auto Unresolved = Resolver->lookup(std::move(Q), Symbols);
|
2018-01-25 05:21:10 +08:00
|
|
|
|
|
|
|
EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol";
|
|
|
|
EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved";
|
|
|
|
EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run";
|
|
|
|
}
|
|
|
|
|
2018-03-14 12:18:04 +08:00
|
|
|
TEST(CoreAPIsTest, TestLookupWithUnthreadedMaterialization) {
|
|
|
|
constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
|
|
|
|
JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported);
|
|
|
|
|
2018-04-03 04:57:56 +08:00
|
|
|
ExecutionSession ES(std::make_shared<SymbolStringPool>());
|
|
|
|
auto Foo = ES.getSymbolStringPool().intern("foo");
|
2018-03-14 12:18:04 +08:00
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
|
|
|
[=]() {
|
|
|
|
return SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}});
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[&](MaterializationResponsibility R) {
|
|
|
|
R.resolve({{Foo, FooSym}});
|
|
|
|
R.finalize();
|
2018-03-14 12:18:04 +08:00
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[](const VSO &V, SymbolStringPtr Name) {
|
2018-03-14 12:18:04 +08:00
|
|
|
llvm_unreachable("Not expecting finalization");
|
|
|
|
});
|
|
|
|
|
|
|
|
VSO V;
|
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
cantFail(V.defineLazy(std::move(MU)));
|
2018-03-14 12:18:04 +08:00
|
|
|
|
|
|
|
auto FooLookupResult =
|
2018-04-17 02:05:24 +08:00
|
|
|
cantFail(lookup({&V}, Foo, MaterializeOnCurrentThread()));
|
2018-03-14 12:18:04 +08:00
|
|
|
|
|
|
|
EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
|
|
|
|
<< "lookup returned an incorrect address";
|
|
|
|
EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
|
|
|
|
<< "lookup returned incorrect flags";
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CoreAPIsTest, TestLookupWithThreadedMaterialization) {
|
|
|
|
#if LLVM_ENABLE_THREADS
|
|
|
|
constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
|
|
|
|
JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported);
|
|
|
|
|
2018-04-03 04:57:56 +08:00
|
|
|
ExecutionSession ES(std::make_shared<SymbolStringPool>());
|
|
|
|
auto Foo = ES.getSymbolStringPool().intern("foo");
|
2018-03-14 12:18:04 +08:00
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
auto MU = llvm::make_unique<SimpleMaterializationUnit>(
|
|
|
|
[=]() {
|
|
|
|
return SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}});
|
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[&](MaterializationResponsibility R) {
|
|
|
|
R.resolve({{Foo, FooSym}});
|
|
|
|
R.finalize();
|
2018-03-14 12:18:04 +08:00
|
|
|
},
|
2018-04-17 02:05:24 +08:00
|
|
|
[](const VSO &V, SymbolStringPtr Name) {
|
2018-03-14 12:18:04 +08:00
|
|
|
llvm_unreachable("Not expecting finalization");
|
|
|
|
});
|
|
|
|
|
|
|
|
VSO V;
|
|
|
|
|
2018-03-20 11:49:29 +08:00
|
|
|
cantFail(V.defineLazy(std::move(MU)));
|
2018-03-14 12:18:04 +08:00
|
|
|
|
2018-03-23 18:14:19 +08:00
|
|
|
std::thread MaterializationThread;
|
2018-04-17 02:05:24 +08:00
|
|
|
auto MaterializeOnNewThread = [&](VSO::Materializer M) {
|
2018-03-20 11:49:29 +08:00
|
|
|
// FIXME: Use move capture once we move to C++14.
|
2018-04-17 02:05:24 +08:00
|
|
|
auto SharedM = std::make_shared<VSO::Materializer>(std::move(M));
|
|
|
|
MaterializationThread = std::thread([SharedM]() { (*SharedM)(); });
|
2018-03-20 11:49:29 +08:00
|
|
|
};
|
2018-03-14 12:18:04 +08:00
|
|
|
|
|
|
|
auto FooLookupResult =
|
|
|
|
cantFail(lookup({&V}, Foo, MaterializeOnNewThread));
|
|
|
|
|
|
|
|
EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
|
|
|
|
<< "lookup returned an incorrect address";
|
|
|
|
EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
|
|
|
|
<< "lookup returned incorrect flags";
|
2018-03-23 18:14:19 +08:00
|
|
|
MaterializationThread.join();
|
2018-03-14 12:18:04 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-01-10 08:09:38 +08:00
|
|
|
} // namespace
|