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 "llvm/ExecutionEngine/Orc/Core.h"
11 #include "OrcTestCommon.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 =
51     [&](Expected<SymbolMap> Result) {
52       EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
53       auto I = Result->find(Foo);
54       EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
55       EXPECT_EQ(cantFail(I->second.getAddress()), FakeAddr)
56         << "Resolution returned incorrect result";
57       OnResolutionRun = true;
58     };
59   auto OnReady =
60     [&](Error Err) {
61       cantFail(std::move(Err));
62       OnResolutionRun = true;
63     };
64 
65   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
66 
67   Q.setDefinition(Foo, JITSymbol(FakeAddr, JITSymbolFlags::Exported));
68 
69   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
70   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
71 }
72 
73 TEST(CoreAPIsTest, AsynchronousSymbolQueryResolutionErrorOnly) {
74   SymbolStringPool SP;
75   auto Foo = SP.intern("foo");
76   SymbolNameSet Names({Foo});
77 
78   bool OnResolutionRun = false;
79   bool OnReadyRun = false;
80 
81   auto OnResolution =
82     [&](Expected<SymbolMap> Result) {
83       EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
84       auto Msg = toString(Result.takeError());
85       EXPECT_EQ(Msg, "xyz")
86         << "Resolution returned incorrect result";
87       OnResolutionRun = true;
88     };
89   auto OnReady =
90     [&](Error Err) {
91       cantFail(std::move(Err));
92       OnReadyRun = true;
93     };
94 
95   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
96 
97   Q.setFailed(make_error<StringError>("xyz", inconvertibleErrorCode()));
98 
99   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
100   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
101 }
102 
103 TEST(CoreAPIsTest, SimpleAsynchronousSymbolQueryAgainstVSO) {
104   SymbolStringPool SP;
105   auto Foo = SP.intern("foo");
106   constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
107   SymbolNameSet Names({Foo});
108 
109   bool OnResolutionRun = false;
110   bool OnReadyRun = false;
111 
112   auto OnResolution =
113     [&](Expected<SymbolMap> Result) {
114       EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
115       auto I = Result->find(Foo);
116       EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
117       EXPECT_EQ(cantFail(I->second.getAddress()), FakeAddr)
118         << "Resolution returned incorrect result";
119       OnResolutionRun = true;
120     };
121 
122   auto OnReady =
123     [&](Error Err) {
124       cantFail(std::move(Err));
125       OnReadyRun = true;
126     };
127 
128   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
129   VSO V;
130 
131   SymbolMap Defs;
132   Defs.insert(
133     std::make_pair(Foo, JITSymbol(FakeAddr, JITSymbolFlags::Exported)));
134   cantFail(V.define(std::move(Defs)));
135   V.lookup(Q, Names);
136 
137   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
138   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
139 }
140 
141 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
142 
143   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
144   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
145 
146   SymbolStringPool SP;
147   auto Foo = SP.intern("foo");
148   auto Bar = SP.intern("bar");
149 
150   bool FooMaterialized = false;
151   bool BarDiscarded = false;
152 
153   VSO V;
154 
155   auto Source =
156     std::make_shared<SimpleSource>(
157       [&](VSO &V, SymbolNameSet Symbols) {
158         EXPECT_EQ(Symbols.size(), 1U)
159           << "Expected Symbols set size to be 1 ({ Foo })";
160         EXPECT_EQ(*Symbols.begin(), Foo)
161           << "Expected Symbols == { Foo }";
162 
163         SymbolMap SymbolsToResolve;
164         SymbolsToResolve.insert(
165           std::make_pair(Foo, JITSymbol(FakeFooAddr,
166                                         JITSymbolFlags::Exported)));
167         V.resolve(std::move(SymbolsToResolve));
168         SymbolNameSet SymbolsToFinalize;
169         SymbolsToFinalize.insert(Foo);
170         V.finalize(SymbolsToFinalize);
171         FooMaterialized = true;
172         return Error::success();
173       },
174       [&](VSO &V, SymbolStringPtr Name) {
175         EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
176         BarDiscarded = true;
177       });
178 
179   SymbolFlagsMap InitialSymbols({
180       {Foo, JITSymbolFlags::Exported},
181       {Bar, static_cast<JITSymbolFlags::FlagNames>(JITSymbolFlags::Exported |
182                                                    JITSymbolFlags::Weak)}
183     });
184   cantFail(V.defineLazy(InitialSymbols, *Source));
185 
186   SymbolMap BarOverride;
187   BarOverride.insert(
188     std::make_pair(Bar, JITSymbol(FakeBarAddr, JITSymbolFlags::Exported)));
189   cantFail(V.define(std::move(BarOverride)));
190 
191   SymbolNameSet Names({Foo});
192 
193   bool OnResolutionRun = false;
194   bool OnReadyRun = false;
195 
196   auto OnResolution =
197     [&](Expected<SymbolMap> Result) {
198       EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
199       auto I = Result->find(Foo);
200       EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
201       EXPECT_EQ(cantFail(I->second.getAddress()), FakeFooAddr)
202         << "Resolution returned incorrect result";
203       OnResolutionRun = true;
204     };
205 
206   auto OnReady =
207     [&](Error Err) {
208       cantFail(std::move(Err));
209       OnReadyRun = true;
210     };
211 
212   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
213 
214   auto LR = V.lookup(Q, Names);
215 
216   for (auto &SWKV : LR.MaterializationWork)
217     cantFail(SWKV.first->materialize(V, std::move(SWKV.second)));
218 
219   EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib";
220   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
221   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
222   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
223   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
224 }
225 
226 }
227