1 //===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "OrcTestCommon.h"
11 #include "llvm/Config/llvm-config.h"
12 #include "llvm/ExecutionEngine/Orc/Core.h"
13 #include "llvm/ExecutionEngine/Orc/OrcError.h"
19 using namespace llvm::orc
;
21 class CoreAPIsStandardTest
: public CoreAPIsBasedStandardTest
{};
25 TEST_F(CoreAPIsStandardTest
, BasicSuccessfulLookup
) {
26 bool OnResolutionRun
= false;
27 bool OnReadyRun
= false;
29 auto OnResolution
= [&](Expected
<SymbolMap
> Result
) {
30 EXPECT_TRUE(!!Result
) << "Resolution unexpectedly returned error";
31 auto &Resolved
= *Result
;
32 auto I
= Resolved
.find(Foo
);
33 EXPECT_NE(I
, Resolved
.end()) << "Could not find symbol definition";
34 EXPECT_EQ(I
->second
.getAddress(), FooAddr
)
35 << "Resolution returned incorrect result";
36 OnResolutionRun
= true;
38 auto OnReady
= [&](Error Err
) {
39 cantFail(std::move(Err
));
43 std::shared_ptr
<MaterializationResponsibility
> FooMR
;
45 cantFail(JD
.define(llvm::make_unique
<SimpleMaterializationUnit
>(
46 SymbolFlagsMap({{Foo
, FooSym
.getFlags()}}),
47 [&](MaterializationResponsibility R
) {
48 FooMR
= std::make_shared
<MaterializationResponsibility
>(std::move(R
));
51 ES
.lookup({&JD
}, {Foo
}, OnResolution
, OnReady
, NoDependenciesToRegister
);
53 EXPECT_FALSE(OnResolutionRun
) << "Should not have been resolved yet";
54 EXPECT_FALSE(OnReadyRun
) << "Should not have been marked ready yet";
56 FooMR
->resolve({{Foo
, FooSym
}});
58 EXPECT_TRUE(OnResolutionRun
) << "Should have been resolved";
59 EXPECT_FALSE(OnReadyRun
) << "Should not have been marked ready yet";
63 EXPECT_TRUE(OnReadyRun
) << "Should have been marked ready";
66 TEST_F(CoreAPIsStandardTest
, ExecutionSessionFailQuery
) {
67 bool OnResolutionRun
= false;
68 bool OnReadyRun
= false;
70 auto OnResolution
= [&](Expected
<SymbolMap
> Result
) {
71 EXPECT_FALSE(!!Result
) << "Resolution unexpectedly returned success";
72 auto Msg
= toString(Result
.takeError());
73 EXPECT_EQ(Msg
, "xyz") << "Resolution returned incorrect result";
74 OnResolutionRun
= true;
76 auto OnReady
= [&](Error Err
) {
77 cantFail(std::move(Err
));
81 AsynchronousSymbolQuery
Q(SymbolNameSet({Foo
}), OnResolution
, OnReady
);
84 make_error
<StringError
>("xyz", inconvertibleErrorCode()));
86 EXPECT_TRUE(OnResolutionRun
) << "OnResolutionCallback was not run";
87 EXPECT_FALSE(OnReadyRun
) << "OnReady unexpectedly run";
90 TEST_F(CoreAPIsStandardTest
, EmptyLookup
) {
91 bool OnResolvedRun
= false;
92 bool OnReadyRun
= false;
94 auto OnResolution
= [&](Expected
<SymbolMap
> Result
) {
95 cantFail(std::move(Result
));
99 auto OnReady
= [&](Error Err
) {
100 cantFail(std::move(Err
));
104 ES
.lookup({&JD
}, {}, OnResolution
, OnReady
, NoDependenciesToRegister
);
106 EXPECT_TRUE(OnResolvedRun
) << "OnResolved was not run for empty query";
107 EXPECT_TRUE(OnReadyRun
) << "OnReady was not run for empty query";
110 TEST_F(CoreAPIsStandardTest
, RemoveSymbolsTest
) {
112 // (1) Missing symbols generate a SymbolsNotFound error.
113 // (2) Materializing symbols generate a SymbolCouldNotBeRemoved error.
114 // (3) Removal of unmaterialized symbols triggers discard on the
115 // materialization unit.
116 // (4) Removal of symbols destroys empty materialization units.
117 // (5) Removal of materialized symbols works.
119 // Foo will be fully materialized.
120 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
122 // Bar will be unmaterialized.
123 bool BarDiscarded
= false;
124 bool BarMaterializerDestructed
= false;
125 cantFail(JD
.define(llvm::make_unique
<SimpleMaterializationUnit
>(
126 SymbolFlagsMap({{Bar
, BarSym
.getFlags()}}),
127 [this](MaterializationResponsibility R
) {
128 ADD_FAILURE() << "Unexpected materialization of \"Bar\"";
129 R
.resolve({{Bar
, BarSym
}});
132 [&](const JITDylib
&JD
, const SymbolStringPtr
&Name
) {
133 EXPECT_EQ(Name
, Bar
) << "Expected \"Bar\" to be discarded";
137 [&]() { BarMaterializerDestructed
= true; })));
139 // Baz will be in the materializing state initially, then
140 // materialized for the final removal attempt.
141 Optional
<MaterializationResponsibility
> BazR
;
142 cantFail(JD
.define(llvm::make_unique
<SimpleMaterializationUnit
>(
143 SymbolFlagsMap({{Baz
, BazSym
.getFlags()}}),
144 [&](MaterializationResponsibility R
) { BazR
.emplace(std::move(R
)); },
145 [](const JITDylib
&JD
, const SymbolStringPtr
&Name
) {
146 ADD_FAILURE() << "\"Baz\" discarded unexpectedly";
149 bool OnResolvedRun
= false;
150 bool OnReadyRun
= false;
151 ES
.lookup({&JD
}, {Foo
, Baz
},
152 [&](Expected
<SymbolMap
> Result
) {
153 EXPECT_TRUE(!!Result
) << "OnResolved failed unexpectedly";
154 consumeError(Result
.takeError());
155 OnResolvedRun
= true;
158 EXPECT_FALSE(!!Err
) << "OnReady failed unexpectedly";
159 consumeError(std::move(Err
));
162 NoDependenciesToRegister
);
165 // Attempt 1: Search for a missing symbol, Qux.
166 auto Err
= JD
.remove({Foo
, Bar
, Baz
, Qux
});
167 EXPECT_TRUE(!!Err
) << "Expected failure";
168 EXPECT_TRUE(Err
.isA
<SymbolsNotFound
>())
169 << "Expected a SymbolsNotFound error";
170 consumeError(std::move(Err
));
174 // Attempt 2: Search for a symbol that is still materializing, Baz.
175 auto Err
= JD
.remove({Foo
, Bar
, Baz
});
176 EXPECT_TRUE(!!Err
) << "Expected failure";
177 EXPECT_TRUE(Err
.isA
<SymbolsCouldNotBeRemoved
>())
178 << "Expected a SymbolsNotFound error";
179 consumeError(std::move(Err
));
182 BazR
->resolve({{Baz
, BazSym
}});
185 // Attempt 3: Search now that all symbols are fully materialized
186 // (Foo, Baz), or not yet materialized (Bar).
187 auto Err
= JD
.remove({Foo
, Bar
, Baz
});
188 EXPECT_FALSE(!!Err
) << "Expected failure";
191 EXPECT_TRUE(BarDiscarded
) << "\"Bar\" should have been discarded";
192 EXPECT_TRUE(BarMaterializerDestructed
)
193 << "\"Bar\"'s materializer should have been destructed";
194 EXPECT_TRUE(OnResolvedRun
) << "OnResolved should have been run";
195 EXPECT_TRUE(OnReadyRun
) << "OnReady should have been run";
198 TEST_F(CoreAPIsStandardTest
, ChainedJITDylibLookup
) {
199 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
201 auto &JD2
= ES
.createJITDylib("JD2");
203 bool OnResolvedRun
= false;
204 bool OnReadyRun
= false;
206 auto Q
= std::make_shared
<AsynchronousSymbolQuery
>(
207 SymbolNameSet({Foo
}),
208 [&](Expected
<SymbolMap
> Result
) {
209 cantFail(std::move(Result
));
210 OnResolvedRun
= true;
213 cantFail(std::move(Err
));
217 JD2
.legacyLookup(Q
, JD
.legacyLookup(Q
, {Foo
}));
219 EXPECT_TRUE(OnResolvedRun
) << "OnResolved was not run for empty query";
220 EXPECT_TRUE(OnReadyRun
) << "OnReady was not run for empty query";
223 TEST_F(CoreAPIsStandardTest
, LookupFlagsTest
) {
224 // Test that lookupFlags works on a predefined symbol, and does not trigger
225 // materialization of a lazy symbol. Make the lazy symbol weak to test that
226 // the weak flag is propagated correctly.
228 BarSym
.setFlags(static_cast<JITSymbolFlags::FlagNames
>(
229 JITSymbolFlags::Exported
| JITSymbolFlags::Weak
));
230 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
231 SymbolFlagsMap({{Bar
, BarSym
.getFlags()}}),
232 [](MaterializationResponsibility R
) {
233 llvm_unreachable("Symbol materialized on flags lookup");
236 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
237 cantFail(JD
.define(std::move(MU
)));
239 SymbolNameSet
Names({Foo
, Bar
, Baz
});
241 auto SymbolFlags
= JD
.lookupFlags(Names
);
243 EXPECT_EQ(SymbolFlags
.size(), 2U)
244 << "Returned symbol flags contains unexpected results";
245 EXPECT_EQ(SymbolFlags
.count(Foo
), 1U) << "Missing lookupFlags result for Foo";
246 EXPECT_EQ(SymbolFlags
[Foo
], FooSym
.getFlags())
247 << "Incorrect flags returned for Foo";
248 EXPECT_EQ(SymbolFlags
.count(Bar
), 1U)
249 << "Missing lookupFlags result for Bar";
250 EXPECT_EQ(SymbolFlags
[Bar
], BarSym
.getFlags())
251 << "Incorrect flags returned for Bar";
254 TEST_F(CoreAPIsStandardTest
, TestBasicAliases
) {
255 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}, {Bar
, BarSym
}})));
256 cantFail(JD
.define(symbolAliases({{Baz
, {Foo
, JITSymbolFlags::Exported
}},
257 {Qux
, {Bar
, JITSymbolFlags::Weak
}}})));
258 cantFail(JD
.define(absoluteSymbols({{Qux
, QuxSym
}})));
260 auto Result
= lookup({&JD
}, {Baz
, Qux
});
261 EXPECT_TRUE(!!Result
) << "Unexpected lookup failure";
262 EXPECT_EQ(Result
->count(Baz
), 1U) << "No result for \"baz\"";
263 EXPECT_EQ(Result
->count(Qux
), 1U) << "No result for \"qux\"";
264 EXPECT_EQ((*Result
)[Baz
].getAddress(), FooSym
.getAddress())
265 << "\"Baz\"'s address should match \"Foo\"'s";
266 EXPECT_EQ((*Result
)[Qux
].getAddress(), QuxSym
.getAddress())
267 << "The \"Qux\" alias should have been overriden";
270 TEST_F(CoreAPIsStandardTest
, TestChainedAliases
) {
271 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
272 cantFail(JD
.define(symbolAliases(
273 {{Baz
, {Bar
, BazSym
.getFlags()}}, {Bar
, {Foo
, BarSym
.getFlags()}}})));
275 auto Result
= lookup({&JD
}, {Bar
, Baz
});
276 EXPECT_TRUE(!!Result
) << "Unexpected lookup failure";
277 EXPECT_EQ(Result
->count(Bar
), 1U) << "No result for \"bar\"";
278 EXPECT_EQ(Result
->count(Baz
), 1U) << "No result for \"baz\"";
279 EXPECT_EQ((*Result
)[Bar
].getAddress(), FooSym
.getAddress())
280 << "\"Bar\"'s address should match \"Foo\"'s";
281 EXPECT_EQ((*Result
)[Baz
].getAddress(), FooSym
.getAddress())
282 << "\"Baz\"'s address should match \"Foo\"'s";
285 TEST_F(CoreAPIsStandardTest
, TestBasicReExports
) {
286 // Test that the basic use case of re-exporting a single symbol from another
288 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
290 auto &JD2
= ES
.createJITDylib("JD2");
292 cantFail(JD2
.define(reexports(JD
, {{Bar
, {Foo
, BarSym
.getFlags()}}})));
294 auto Result
= cantFail(lookup({&JD2
}, Bar
));
295 EXPECT_EQ(Result
.getAddress(), FooSym
.getAddress())
296 << "Re-export Bar for symbol Foo should match FooSym's address";
299 TEST_F(CoreAPIsStandardTest
, TestThatReExportsDontUnnecessarilyMaterialize
) {
300 // Test that re-exports do not materialize symbols that have not been queried
302 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
304 bool BarMaterialized
= false;
305 auto BarMU
= llvm::make_unique
<SimpleMaterializationUnit
>(
306 SymbolFlagsMap({{Bar
, BarSym
.getFlags()}}),
307 [&](MaterializationResponsibility R
) {
308 BarMaterialized
= true;
309 R
.resolve({{Bar
, BarSym
}});
313 cantFail(JD
.define(BarMU
));
315 auto &JD2
= ES
.createJITDylib("JD2");
317 cantFail(JD2
.define(reexports(
318 JD
, {{Baz
, {Foo
, BazSym
.getFlags()}}, {Qux
, {Bar
, QuxSym
.getFlags()}}})));
320 auto Result
= cantFail(lookup({&JD2
}, Baz
));
321 EXPECT_EQ(Result
.getAddress(), FooSym
.getAddress())
322 << "Re-export Baz for symbol Foo should match FooSym's address";
324 EXPECT_FALSE(BarMaterialized
) << "Bar should not have been materialized";
327 TEST_F(CoreAPIsStandardTest
, TestReexportsFallbackGenerator
) {
328 // Test that a re-exports fallback generator can dynamically generate
331 auto &JD2
= ES
.createJITDylib("JD2");
332 cantFail(JD2
.define(absoluteSymbols({{Foo
, FooSym
}, {Bar
, BarSym
}})));
334 auto Filter
= [this](SymbolStringPtr Name
) { return Name
!= Bar
; };
336 JD
.setFallbackDefinitionGenerator(
337 ReexportsFallbackDefinitionGenerator(JD2
, Filter
));
339 auto Flags
= JD
.lookupFlags({Foo
, Bar
, Baz
});
340 EXPECT_EQ(Flags
.size(), 1U) << "Unexpected number of results";
341 EXPECT_EQ(Flags
[Foo
], FooSym
.getFlags()) << "Unexpected flags for Foo";
343 auto Result
= cantFail(lookup({&JD
}, Foo
));
345 EXPECT_EQ(Result
.getAddress(), FooSym
.getAddress())
346 << "Incorrect reexported symbol address";
349 TEST_F(CoreAPIsStandardTest
, TestTrivialCircularDependency
) {
350 Optional
<MaterializationResponsibility
> FooR
;
351 auto FooMU
= llvm::make_unique
<SimpleMaterializationUnit
>(
352 SymbolFlagsMap({{Foo
, FooSym
.getFlags()}}),
353 [&](MaterializationResponsibility R
) { FooR
.emplace(std::move(R
)); });
355 cantFail(JD
.define(FooMU
));
357 bool FooReady
= false;
358 auto OnResolution
= [](Expected
<SymbolMap
> R
) { cantFail(std::move(R
)); };
359 auto OnReady
= [&](Error Err
) {
360 cantFail(std::move(Err
));
364 ES
.lookup({&JD
}, {Foo
}, std::move(OnResolution
), std::move(OnReady
),
365 NoDependenciesToRegister
);
367 FooR
->resolve({{Foo
, FooSym
}});
370 EXPECT_TRUE(FooReady
)
371 << "Self-dependency prevented symbol from being marked ready";
374 TEST_F(CoreAPIsStandardTest
, TestCircularDependenceInOneJITDylib
) {
375 // Test that a circular symbol dependency between three symbols in a JITDylib
376 // does not prevent any symbol from becoming 'ready' once all symbols are
379 // Create three MaterializationResponsibility objects: one for each of Foo,
380 // Bar and Baz. These are optional because MaterializationResponsibility
381 // does not have a default constructor).
382 Optional
<MaterializationResponsibility
> FooR
;
383 Optional
<MaterializationResponsibility
> BarR
;
384 Optional
<MaterializationResponsibility
> BazR
;
386 // Create a MaterializationUnit for each symbol that moves the
387 // MaterializationResponsibility into one of the locals above.
388 auto FooMU
= llvm::make_unique
<SimpleMaterializationUnit
>(
389 SymbolFlagsMap({{Foo
, FooSym
.getFlags()}}),
390 [&](MaterializationResponsibility R
) { FooR
.emplace(std::move(R
)); });
392 auto BarMU
= llvm::make_unique
<SimpleMaterializationUnit
>(
393 SymbolFlagsMap({{Bar
, BarSym
.getFlags()}}),
394 [&](MaterializationResponsibility R
) { BarR
.emplace(std::move(R
)); });
396 auto BazMU
= llvm::make_unique
<SimpleMaterializationUnit
>(
397 SymbolFlagsMap({{Baz
, BazSym
.getFlags()}}),
398 [&](MaterializationResponsibility R
) { BazR
.emplace(std::move(R
)); });
400 // Define the symbols.
401 cantFail(JD
.define(FooMU
));
402 cantFail(JD
.define(BarMU
));
403 cantFail(JD
.define(BazMU
));
405 // Query each of the symbols to trigger materialization.
406 bool FooResolved
= false;
407 bool FooReady
= false;
409 auto OnFooResolution
= [&](Expected
<SymbolMap
> Result
) {
410 cantFail(std::move(Result
));
414 auto OnFooReady
= [&](Error Err
) {
415 cantFail(std::move(Err
));
419 // Issue a lookup for Foo. Use NoDependenciesToRegister: We're going to add
420 // the dependencies manually below.
421 ES
.lookup({&JD
}, {Foo
}, std::move(OnFooResolution
), std::move(OnFooReady
),
422 NoDependenciesToRegister
);
424 bool BarResolved
= false;
425 bool BarReady
= false;
426 auto OnBarResolution
= [&](Expected
<SymbolMap
> Result
) {
427 cantFail(std::move(Result
));
431 auto OnBarReady
= [&](Error Err
) {
432 cantFail(std::move(Err
));
436 ES
.lookup({&JD
}, {Bar
}, std::move(OnBarResolution
), std::move(OnBarReady
),
437 NoDependenciesToRegister
);
439 bool BazResolved
= false;
440 bool BazReady
= false;
442 auto OnBazResolution
= [&](Expected
<SymbolMap
> Result
) {
443 cantFail(std::move(Result
));
447 auto OnBazReady
= [&](Error Err
) {
448 cantFail(std::move(Err
));
452 ES
.lookup({&JD
}, {Baz
}, std::move(OnBazResolution
), std::move(OnBazReady
),
453 NoDependenciesToRegister
);
455 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo.
456 FooR
->addDependenciesForAll({{&JD
, SymbolNameSet({Bar
})}});
457 BarR
->addDependenciesForAll({{&JD
, SymbolNameSet({Baz
})}});
458 BazR
->addDependenciesForAll({{&JD
, SymbolNameSet({Foo
})}});
460 // Add self-dependencies for good measure. This tests that the implementation
461 // of addDependencies filters these out.
462 FooR
->addDependenciesForAll({{&JD
, SymbolNameSet({Foo
})}});
463 BarR
->addDependenciesForAll({{&JD
, SymbolNameSet({Bar
})}});
464 BazR
->addDependenciesForAll({{&JD
, SymbolNameSet({Baz
})}});
466 // Check that nothing has been resolved yet.
467 EXPECT_FALSE(FooResolved
) << "\"Foo\" should not be resolved yet";
468 EXPECT_FALSE(BarResolved
) << "\"Bar\" should not be resolved yet";
469 EXPECT_FALSE(BazResolved
) << "\"Baz\" should not be resolved yet";
471 // Resolve the symbols (but do not emit them).
472 FooR
->resolve({{Foo
, FooSym
}});
473 BarR
->resolve({{Bar
, BarSym
}});
474 BazR
->resolve({{Baz
, BazSym
}});
476 // Verify that the symbols have been resolved, but are not ready yet.
477 EXPECT_TRUE(FooResolved
) << "\"Foo\" should be resolved now";
478 EXPECT_TRUE(BarResolved
) << "\"Bar\" should be resolved now";
479 EXPECT_TRUE(BazResolved
) << "\"Baz\" should be resolved now";
481 EXPECT_FALSE(FooReady
) << "\"Foo\" should not be ready yet";
482 EXPECT_FALSE(BarReady
) << "\"Bar\" should not be ready yet";
483 EXPECT_FALSE(BazReady
) << "\"Baz\" should not be ready yet";
485 // Emit two of the symbols.
489 // Verify that nothing is ready until the circular dependence is resolved.
490 EXPECT_FALSE(FooReady
) << "\"Foo\" still should not be ready";
491 EXPECT_FALSE(BarReady
) << "\"Bar\" still should not be ready";
492 EXPECT_FALSE(BazReady
) << "\"Baz\" still should not be ready";
494 // Emit the last symbol.
497 // Verify that everything becomes ready once the circular dependence resolved.
498 EXPECT_TRUE(FooReady
) << "\"Foo\" should be ready now";
499 EXPECT_TRUE(BarReady
) << "\"Bar\" should be ready now";
500 EXPECT_TRUE(BazReady
) << "\"Baz\" should be ready now";
503 TEST_F(CoreAPIsStandardTest
, DropMaterializerWhenEmpty
) {
504 bool DestructorRun
= false;
506 JITSymbolFlags
WeakExported(JITSymbolFlags::Exported
);
507 WeakExported
|= JITSymbolFlags::Weak
;
509 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
510 SymbolFlagsMap({{Foo
, WeakExported
}, {Bar
, WeakExported
}}),
511 [](MaterializationResponsibility R
) {
512 llvm_unreachable("Unexpected call to materialize");
514 [&](const JITDylib
&JD
, SymbolStringPtr Name
) {
515 EXPECT_TRUE(Name
== Foo
|| Name
== Bar
)
516 << "Discard of unexpected symbol?";
518 [&]() { DestructorRun
= true; });
520 cantFail(JD
.define(MU
));
522 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
524 EXPECT_FALSE(DestructorRun
)
525 << "MaterializationUnit should not have been destroyed yet";
527 cantFail(JD
.define(absoluteSymbols({{Bar
, BarSym
}})));
529 EXPECT_TRUE(DestructorRun
)
530 << "MaterializationUnit should have been destroyed";
533 TEST_F(CoreAPIsStandardTest
, AddAndMaterializeLazySymbol
) {
534 bool FooMaterialized
= false;
535 bool BarDiscarded
= false;
537 JITSymbolFlags
WeakExported(JITSymbolFlags::Exported
);
538 WeakExported
|= JITSymbolFlags::Weak
;
540 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
541 SymbolFlagsMap({{Foo
, JITSymbolFlags::Exported
}, {Bar
, WeakExported
}}),
542 [&](MaterializationResponsibility R
) {
543 assert(BarDiscarded
&& "Bar should have been discarded by this point");
544 R
.resolve(SymbolMap({{Foo
, FooSym
}}));
546 FooMaterialized
= true;
548 [&](const JITDylib
&JD
, SymbolStringPtr Name
) {
549 EXPECT_EQ(Name
, Bar
) << "Expected Name to be Bar";
553 cantFail(JD
.define(MU
));
554 cantFail(JD
.define(absoluteSymbols({{Bar
, BarSym
}})));
556 SymbolNameSet
Names({Foo
});
558 bool OnResolutionRun
= false;
559 bool OnReadyRun
= false;
561 auto OnResolution
= [&](Expected
<SymbolMap
> Result
) {
562 EXPECT_TRUE(!!Result
) << "Resolution unexpectedly returned error";
563 auto I
= Result
->find(Foo
);
564 EXPECT_NE(I
, Result
->end()) << "Could not find symbol definition";
565 EXPECT_EQ(I
->second
.getAddress(), FooSym
.getAddress())
566 << "Resolution returned incorrect result";
567 OnResolutionRun
= true;
570 auto OnReady
= [&](Error Err
) {
571 cantFail(std::move(Err
));
575 ES
.lookup({&JD
}, Names
, std::move(OnResolution
), std::move(OnReady
),
576 NoDependenciesToRegister
);
578 EXPECT_TRUE(FooMaterialized
) << "Foo was not materialized";
579 EXPECT_TRUE(BarDiscarded
) << "Bar was not discarded";
580 EXPECT_TRUE(OnResolutionRun
) << "OnResolutionCallback was not run";
581 EXPECT_TRUE(OnReadyRun
) << "OnReady was not run";
584 TEST_F(CoreAPIsStandardTest
, TestBasicWeakSymbolMaterialization
) {
585 // Test that weak symbols are materialized correctly when we look them up.
586 BarSym
.setFlags(BarSym
.getFlags() | JITSymbolFlags::Weak
);
588 bool BarMaterialized
= false;
589 auto MU1
= llvm::make_unique
<SimpleMaterializationUnit
>(
590 SymbolFlagsMap({{Foo
, FooSym
.getFlags()}, {Bar
, BarSym
.getFlags()}}),
591 [&](MaterializationResponsibility R
) {
592 R
.resolve(SymbolMap({{Foo
, FooSym
}, {Bar
, BarSym
}})), R
.emit();
593 BarMaterialized
= true;
596 bool DuplicateBarDiscarded
= false;
597 auto MU2
= llvm::make_unique
<SimpleMaterializationUnit
>(
598 SymbolFlagsMap({{Bar
, BarSym
.getFlags()}}),
599 [&](MaterializationResponsibility R
) {
600 ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit";
601 R
.failMaterialization();
603 [&](const JITDylib
&JD
, SymbolStringPtr Name
) {
604 EXPECT_EQ(Name
, Bar
) << "Expected \"Bar\" to be discarded";
605 DuplicateBarDiscarded
= true;
608 cantFail(JD
.define(MU1
));
609 cantFail(JD
.define(MU2
));
611 bool OnResolvedRun
= false;
612 bool OnReadyRun
= false;
614 auto OnResolution
= [&](Expected
<SymbolMap
> Result
) {
615 cantFail(std::move(Result
));
616 OnResolvedRun
= true;
619 auto OnReady
= [&](Error Err
) {
620 cantFail(std::move(Err
));
624 ES
.lookup({&JD
}, {Bar
}, std::move(OnResolution
), std::move(OnReady
),
625 NoDependenciesToRegister
);
627 EXPECT_TRUE(OnResolvedRun
) << "OnResolved not run";
628 EXPECT_TRUE(OnReadyRun
) << "OnReady not run";
629 EXPECT_TRUE(BarMaterialized
) << "Bar was not materialized at all";
630 EXPECT_TRUE(DuplicateBarDiscarded
)
631 << "Duplicate bar definition not discarded";
634 TEST_F(CoreAPIsStandardTest
, DefineMaterializingSymbol
) {
635 bool ExpectNoMoreMaterialization
= false;
636 ES
.setDispatchMaterialization(
637 [&](JITDylib
&JD
, std::unique_ptr
<MaterializationUnit
> MU
) {
638 if (ExpectNoMoreMaterialization
)
639 ADD_FAILURE() << "Unexpected materialization";
640 MU
->doMaterialize(JD
);
643 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
644 SymbolFlagsMap({{Foo
, FooSym
.getFlags()}}),
645 [&](MaterializationResponsibility R
) {
647 R
.defineMaterializing(SymbolFlagsMap({{Bar
, BarSym
.getFlags()}})));
648 R
.resolve(SymbolMap({{Foo
, FooSym
}, {Bar
, BarSym
}}));
652 cantFail(JD
.define(MU
));
653 cantFail(lookup({&JD
}, Foo
));
655 // Assert that materialization is complete by now.
656 ExpectNoMoreMaterialization
= true;
658 // Look up bar to verify that no further materialization happens.
659 auto BarResult
= cantFail(lookup({&JD
}, Bar
));
660 EXPECT_EQ(BarResult
.getAddress(), BarSym
.getAddress())
661 << "Expected Bar == BarSym";
664 TEST_F(CoreAPIsStandardTest
, FallbackDefinitionGeneratorTest
) {
665 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
667 JD
.setFallbackDefinitionGenerator(
668 [&](JITDylib
&JD2
, const SymbolNameSet
&Names
) {
669 cantFail(JD2
.define(absoluteSymbols({{Bar
, BarSym
}})));
670 return SymbolNameSet({Bar
});
673 auto Result
= cantFail(lookup({&JD
}, {Foo
, Bar
}));
675 EXPECT_EQ(Result
.count(Bar
), 1U) << "Expected to find fallback def for 'bar'";
676 EXPECT_EQ(Result
[Bar
].getAddress(), BarSym
.getAddress())
677 << "Expected fallback def for Bar to be equal to BarSym";
680 TEST_F(CoreAPIsStandardTest
, FailResolution
) {
681 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
683 {{Foo
, JITSymbolFlags::Weak
}, {Bar
, JITSymbolFlags::Weak
}}),
684 [&](MaterializationResponsibility R
) { R
.failMaterialization(); });
686 cantFail(JD
.define(MU
));
688 SymbolNameSet
Names({Foo
, Bar
});
689 auto Result
= lookup({&JD
}, Names
);
691 EXPECT_FALSE(!!Result
) << "Expected failure";
693 handleAllErrors(Result
.takeError(),
694 [&](FailedToMaterialize
&F
) {
695 EXPECT_EQ(F
.getSymbols(), Names
)
696 << "Expected to fail on symbols in Names";
698 [](ErrorInfoBase
&EIB
) {
701 raw_string_ostream
ErrOut(ErrMsg
);
705 << "Expected a FailedToResolve error. Got:\n"
711 TEST_F(CoreAPIsStandardTest
, TestLookupWithUnthreadedMaterialization
) {
712 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
713 SymbolFlagsMap({{Foo
, JITSymbolFlags::Exported
}}),
714 [&](MaterializationResponsibility R
) {
715 R
.resolve({{Foo
, FooSym
}});
719 cantFail(JD
.define(MU
));
721 auto FooLookupResult
= cantFail(lookup({&JD
}, Foo
));
723 EXPECT_EQ(FooLookupResult
.getAddress(), FooSym
.getAddress())
724 << "lookup returned an incorrect address";
725 EXPECT_EQ(FooLookupResult
.getFlags(), FooSym
.getFlags())
726 << "lookup returned incorrect flags";
729 TEST_F(CoreAPIsStandardTest
, TestLookupWithThreadedMaterialization
) {
730 #if LLVM_ENABLE_THREADS
732 std::thread MaterializationThread
;
733 ES
.setDispatchMaterialization(
734 [&](JITDylib
&JD
, std::unique_ptr
<MaterializationUnit
> MU
) {
735 auto SharedMU
= std::shared_ptr
<MaterializationUnit
>(std::move(MU
));
736 MaterializationThread
=
737 std::thread([SharedMU
, &JD
]() { SharedMU
->doMaterialize(JD
); });
740 cantFail(JD
.define(absoluteSymbols({{Foo
, FooSym
}})));
742 auto FooLookupResult
= cantFail(lookup({&JD
}, Foo
));
744 EXPECT_EQ(FooLookupResult
.getAddress(), FooSym
.getAddress())
745 << "lookup returned an incorrect address";
746 EXPECT_EQ(FooLookupResult
.getFlags(), FooSym
.getFlags())
747 << "lookup returned incorrect flags";
748 MaterializationThread
.join();
752 TEST_F(CoreAPIsStandardTest
, TestGetRequestedSymbolsAndReplace
) {
753 // Test that GetRequestedSymbols returns the set of symbols that currently
754 // have pending queries, and test that MaterializationResponsibility's
755 // replace method can be used to return definitions to the JITDylib in a new
756 // MaterializationUnit.
757 SymbolNameSet
Names({Foo
, Bar
});
759 bool FooMaterialized
= false;
760 bool BarMaterialized
= false;
762 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
763 SymbolFlagsMap({{Foo
, FooSym
.getFlags()}, {Bar
, BarSym
.getFlags()}}),
764 [&](MaterializationResponsibility R
) {
765 auto Requested
= R
.getRequestedSymbols();
766 EXPECT_EQ(Requested
.size(), 1U) << "Expected one symbol requested";
767 EXPECT_EQ(*Requested
.begin(), Foo
) << "Expected \"Foo\" requested";
769 auto NewMU
= llvm::make_unique
<SimpleMaterializationUnit
>(
770 SymbolFlagsMap({{Bar
, BarSym
.getFlags()}}),
771 [&](MaterializationResponsibility R2
) {
772 R2
.resolve(SymbolMap({{Bar
, BarSym
}}));
774 BarMaterialized
= true;
777 R
.replace(std::move(NewMU
));
779 R
.resolve(SymbolMap({{Foo
, FooSym
}}));
782 FooMaterialized
= true;
785 cantFail(JD
.define(MU
));
787 EXPECT_FALSE(FooMaterialized
) << "Foo should not be materialized yet";
788 EXPECT_FALSE(BarMaterialized
) << "Bar should not be materialized yet";
790 auto FooSymResult
= cantFail(lookup({&JD
}, Foo
));
791 EXPECT_EQ(FooSymResult
.getAddress(), FooSym
.getAddress())
792 << "Address mismatch for Foo";
794 EXPECT_TRUE(FooMaterialized
) << "Foo should be materialized now";
795 EXPECT_FALSE(BarMaterialized
) << "Bar still should not be materialized";
797 auto BarSymResult
= cantFail(lookup({&JD
}, Bar
));
798 EXPECT_EQ(BarSymResult
.getAddress(), BarSym
.getAddress())
799 << "Address mismatch for Bar";
800 EXPECT_TRUE(BarMaterialized
) << "Bar should be materialized now";
803 TEST_F(CoreAPIsStandardTest
, TestMaterializationResponsibilityDelegation
) {
804 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
805 SymbolFlagsMap({{Foo
, FooSym
.getFlags()}, {Bar
, BarSym
.getFlags()}}),
806 [&](MaterializationResponsibility R
) {
807 auto R2
= R
.delegate({Bar
});
809 R
.resolve({{Foo
, FooSym
}});
811 R2
.resolve({{Bar
, BarSym
}});
815 cantFail(JD
.define(MU
));
817 auto Result
= lookup({&JD
}, {Foo
, Bar
});
819 EXPECT_TRUE(!!Result
) << "Result should be a success value";
820 EXPECT_EQ(Result
->count(Foo
), 1U) << "\"Foo\" entry missing";
821 EXPECT_EQ(Result
->count(Bar
), 1U) << "\"Bar\" entry missing";
822 EXPECT_EQ((*Result
)[Foo
].getAddress(), FooSym
.getAddress())
823 << "Address mismatch for \"Foo\"";
824 EXPECT_EQ((*Result
)[Bar
].getAddress(), BarSym
.getAddress())
825 << "Address mismatch for \"Bar\"";
828 TEST_F(CoreAPIsStandardTest
, TestMaterializeWeakSymbol
) {
829 // Confirm that once a weak definition is selected for materialization it is
830 // treated as strong.
831 JITSymbolFlags WeakExported
= JITSymbolFlags::Exported
;
832 WeakExported
&= JITSymbolFlags::Weak
;
834 std::unique_ptr
<MaterializationResponsibility
> FooResponsibility
;
835 auto MU
= llvm::make_unique
<SimpleMaterializationUnit
>(
836 SymbolFlagsMap({{Foo
, FooSym
.getFlags()}}),
837 [&](MaterializationResponsibility R
) {
839 llvm::make_unique
<MaterializationResponsibility
>(std::move(R
));
842 cantFail(JD
.define(MU
));
843 auto OnResolution
= [](Expected
<SymbolMap
> Result
) {
844 cantFail(std::move(Result
));
847 auto OnReady
= [](Error Err
) { cantFail(std::move(Err
)); };
849 ES
.lookup({&JD
}, {Foo
}, std::move(OnResolution
), std::move(OnReady
),
850 NoDependenciesToRegister
);
852 auto MU2
= llvm::make_unique
<SimpleMaterializationUnit
>(
853 SymbolFlagsMap({{Foo
, JITSymbolFlags::Exported
}}),
854 [](MaterializationResponsibility R
) {
855 llvm_unreachable("This unit should never be materialized");
858 auto Err
= JD
.define(MU2
);
859 EXPECT_TRUE(!!Err
) << "Expected failure value";
860 EXPECT_TRUE(Err
.isA
<DuplicateDefinition
>())
861 << "Expected a duplicate definition error";
862 consumeError(std::move(Err
));
864 FooResponsibility
->resolve(SymbolMap({{Foo
, FooSym
}}));
865 FooResponsibility
->emit();
868 TEST_F(CoreAPIsStandardTest
, TestMainJITDylibAndDefaultLookupOrder
) {
869 cantFail(ES
.getMainJITDylib().define(absoluteSymbols({{Foo
, FooSym
}})));
870 auto Results
= cantFail(ES
.lookup({Foo
}));
872 EXPECT_EQ(Results
.size(), 1U) << "Incorrect number of results";
873 EXPECT_EQ(Results
.count(Foo
), 1U) << "Expected result for 'Foo'";
874 EXPECT_EQ(Results
[Foo
].getAddress(), FooSym
.getAddress())
875 << "Expected result address to match Foo's address";