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   auto LFR = V.lookupFlags(Names);
167 
168   EXPECT_EQ(LFR.SymbolsNotFound.size(), 1U) << "Expected one not-found symbol";
169   EXPECT_EQ(*LFR.SymbolsNotFound.begin(), Baz)
170       << "Expected Baz to be not-found";
171   EXPECT_EQ(LFR.SymbolFlags.size(), 2U)
172       << "Returned symbol flags contains unexpected results";
173   EXPECT_EQ(LFR.SymbolFlags.count(Foo), 1U)
174       << "Missing lookupFlags result for Foo";
175   EXPECT_EQ(LFR.SymbolFlags[Foo], FooFlags)
176       << "Incorrect flags returned for Foo";
177   EXPECT_EQ(LFR.SymbolFlags.count(Bar), 1U)
178       << "Missing  lookupFlags result for Bar";
179   EXPECT_EQ(LFR.SymbolFlags[Bar], BarFlags)
180       << "Incorrect flags returned for Bar";
181 }
182 
183 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
184 
185   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
186   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
187 
188   SymbolStringPool SP;
189   auto Foo = SP.intern("foo");
190   auto Bar = SP.intern("bar");
191 
192   bool FooMaterialized = false;
193   bool BarDiscarded = false;
194 
195   VSO V;
196 
197   auto Source = std::make_shared<SimpleSource>(
198       [&](VSO &V, SymbolNameSet Symbols) {
199         EXPECT_EQ(Symbols.size(), 1U)
200             << "Expected Symbols set size to be 1 ({ Foo })";
201         EXPECT_EQ(*Symbols.begin(), Foo) << "Expected Symbols == { Foo }";
202 
203         SymbolMap SymbolsToResolve;
204         SymbolsToResolve[Foo] =
205             JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
206         V.resolve(std::move(SymbolsToResolve));
207         SymbolNameSet SymbolsToFinalize;
208         SymbolsToFinalize.insert(Foo);
209         V.finalize(SymbolsToFinalize);
210         FooMaterialized = true;
211         return Error::success();
212       },
213       [&](VSO &V, SymbolStringPtr Name) {
214         EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
215         BarDiscarded = true;
216       });
217 
218   SymbolFlagsMap InitialSymbols(
219       {{Foo, JITSymbolFlags::Exported},
220        {Bar, static_cast<JITSymbolFlags::FlagNames>(JITSymbolFlags::Exported |
221                                                     JITSymbolFlags::Weak)}});
222   cantFail(V.defineLazy(InitialSymbols, *Source));
223 
224   SymbolMap BarOverride;
225   BarOverride[Bar] = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
226   cantFail(V.define(std::move(BarOverride)));
227 
228   SymbolNameSet Names({Foo});
229 
230   bool OnResolutionRun = false;
231   bool OnReadyRun = false;
232 
233   auto OnResolution = [&](Expected<SymbolMap> Result) {
234     EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
235     auto I = Result->find(Foo);
236     EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
237     EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
238         << "Resolution returned incorrect result";
239     OnResolutionRun = true;
240   };
241 
242   auto OnReady = [&](Error Err) {
243     cantFail(std::move(Err));
244     OnReadyRun = true;
245   };
246 
247   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
248 
249   auto LR = V.lookup(Q, Names);
250 
251   for (auto &SWKV : LR.MaterializationWork)
252     cantFail(SWKV.first->materialize(V, std::move(SWKV.second)));
253 
254   EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib";
255   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
256   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
257   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
258   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
259 }
260 
261 } // namespace
262