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 auto Q = 122 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 123 VSO V; 124 125 SymbolMap Defs; 126 Defs[Foo] = JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported); 127 cantFail(V.define(std::move(Defs))); 128 V.lookup(Q, Names); 129 130 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 131 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 132 } 133 134 TEST(CoreAPIsTest, LookupFlagsTest) { 135 136 // Test that lookupFlags works on a predefined symbol, and does not trigger 137 // materialization of a lazy symbol. 138 139 SymbolStringPool SP; 140 auto Foo = SP.intern("foo"); 141 auto Bar = SP.intern("bar"); 142 auto Baz = SP.intern("baz"); 143 144 VSO V; 145 146 auto Source = std::make_shared<SimpleSource>( 147 [](VSO &V, SymbolNameSet Symbols) -> Error { 148 llvm_unreachable("Symbol materialized on flags lookup"); 149 }, 150 [](VSO &V, SymbolStringPtr Name) -> Error { 151 llvm_unreachable("Symbol finalized on flags lookup"); 152 }); 153 154 JITSymbolFlags FooFlags = JITSymbolFlags::Exported; 155 JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>( 156 JITSymbolFlags::Exported | JITSymbolFlags::Weak); 157 158 SymbolMap InitialDefs; 159 InitialDefs[Foo] = JITEvaluatedSymbol(0xdeadbeef, FooFlags); 160 cantFail(V.define(std::move(InitialDefs))); 161 162 SymbolFlagsMap InitialLazyDefs({{Bar, BarFlags}}); 163 cantFail(V.defineLazy(InitialLazyDefs, Source)); 164 165 SymbolNameSet Names({Foo, Bar, Baz}); 166 167 SymbolFlagsMap SymbolFlags; 168 auto SymbolsNotFound = V.lookupFlags(SymbolFlags, Names); 169 170 EXPECT_EQ(SymbolsNotFound.size(), 1U) << "Expected one not-found symbol"; 171 EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) << "Expected Baz to be not-found"; 172 EXPECT_EQ(SymbolFlags.size(), 2U) 173 << "Returned symbol flags contains unexpected results"; 174 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo"; 175 EXPECT_EQ(SymbolFlags[Foo], FooFlags) << "Incorrect flags returned for Foo"; 176 EXPECT_EQ(SymbolFlags.count(Bar), 1U) 177 << "Missing lookupFlags result for Bar"; 178 EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar"; 179 } 180 181 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) { 182 183 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 184 constexpr JITTargetAddress FakeBarAddr = 0xcafef00d; 185 186 SymbolStringPool SP; 187 auto Foo = SP.intern("foo"); 188 auto Bar = SP.intern("bar"); 189 190 bool FooMaterialized = false; 191 bool BarDiscarded = false; 192 193 VSO V; 194 195 auto Source = std::make_shared<SimpleSource>( 196 [&](VSO &V, SymbolNameSet Symbols) { 197 EXPECT_EQ(Symbols.size(), 1U) 198 << "Expected Symbols set size to be 1 ({ Foo })"; 199 EXPECT_EQ(*Symbols.begin(), Foo) << "Expected Symbols == { Foo }"; 200 201 SymbolMap SymbolsToResolve; 202 SymbolsToResolve[Foo] = 203 JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported); 204 V.resolve(std::move(SymbolsToResolve)); 205 SymbolNameSet SymbolsToFinalize; 206 SymbolsToFinalize.insert(Foo); 207 V.finalize(SymbolsToFinalize); 208 FooMaterialized = true; 209 return Error::success(); 210 }, 211 [&](VSO &V, SymbolStringPtr Name) { 212 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 213 BarDiscarded = true; 214 }); 215 216 SymbolFlagsMap InitialSymbols( 217 {{Foo, JITSymbolFlags::Exported}, 218 {Bar, static_cast<JITSymbolFlags::FlagNames>(JITSymbolFlags::Exported | 219 JITSymbolFlags::Weak)}}); 220 cantFail(V.defineLazy(InitialSymbols, Source)); 221 222 SymbolMap BarOverride; 223 BarOverride[Bar] = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported); 224 cantFail(V.define(std::move(BarOverride))); 225 226 SymbolNameSet Names({Foo}); 227 228 bool OnResolutionRun = false; 229 bool OnReadyRun = false; 230 231 auto OnResolution = [&](Expected<SymbolMap> Result) { 232 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 233 auto I = Result->find(Foo); 234 EXPECT_NE(I, Result->end()) << "Could not find symbol definition"; 235 EXPECT_EQ(I->second.getAddress(), FakeFooAddr) 236 << "Resolution returned incorrect result"; 237 OnResolutionRun = true; 238 }; 239 240 auto OnReady = [&](Error Err) { 241 cantFail(std::move(Err)); 242 OnReadyRun = true; 243 }; 244 245 auto Q = 246 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 247 248 auto LR = V.lookup(std::move(Q), Names); 249 250 for (auto &SWKV : LR.MaterializationWork) 251 cantFail(SWKV.first->materialize(V, std::move(SWKV.second))); 252 253 EXPECT_TRUE(LR.UnresolvedSymbols.empty()) << "Could not find Foo in dylib"; 254 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 255 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 256 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 257 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 258 } 259 260 TEST(CoreAPIsTest, TestLambdaSymbolResolver) { 261 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported); 262 JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported); 263 264 SymbolStringPool SP; 265 auto Foo = SP.intern("foo"); 266 auto Bar = SP.intern("bar"); 267 auto Baz = SP.intern("baz"); 268 269 VSO V; 270 cantFail(V.define({{Foo, FooSym}, {Bar, BarSym}})); 271 272 auto Resolver = createSymbolResolver( 273 [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) { 274 return V.lookupFlags(SymbolFlags, Symbols); 275 }, 276 [&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) { 277 auto LR = V.lookup(std::move(Q), Symbols); 278 assert(LR.MaterializationWork.empty() && 279 "Test generated unexpected materialization " 280 "work?"); 281 return std::move(LR.UnresolvedSymbols); 282 }); 283 284 SymbolNameSet Symbols({Foo, Bar, Baz}); 285 286 SymbolFlagsMap SymbolFlags; 287 SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols); 288 289 EXPECT_EQ(SymbolFlags.size(), 2U) 290 << "lookupFlags returned the wrong number of results"; 291 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo"; 292 EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar"; 293 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) 294 << "Incorrect lookupFlags result for Foo"; 295 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) 296 << "Incorrect lookupFlags result for Bar"; 297 EXPECT_EQ(SymbolsNotFound.size(), 1U) 298 << "Expected one symbol not found in lookupFlags"; 299 EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) 300 << "Expected baz not to be found in lookupFlags"; 301 302 bool OnResolvedRun = false; 303 304 auto OnResolved = [&](Expected<SymbolMap> Result) { 305 OnResolvedRun = true; 306 EXPECT_TRUE(!!Result) << "Unexpected error"; 307 EXPECT_EQ(Result->size(), 2U) << "Unexpected number of resolved symbols"; 308 EXPECT_EQ(Result->count(Foo), 1U) << "Missing lookup result for foo"; 309 EXPECT_EQ(Result->count(Bar), 1U) << "Missing lookup result for bar"; 310 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) 311 << "Incorrect address for foo"; 312 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress()) 313 << "Incorrect address for bar"; 314 }; 315 auto OnReady = [&](Error Err) { 316 EXPECT_FALSE(!!Err) << "Finalization should never fail in this test"; 317 }; 318 319 auto Q = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo, Bar}), 320 OnResolved, OnReady); 321 auto Unresolved = Resolver->lookup(std::move(Q), Symbols); 322 323 EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol"; 324 EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved"; 325 EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run"; 326 } 327 328 } // namespace 329