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, AddAndMaterializeLazySymbol) {
134 
135   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
136   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
137 
138   SymbolStringPool SP;
139   auto Foo = SP.intern("foo");
140   auto Bar = SP.intern("bar");
141 
142   bool FooMaterialized = false;
143   bool BarDiscarded = false;
144 
145   VSO V;
146 
147   auto Source = std::make_shared<SimpleSource>(
148       [&](VSO &V, SymbolNameSet Symbols) {
149         EXPECT_EQ(Symbols.size(), 1U)
150             << "Expected Symbols set size to be 1 ({ Foo })";
151         EXPECT_EQ(*Symbols.begin(), Foo) << "Expected Symbols == { Foo }";
152 
153         SymbolMap SymbolsToResolve;
154         SymbolsToResolve[Foo] =
155             JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
156         V.resolve(std::move(SymbolsToResolve));
157         SymbolNameSet SymbolsToFinalize;
158         SymbolsToFinalize.insert(Foo);
159         V.finalize(SymbolsToFinalize);
160         FooMaterialized = true;
161         return Error::success();
162       },
163       [&](VSO &V, SymbolStringPtr Name) {
164         EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
165         BarDiscarded = true;
166       });
167 
168   SymbolFlagsMap InitialSymbols(
169       {{Foo, JITSymbolFlags::Exported},
170        {Bar, static_cast<JITSymbolFlags::FlagNames>(JITSymbolFlags::Exported |
171                                                     JITSymbolFlags::Weak)}});
172   cantFail(V.defineLazy(InitialSymbols, *Source));
173 
174   SymbolMap BarOverride;
175   BarOverride[Bar] = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
176   cantFail(V.define(std::move(BarOverride)));
177 
178   SymbolNameSet Names({Foo});
179 
180   bool OnResolutionRun = false;
181   bool OnReadyRun = false;
182 
183   auto OnResolution = [&](Expected<SymbolMap> Result) {
184     EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
185     auto I = Result->find(Foo);
186     EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
187     EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
188         << "Resolution returned incorrect result";
189     OnResolutionRun = true;
190   };
191 
192   auto OnReady = [&](Error Err) {
193     cantFail(std::move(Err));
194     OnReadyRun = true;
195   };
196 
197   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
198 
199   auto LR = V.lookup(Q, Names);
200 
201   for (auto &SWKV : LR.MaterializationWork)
202     cantFail(SWKV.first->materialize(V, std::move(SWKV.second)));
203 
204   EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib";
205   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
206   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
207   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
208   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
209 }
210 
211 } // namespace
212