1 //===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "OrcTestCommon.h"
11 #include "llvm/ExecutionEngine/Orc/Core.h"
12 #include "gtest/gtest.h"
13 
14 #include <set>
15 
16 using namespace llvm;
17 using namespace llvm::orc;
18 
19 namespace {
20 
21 class SimpleSource : public SymbolSource {
22 public:
23   using MaterializeFunction = std::function<Error(VSO &, SymbolNameSet)>;
24   using DiscardFunction = std::function<void(VSO &, SymbolStringPtr)>;
25 
26   SimpleSource(MaterializeFunction Materialize, DiscardFunction Discard)
27       : Materialize(std::move(Materialize)), Discard(std::move(Discard)) {}
28 
29   Error materialize(VSO &V, SymbolNameSet Symbols) override {
30     return Materialize(V, std::move(Symbols));
31   }
32 
33   void discard(VSO &V, SymbolStringPtr Name) override {
34     Discard(V, std::move(Name));
35   }
36 
37 private:
38   MaterializeFunction Materialize;
39   DiscardFunction Discard;
40 };
41 
42 TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) {
43   SymbolStringPool SP;
44   auto Foo = SP.intern("foo");
45   constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
46   SymbolNameSet Names({Foo});
47 
48   bool OnResolutionRun = false;
49   bool OnReadyRun = false;
50   auto OnResolution = [&](Expected<SymbolMap> Result) {
51     EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
52     auto I = Result->find(Foo);
53     EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
54     EXPECT_EQ(I->second.getAddress(), FakeAddr)
55         << "Resolution returned incorrect result";
56     OnResolutionRun = true;
57   };
58   auto OnReady = [&](Error Err) {
59     cantFail(std::move(Err));
60     OnReadyRun = true;
61   };
62 
63   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
64 
65   Q.setDefinition(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
66 
67   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
68   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
69 }
70 
71 TEST(CoreAPIsTest, AsynchronousSymbolQueryResolutionErrorOnly) {
72   SymbolStringPool SP;
73   auto Foo = SP.intern("foo");
74   SymbolNameSet Names({Foo});
75 
76   bool OnResolutionRun = false;
77   bool OnReadyRun = false;
78 
79   auto OnResolution = [&](Expected<SymbolMap> Result) {
80     EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
81     auto Msg = toString(Result.takeError());
82     EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
83     OnResolutionRun = true;
84   };
85   auto OnReady = [&](Error Err) {
86     cantFail(std::move(Err));
87     OnReadyRun = true;
88   };
89 
90   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
91 
92   Q.setFailed(make_error<StringError>("xyz", inconvertibleErrorCode()));
93 
94   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
95   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
96 }
97 
98 TEST(CoreAPIsTest, SimpleAsynchronousSymbolQueryAgainstVSO) {
99   SymbolStringPool SP;
100   auto Foo = SP.intern("foo");
101   constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
102   SymbolNameSet Names({Foo});
103 
104   bool OnResolutionRun = false;
105   bool OnReadyRun = false;
106 
107   auto OnResolution = [&](Expected<SymbolMap> Result) {
108     EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
109     auto I = Result->find(Foo);
110     EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
111     EXPECT_EQ(I->second.getAddress(), FakeAddr)
112         << "Resolution returned incorrect result";
113     OnResolutionRun = true;
114   };
115 
116   auto OnReady = [&](Error Err) {
117     cantFail(std::move(Err));
118     OnReadyRun = true;
119   };
120 
121   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
122   VSO V;
123 
124   SymbolMap Defs;
125   Defs[Foo] = JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported);
126   cantFail(V.define(std::move(Defs)));
127   V.lookup(Q, Names);
128 
129   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
130   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
131 }
132 
133 TEST(CoreAPIsTest, LookupFlagsTest) {
134 
135   // Test that lookupFlags works on a predefined symbol, and does not trigger
136   // materialization of a lazy symbol.
137 
138   SymbolStringPool SP;
139   auto Foo = SP.intern("foo");
140   auto Bar = SP.intern("bar");
141   auto Baz = SP.intern("baz");
142 
143   VSO V;
144 
145   auto Source = std::make_shared<SimpleSource>(
146       [](VSO &V, SymbolNameSet Symbols) -> Error {
147         llvm_unreachable("Symbol materialized on flags lookup");
148       },
149       [](VSO &V, SymbolStringPtr Name) -> Error {
150         llvm_unreachable("Symbol finalized on flags lookup");
151       });
152 
153   JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
154   JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>(
155       JITSymbolFlags::Exported | JITSymbolFlags::Weak);
156 
157   SymbolMap InitialDefs;
158   InitialDefs[Foo] = JITEvaluatedSymbol(0xdeadbeef, FooFlags);
159   cantFail(V.define(std::move(InitialDefs)));
160 
161   SymbolFlagsMap InitialLazyDefs({{Bar, BarFlags}});
162   cantFail(V.defineLazy(InitialLazyDefs, *Source));
163 
164   SymbolNameSet Names({Foo, Bar, Baz});
165 
166   SymbolFlagsMap SymbolFlags;
167   auto SymbolsNotFound = V.lookupFlags(SymbolFlags, Names);
168 
169   EXPECT_EQ(SymbolsNotFound.size(), 1U) << "Expected one not-found symbol";
170   EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) << "Expected Baz to be not-found";
171   EXPECT_EQ(SymbolFlags.size(), 2U)
172       << "Returned symbol flags contains unexpected results";
173   EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo";
174   EXPECT_EQ(SymbolFlags[Foo], FooFlags) << "Incorrect flags returned for Foo";
175   EXPECT_EQ(SymbolFlags.count(Bar), 1U)
176       << "Missing  lookupFlags result for Bar";
177   EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
178 }
179 
180 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
181 
182   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
183   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
184 
185   SymbolStringPool SP;
186   auto Foo = SP.intern("foo");
187   auto Bar = SP.intern("bar");
188 
189   bool FooMaterialized = false;
190   bool BarDiscarded = false;
191 
192   VSO V;
193 
194   auto Source = std::make_shared<SimpleSource>(
195       [&](VSO &V, SymbolNameSet Symbols) {
196         EXPECT_EQ(Symbols.size(), 1U)
197             << "Expected Symbols set size to be 1 ({ Foo })";
198         EXPECT_EQ(*Symbols.begin(), Foo) << "Expected Symbols == { Foo }";
199 
200         SymbolMap SymbolsToResolve;
201         SymbolsToResolve[Foo] =
202             JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
203         V.resolve(std::move(SymbolsToResolve));
204         SymbolNameSet SymbolsToFinalize;
205         SymbolsToFinalize.insert(Foo);
206         V.finalize(SymbolsToFinalize);
207         FooMaterialized = true;
208         return Error::success();
209       },
210       [&](VSO &V, SymbolStringPtr Name) {
211         EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
212         BarDiscarded = true;
213       });
214 
215   SymbolFlagsMap InitialSymbols(
216       {{Foo, JITSymbolFlags::Exported},
217        {Bar, static_cast<JITSymbolFlags::FlagNames>(JITSymbolFlags::Exported |
218                                                     JITSymbolFlags::Weak)}});
219   cantFail(V.defineLazy(InitialSymbols, *Source));
220 
221   SymbolMap BarOverride;
222   BarOverride[Bar] = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
223   cantFail(V.define(std::move(BarOverride)));
224 
225   SymbolNameSet Names({Foo});
226 
227   bool OnResolutionRun = false;
228   bool OnReadyRun = false;
229 
230   auto OnResolution = [&](Expected<SymbolMap> Result) {
231     EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
232     auto I = Result->find(Foo);
233     EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
234     EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
235         << "Resolution returned incorrect result";
236     OnResolutionRun = true;
237   };
238 
239   auto OnReady = [&](Error Err) {
240     cantFail(std::move(Err));
241     OnReadyRun = true;
242   };
243 
244   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
245 
246   auto LR = V.lookup(Q, Names);
247 
248   for (auto &SWKV : LR.MaterializationWork)
249     cantFail(SWKV.first->materialize(V, std::move(SWKV.second)));
250 
251   EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib";
252   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
253   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
254   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
255   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
256 }
257 
258 TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
259   JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
260   JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
261 
262   SymbolStringPool SP;
263   auto Foo = SP.intern("foo");
264   auto Bar = SP.intern("bar");
265   auto Baz = SP.intern("baz");
266 
267   VSO V;
268   cantFail(V.define({{Foo, FooSym}, {Bar, BarSym}}));
269 
270   auto Resolver = createSymbolResolver(
271       [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) {
272         return V.lookupFlags(SymbolFlags, Symbols);
273       },
274       [&](AsynchronousSymbolQuery &Q, SymbolNameSet Symbols) {
275         auto LR = V.lookup(Q, Symbols);
276         assert(LR.MaterializationWork.empty() &&
277                "Test generated unexpected materialization "
278                "work?");
279         return std::move(LR.UnresolvedSymbols);
280       });
281 
282   SymbolNameSet Symbols({Foo, Bar, Baz});
283 
284   SymbolFlagsMap SymbolFlags;
285   SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols);
286 
287   EXPECT_EQ(SymbolFlags.size(), 2U)
288       << "lookupFlags returned the wrong number of results";
289   EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo";
290   EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar";
291   EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags())
292       << "Incorrect lookupFlags result for Foo";
293   EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags())
294       << "Incorrect lookupFlags result for Bar";
295   EXPECT_EQ(SymbolsNotFound.size(), 1U)
296       << "Expected one symbol not found in lookupFlags";
297   EXPECT_EQ(SymbolsNotFound.count(Baz), 1U)
298       << "Expected baz not to be found in lookupFlags";
299 
300   bool OnResolvedRun = false;
301 
302   auto OnResolved = [&](Expected<SymbolMap> Result) {
303     OnResolvedRun = true;
304     EXPECT_TRUE(!!Result) << "Unexpected error";
305     EXPECT_EQ(Result->size(), 2U) << "Unexpected number of resolved symbols";
306     EXPECT_EQ(Result->count(Foo), 1U) << "Missing lookup result for foo";
307     EXPECT_EQ(Result->count(Bar), 1U) << "Missing lookup result for bar";
308     EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
309         << "Incorrect address for foo";
310     EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress())
311         << "Incorrect address for bar";
312   };
313   auto OnReady = [&](Error Err) {
314     EXPECT_FALSE(!!Err) << "Finalization should never fail in this test";
315   };
316 
317   AsynchronousSymbolQuery Q({Foo, Bar}, OnResolved, OnReady);
318   auto Unresolved = Resolver->lookup(Q, Symbols);
319 
320   EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol";
321   EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved";
322   EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run";
323 }
324 
325 } // namespace
326