xref: /llvm-project/llvm/unittests/ExecutionEngine/Orc/ResourceTrackerTest.cpp (revision ebe8733a11e735bb9f5ca45ec752c2a416380c8d)
1b66b73beSStefan Gränitz //===------ ResourceTrackerTest.cpp - Unit tests ResourceTracker API ------===//
20aec49c8SLang Hames //
30aec49c8SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40aec49c8SLang Hames // See https://llvm.org/LICENSE.txt for license information.
50aec49c8SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60aec49c8SLang Hames //
70aec49c8SLang Hames //===----------------------------------------------------------------------===//
80aec49c8SLang Hames 
90aec49c8SLang Hames #include "OrcTestCommon.h"
100aec49c8SLang Hames #include "llvm/ADT/FunctionExtras.h"
110aec49c8SLang Hames #include "llvm/Config/llvm-config.h"
120aec49c8SLang Hames #include "llvm/ExecutionEngine/Orc/Core.h"
1324672ddeSLang Hames #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"
140aec49c8SLang Hames #include "llvm/Testing/Support/Error.h"
150aec49c8SLang Hames 
160aec49c8SLang Hames using namespace llvm;
170aec49c8SLang Hames using namespace llvm::orc;
180aec49c8SLang Hames 
190aec49c8SLang Hames class ResourceTrackerStandardTest : public CoreAPIsBasedStandardTest {};
200aec49c8SLang Hames 
210aec49c8SLang Hames namespace {
220aec49c8SLang Hames 
230aec49c8SLang Hames template <typename ResourceT = unsigned>
240aec49c8SLang Hames class SimpleResourceManager : public ResourceManager {
250aec49c8SLang Hames public:
26bf6d7ca9SLang Hames   using HandleRemoveFunction =
27bf6d7ca9SLang Hames       unique_function<Error(JITDylib &JD, ResourceKey)>;
280aec49c8SLang Hames 
290aec49c8SLang Hames   using HandleTransferFunction =
30bf6d7ca9SLang Hames       unique_function<void(JITDylib &JD, ResourceKey, ResourceKey)>;
310aec49c8SLang Hames 
320aec49c8SLang Hames   using RecordedResourcesMap = DenseMap<ResourceKey, ResourceT>;
330aec49c8SLang Hames 
SimpleResourceManager(ExecutionSession & ES)34d54c4e38SLang Hames   SimpleResourceManager(ExecutionSession &ES) : ES(ES) {
35bf6d7ca9SLang Hames     HandleRemove = [&](JITDylib &JD, ResourceKey K) -> Error {
36bf6d7ca9SLang Hames       ES.runSessionLocked([&] { removeResource(JD, K); });
370aec49c8SLang Hames       return Error::success();
380aec49c8SLang Hames     };
390aec49c8SLang Hames 
40bf6d7ca9SLang Hames     HandleTransfer = [this](JITDylib &JD, ResourceKey DstKey,
41bf6d7ca9SLang Hames                             ResourceKey SrcKey) {
42bf6d7ca9SLang Hames       transferResources(JD, DstKey, SrcKey);
430aec49c8SLang Hames     };
440aec49c8SLang Hames 
450aec49c8SLang Hames     ES.registerResourceManager(*this);
460aec49c8SLang Hames   }
470aec49c8SLang Hames 
480aec49c8SLang Hames   SimpleResourceManager(const SimpleResourceManager &) = delete;
490aec49c8SLang Hames   SimpleResourceManager &operator=(const SimpleResourceManager &) = delete;
500aec49c8SLang Hames   SimpleResourceManager(SimpleResourceManager &&) = delete;
510aec49c8SLang Hames   SimpleResourceManager &operator=(SimpleResourceManager &&) = delete;
520aec49c8SLang Hames 
~SimpleResourceManager()530aec49c8SLang Hames   ~SimpleResourceManager() { ES.deregisterResourceManager(*this); }
540aec49c8SLang Hames 
55d54c4e38SLang Hames   /// Set the HandleRemove function object.
setHandleRemove(HandleRemoveFunction HandleRemove)56d54c4e38SLang Hames   void setHandleRemove(HandleRemoveFunction HandleRemove) {
57d54c4e38SLang Hames     this->HandleRemove = std::move(HandleRemove);
58d54c4e38SLang Hames   }
59d54c4e38SLang Hames 
60d54c4e38SLang Hames   /// Set the HandleTransfer function object.
setHandleTransfer(HandleTransferFunction HandleTransfer)61d54c4e38SLang Hames   void setHandleTransfer(HandleTransferFunction HandleTransfer) {
62d54c4e38SLang Hames     this->HandleTransfer = std::move(HandleTransfer);
63d54c4e38SLang Hames   }
64d54c4e38SLang Hames 
650aec49c8SLang Hames   /// Create an association between the given key and resource.
660aec49c8SLang Hames   template <typename MergeOp = std::plus<ResourceT>>
recordResource(ResourceKey K,ResourceT Val=ResourceT (),MergeOp Merge=MergeOp ())670aec49c8SLang Hames   void recordResource(ResourceKey K, ResourceT Val = ResourceT(),
680aec49c8SLang Hames                       MergeOp Merge = MergeOp()) {
690aec49c8SLang Hames     auto Tmp = std::move(Resources[K]);
700aec49c8SLang Hames     Resources[K] = Merge(std::move(Tmp), std::move(Val));
710aec49c8SLang Hames   }
720aec49c8SLang Hames 
730aec49c8SLang Hames   /// Remove the resource associated with K from the map if present.
removeResource(JITDylib & JD,ResourceKey K)74bf6d7ca9SLang Hames   void removeResource(JITDylib &JD, ResourceKey K) { Resources.erase(K); }
750aec49c8SLang Hames 
760aec49c8SLang Hames   /// Transfer resources from DstKey to SrcKey.
770aec49c8SLang Hames   template <typename MergeOp = std::plus<ResourceT>>
transferResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey,MergeOp Merge=MergeOp ())78bf6d7ca9SLang Hames   void transferResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey,
790aec49c8SLang Hames                          MergeOp Merge = MergeOp()) {
800aec49c8SLang Hames     auto &DstResourceRef = Resources[DstKey];
810aec49c8SLang Hames     ResourceT DstResources;
820aec49c8SLang Hames     std::swap(DstResourceRef, DstResources);
830aec49c8SLang Hames 
840aec49c8SLang Hames     auto SI = Resources.find(SrcKey);
850aec49c8SLang Hames     assert(SI != Resources.end() && "No resource associated with SrcKey");
860aec49c8SLang Hames 
870aec49c8SLang Hames     DstResourceRef = Merge(std::move(DstResources), std::move(SI->second));
880aec49c8SLang Hames     Resources.erase(SI);
890aec49c8SLang Hames   }
900aec49c8SLang Hames 
910aec49c8SLang Hames   /// Return a reference to the Resources map.
getRecordedResources()920aec49c8SLang Hames   RecordedResourcesMap &getRecordedResources() { return Resources; }
getRecordedResources() const930aec49c8SLang Hames   const RecordedResourcesMap &getRecordedResources() const { return Resources; }
940aec49c8SLang Hames 
handleRemoveResources(JITDylib & JD,ResourceKey K)95bf6d7ca9SLang Hames   Error handleRemoveResources(JITDylib &JD, ResourceKey K) override {
96bf6d7ca9SLang Hames     return HandleRemove(JD, K);
970aec49c8SLang Hames   }
980aec49c8SLang Hames 
handleTransferResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)99bf6d7ca9SLang Hames   void handleTransferResources(JITDylib &JD, ResourceKey DstKey,
1000aec49c8SLang Hames                                ResourceKey SrcKey) override {
101bf6d7ca9SLang Hames     HandleTransfer(JD, DstKey, SrcKey);
1020aec49c8SLang Hames   }
1030aec49c8SLang Hames 
transferNotAllowed(ResourceKey DstKey,ResourceKey SrcKey)1040aec49c8SLang Hames   static void transferNotAllowed(ResourceKey DstKey, ResourceKey SrcKey) {
1050aec49c8SLang Hames     llvm_unreachable("Resource transfer not allowed");
1060aec49c8SLang Hames   }
1070aec49c8SLang Hames 
1080aec49c8SLang Hames private:
1090aec49c8SLang Hames   ExecutionSession &ES;
1100aec49c8SLang Hames   HandleRemoveFunction HandleRemove;
1110aec49c8SLang Hames   HandleTransferFunction HandleTransfer;
1120aec49c8SLang Hames   RecordedResourcesMap Resources;
1130aec49c8SLang Hames };
1140aec49c8SLang Hames 
TEST_F(ResourceTrackerStandardTest,BasicDefineAndRemoveAllBeforeMaterializing)1150aec49c8SLang Hames TEST_F(ResourceTrackerStandardTest,
1160aec49c8SLang Hames        BasicDefineAndRemoveAllBeforeMaterializing) {
1170aec49c8SLang Hames 
1180aec49c8SLang Hames   bool ResourceManagerGotRemove = false;
119d54c4e38SLang Hames   SimpleResourceManager<> SRM(ES);
120bf6d7ca9SLang Hames   SRM.setHandleRemove([&](JITDylib &JD, ResourceKey K) -> Error {
1210aec49c8SLang Hames     ResourceManagerGotRemove = true;
1220aec49c8SLang Hames     EXPECT_EQ(SRM.getRecordedResources().size(), 0U)
1230aec49c8SLang Hames         << "Unexpected resources recorded";
124bf6d7ca9SLang Hames     SRM.removeResource(JD, K);
1250aec49c8SLang Hames     return Error::success();
1260aec49c8SLang Hames   });
1270aec49c8SLang Hames 
1280aec49c8SLang Hames   bool MaterializationUnitDestroyed = false;
1290aec49c8SLang Hames   auto MU = std::make_unique<SimpleMaterializationUnit>(
1300aec49c8SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
1310aec49c8SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
1320aec49c8SLang Hames         llvm_unreachable("Never called");
1330aec49c8SLang Hames       },
1340aec49c8SLang Hames       nullptr, SimpleMaterializationUnit::DiscardFunction(),
1350aec49c8SLang Hames       [&]() { MaterializationUnitDestroyed = true; });
1360aec49c8SLang Hames 
1370aec49c8SLang Hames   auto RT = JD.createResourceTracker();
1380aec49c8SLang Hames   cantFail(JD.define(std::move(MU), RT));
1390aec49c8SLang Hames   cantFail(RT->remove());
140069919c9SLang Hames   auto SymFlags = cantFail(ES.lookupFlags(
141069919c9SLang Hames       LookupKind::Static,
142069919c9SLang Hames       {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
143069919c9SLang Hames       SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol)));
1440aec49c8SLang Hames 
1450aec49c8SLang Hames   EXPECT_EQ(SymFlags.size(), 0U)
1460aec49c8SLang Hames       << "Symbols should have been removed from the symbol table";
1470aec49c8SLang Hames   EXPECT_TRUE(ResourceManagerGotRemove)
1480aec49c8SLang Hames       << "ResourceManager did not receive handleRemoveResources";
1490aec49c8SLang Hames   EXPECT_TRUE(MaterializationUnitDestroyed)
1500aec49c8SLang Hames       << "MaterializationUnit not destroyed in response to removal";
1510aec49c8SLang Hames }
1520aec49c8SLang Hames 
TEST_F(ResourceTrackerStandardTest,BasicDefineAndRemoveAllAfterMaterializing)1530aec49c8SLang Hames TEST_F(ResourceTrackerStandardTest, BasicDefineAndRemoveAllAfterMaterializing) {
1540aec49c8SLang Hames 
1550aec49c8SLang Hames   bool ResourceManagerGotRemove = false;
156d54c4e38SLang Hames   SimpleResourceManager<> SRM(ES);
157bf6d7ca9SLang Hames   SRM.setHandleRemove([&](JITDylib &JD, ResourceKey K) -> Error {
1580aec49c8SLang Hames     ResourceManagerGotRemove = true;
1590aec49c8SLang Hames     EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
1600aec49c8SLang Hames         << "Unexpected number of resources recorded";
1610aec49c8SLang Hames     EXPECT_EQ(SRM.getRecordedResources().count(K), 1U)
1620aec49c8SLang Hames         << "Unexpected recorded resource";
163bf6d7ca9SLang Hames     SRM.removeResource(JD, K);
1640aec49c8SLang Hames     return Error::success();
1650aec49c8SLang Hames   });
1660aec49c8SLang Hames 
1670aec49c8SLang Hames   auto MU = std::make_unique<SimpleMaterializationUnit>(
1680aec49c8SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
1690aec49c8SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
1700aec49c8SLang Hames         cantFail(R->withResourceKeyDo(
1710aec49c8SLang Hames             [&](ResourceKey K) { SRM.recordResource(K); }));
1720aec49c8SLang Hames         cantFail(R->notifyResolved({{Foo, FooSym}}));
173*ebe8733aSlhames         cantFail(R->notifyEmitted({}));
1740aec49c8SLang Hames       });
1750aec49c8SLang Hames 
1760aec49c8SLang Hames   auto RT = JD.createResourceTracker();
1770aec49c8SLang Hames   cantFail(JD.define(std::move(MU), RT));
1780aec49c8SLang Hames   cantFail(ES.lookup({&JD}, Foo));
1790aec49c8SLang Hames   cantFail(RT->remove());
180069919c9SLang Hames   auto SymFlags = cantFail(ES.lookupFlags(
181069919c9SLang Hames       LookupKind::Static,
182069919c9SLang Hames       {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
183069919c9SLang Hames       SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol)));
1840aec49c8SLang Hames 
1850aec49c8SLang Hames   EXPECT_EQ(SymFlags.size(), 0U)
1860aec49c8SLang Hames       << "Symbols should have been removed from the symbol table";
1870aec49c8SLang Hames   EXPECT_TRUE(ResourceManagerGotRemove)
1880aec49c8SLang Hames       << "ResourceManager did not receive handleRemoveResources";
1890aec49c8SLang Hames }
1900aec49c8SLang Hames 
TEST_F(ResourceTrackerStandardTest,BasicDefineAndRemoveAllWhileMaterializing)1910aec49c8SLang Hames TEST_F(ResourceTrackerStandardTest, BasicDefineAndRemoveAllWhileMaterializing) {
1920aec49c8SLang Hames 
1930aec49c8SLang Hames   bool ResourceManagerGotRemove = false;
194d54c4e38SLang Hames   SimpleResourceManager<> SRM(ES);
195bf6d7ca9SLang Hames   SRM.setHandleRemove([&](JITDylib &JD, ResourceKey K) -> Error {
1960aec49c8SLang Hames     ResourceManagerGotRemove = true;
1970aec49c8SLang Hames     EXPECT_EQ(SRM.getRecordedResources().size(), 0U)
1980aec49c8SLang Hames         << "Unexpected resources recorded";
199bf6d7ca9SLang Hames     SRM.removeResource(JD, K);
2000aec49c8SLang Hames     return Error::success();
2010aec49c8SLang Hames   });
2020aec49c8SLang Hames 
2030aec49c8SLang Hames   std::unique_ptr<MaterializationResponsibility> MR;
2040aec49c8SLang Hames   auto MU = std::make_unique<SimpleMaterializationUnit>(
2050aec49c8SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
2060aec49c8SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
2070aec49c8SLang Hames         MR = std::move(R);
2080aec49c8SLang Hames       });
2090aec49c8SLang Hames 
2100aec49c8SLang Hames   auto RT = JD.createResourceTracker();
2110aec49c8SLang Hames   cantFail(JD.define(std::move(MU), RT));
2120aec49c8SLang Hames 
2130aec49c8SLang Hames   ES.lookup(
2140aec49c8SLang Hames       LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
2150aec49c8SLang Hames       SymbolState::Ready,
2160aec49c8SLang Hames       [](Expected<SymbolMap> Result) {
2170aec49c8SLang Hames         EXPECT_THAT_EXPECTED(Result, Failed<FailedToMaterialize>())
2180aec49c8SLang Hames             << "Lookup failed unexpectedly";
2190aec49c8SLang Hames       },
2200aec49c8SLang Hames       NoDependenciesToRegister);
2210aec49c8SLang Hames 
2220aec49c8SLang Hames   cantFail(RT->remove());
223069919c9SLang Hames   auto SymFlags = cantFail(ES.lookupFlags(
224069919c9SLang Hames       LookupKind::Static,
225069919c9SLang Hames       {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
226069919c9SLang Hames       SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol)));
2270aec49c8SLang Hames 
2280aec49c8SLang Hames   EXPECT_EQ(SymFlags.size(), 0U)
2290aec49c8SLang Hames       << "Symbols should have been removed from the symbol table";
2300aec49c8SLang Hames   EXPECT_TRUE(ResourceManagerGotRemove)
2310aec49c8SLang Hames       << "ResourceManager did not receive handleRemoveResources";
2320aec49c8SLang Hames 
2330aec49c8SLang Hames   EXPECT_THAT_ERROR(MR->withResourceKeyDo([](ResourceKey K) {
2340aec49c8SLang Hames     ADD_FAILURE() << "Should not reach withResourceKeyDo body for removed key";
2350aec49c8SLang Hames   }),
2360aec49c8SLang Hames                     Failed<ResourceTrackerDefunct>())
2370aec49c8SLang Hames       << "withResourceKeyDo on MR with removed tracker should have failed";
2380aec49c8SLang Hames   EXPECT_THAT_ERROR(MR->notifyResolved({{Foo, FooSym}}),
2390aec49c8SLang Hames                     Failed<ResourceTrackerDefunct>())
2400aec49c8SLang Hames       << "notifyResolved on MR with removed tracker should have failed";
2410aec49c8SLang Hames 
2420aec49c8SLang Hames   MR->failMaterialization();
2430aec49c8SLang Hames }
2440aec49c8SLang Hames 
TEST_F(ResourceTrackerStandardTest,JITDylibClear)2450aec49c8SLang Hames TEST_F(ResourceTrackerStandardTest, JITDylibClear) {
2460aec49c8SLang Hames   SimpleResourceManager<> SRM(ES);
2470aec49c8SLang Hames 
2480aec49c8SLang Hames   // Add materializer for Foo.
2490aec49c8SLang Hames   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
2500aec49c8SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
2510aec49c8SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
2520aec49c8SLang Hames         cantFail(R->withResourceKeyDo(
2530aec49c8SLang Hames             [&](ResourceKey K) { ++SRM.getRecordedResources()[K]; }));
2540aec49c8SLang Hames         cantFail(R->notifyResolved({{Foo, FooSym}}));
255*ebe8733aSlhames         cantFail(R->notifyEmitted({}));
2560aec49c8SLang Hames       })));
2570aec49c8SLang Hames 
2580aec49c8SLang Hames   // Add materializer for Bar.
2590aec49c8SLang Hames   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
2600aec49c8SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
2610aec49c8SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
2620aec49c8SLang Hames         cantFail(R->withResourceKeyDo(
2630aec49c8SLang Hames             [&](ResourceKey K) { ++SRM.getRecordedResources()[K]; }));
2640aec49c8SLang Hames         cantFail(R->notifyResolved({{Bar, BarSym}}));
265*ebe8733aSlhames         cantFail(R->notifyEmitted({}));
2660aec49c8SLang Hames       })));
2670aec49c8SLang Hames 
2680aec49c8SLang Hames   EXPECT_TRUE(SRM.getRecordedResources().empty())
2690aec49c8SLang Hames       << "Expected no resources recorded yet.";
2700aec49c8SLang Hames 
2710aec49c8SLang Hames   cantFail(
2720aec49c8SLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar})));
2730aec49c8SLang Hames 
2740aec49c8SLang Hames   auto JDResourceKey = JD.getDefaultResourceTracker()->getKeyUnsafe();
2750aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
2760aec49c8SLang Hames       << "Expected exactly one entry (for JD's ResourceKey)";
2770aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().count(JDResourceKey), 1U)
2780aec49c8SLang Hames       << "Expected an entry for JD's ResourceKey";
2790aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources()[JDResourceKey], 2U)
2800aec49c8SLang Hames       << "Expected value of 2 for JD's ResourceKey "
2810aec49c8SLang Hames          "(+1 for each of Foo and Bar)";
2820aec49c8SLang Hames 
2830aec49c8SLang Hames   cantFail(JD.clear());
2840aec49c8SLang Hames 
2850aec49c8SLang Hames   EXPECT_TRUE(SRM.getRecordedResources().empty())
2860aec49c8SLang Hames       << "Expected no resources recorded after clear";
2870aec49c8SLang Hames }
2880aec49c8SLang Hames 
TEST_F(ResourceTrackerStandardTest,BasicDefineAndExplicitTransferBeforeMaterializing)2890aec49c8SLang Hames TEST_F(ResourceTrackerStandardTest,
2900aec49c8SLang Hames        BasicDefineAndExplicitTransferBeforeMaterializing) {
2910aec49c8SLang Hames 
2920aec49c8SLang Hames   bool ResourceManagerGotTransfer = false;
293d54c4e38SLang Hames   SimpleResourceManager<> SRM(ES);
294bf6d7ca9SLang Hames   SRM.setHandleTransfer(
295bf6d7ca9SLang Hames       [&](JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {
2960aec49c8SLang Hames         ResourceManagerGotTransfer = true;
2970aec49c8SLang Hames         auto &RR = SRM.getRecordedResources();
2980aec49c8SLang Hames         EXPECT_EQ(RR.size(), 0U) << "Expected no resources recorded yet";
2990aec49c8SLang Hames       });
3000aec49c8SLang Hames 
3018b1771bdSLang Hames   auto MakeMU = [&](SymbolStringPtr Name, ExecutorSymbolDef Sym) {
3020aec49c8SLang Hames     return std::make_unique<SimpleMaterializationUnit>(
3030aec49c8SLang Hames         SymbolFlagsMap({{Name, Sym.getFlags()}}),
3040aec49c8SLang Hames         [=, &SRM](std::unique_ptr<MaterializationResponsibility> R) {
3050aec49c8SLang Hames           cantFail(R->withResourceKeyDo(
3060aec49c8SLang Hames               [&](ResourceKey K) { SRM.recordResource(K); }));
3070aec49c8SLang Hames           cantFail(R->notifyResolved({{Name, Sym}}));
308*ebe8733aSlhames           cantFail(R->notifyEmitted({}));
3090aec49c8SLang Hames         });
3100aec49c8SLang Hames   };
3110aec49c8SLang Hames 
3120aec49c8SLang Hames   auto FooRT = JD.createResourceTracker();
3130aec49c8SLang Hames   cantFail(JD.define(MakeMU(Foo, FooSym), FooRT));
3140aec49c8SLang Hames 
3150aec49c8SLang Hames   auto BarRT = JD.createResourceTracker();
3160aec49c8SLang Hames   cantFail(JD.define(MakeMU(Bar, BarSym), BarRT));
3170aec49c8SLang Hames 
3180aec49c8SLang Hames   BarRT->transferTo(*FooRT);
3190aec49c8SLang Hames 
3200aec49c8SLang Hames   EXPECT_TRUE(ResourceManagerGotTransfer)
3210aec49c8SLang Hames       << "ResourceManager did not receive transfer";
3220aec49c8SLang Hames   EXPECT_TRUE(BarRT->isDefunct()) << "BarRT should now be defunct";
3230aec49c8SLang Hames 
3240aec49c8SLang Hames   cantFail(
3250aec49c8SLang Hames       ES.lookup(makeJITDylibSearchOrder({&JD}), SymbolLookupSet({Foo, Bar})));
3260aec49c8SLang Hames 
3270aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
3280aec49c8SLang Hames       << "Expected exactly one entry (for FooRT's Key)";
3290aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().count(FooRT->getKeyUnsafe()), 1U)
3300aec49c8SLang Hames       << "Expected an entry for FooRT's ResourceKey";
3310aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().count(BarRT->getKeyUnsafe()), 0U)
3320aec49c8SLang Hames       << "Expected no entry for BarRT's ResourceKey";
3330aec49c8SLang Hames 
3340aec49c8SLang Hames   // We need to explicitly destroy FooRT or its resources will be implicitly
3350aec49c8SLang Hames   // transferred to the default tracker triggering a second call to our
3360aec49c8SLang Hames   // transfer function above (which expects only one call).
3370aec49c8SLang Hames   cantFail(FooRT->remove());
3380aec49c8SLang Hames }
3390aec49c8SLang Hames 
TEST_F(ResourceTrackerStandardTest,BasicDefineAndExplicitTransferAfterMaterializing)3400aec49c8SLang Hames TEST_F(ResourceTrackerStandardTest,
3410aec49c8SLang Hames        BasicDefineAndExplicitTransferAfterMaterializing) {
3420aec49c8SLang Hames 
3430aec49c8SLang Hames   bool ResourceManagerGotTransfer = false;
344d54c4e38SLang Hames   SimpleResourceManager<> SRM(ES);
345bf6d7ca9SLang Hames   SRM.setHandleTransfer(
346bf6d7ca9SLang Hames       [&](JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {
3470aec49c8SLang Hames         ResourceManagerGotTransfer = true;
348bf6d7ca9SLang Hames         SRM.transferResources(JD, DstKey, SrcKey);
3490aec49c8SLang Hames       });
3500aec49c8SLang Hames 
3518b1771bdSLang Hames   auto MakeMU = [&](SymbolStringPtr Name, ExecutorSymbolDef Sym) {
3520aec49c8SLang Hames     return std::make_unique<SimpleMaterializationUnit>(
3530aec49c8SLang Hames         SymbolFlagsMap({{Name, Sym.getFlags()}}),
3540aec49c8SLang Hames         [=, &SRM](std::unique_ptr<MaterializationResponsibility> R) {
3550aec49c8SLang Hames           cantFail(R->withResourceKeyDo(
3560aec49c8SLang Hames               [&](ResourceKey K) { SRM.recordResource(K, 1); }));
3570aec49c8SLang Hames           cantFail(R->notifyResolved({{Name, Sym}}));
358*ebe8733aSlhames           cantFail(R->notifyEmitted({}));
3590aec49c8SLang Hames         });
3600aec49c8SLang Hames   };
3610aec49c8SLang Hames 
3620aec49c8SLang Hames   auto FooRT = JD.createResourceTracker();
3630aec49c8SLang Hames   cantFail(JD.define(MakeMU(Foo, FooSym), FooRT));
3640aec49c8SLang Hames 
3650aec49c8SLang Hames   auto BarRT = JD.createResourceTracker();
3660aec49c8SLang Hames   cantFail(JD.define(MakeMU(Bar, BarSym), BarRT));
3670aec49c8SLang Hames 
3680aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().size(), 0U)
3690aec49c8SLang Hames       << "Expected no recorded resources yet";
3700aec49c8SLang Hames 
3710aec49c8SLang Hames   cantFail(
3720aec49c8SLang Hames       ES.lookup(makeJITDylibSearchOrder({&JD}), SymbolLookupSet({Foo, Bar})));
3730aec49c8SLang Hames 
3740aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().size(), 2U)
3750aec49c8SLang Hames       << "Expected recorded resources for both Foo and Bar";
3760aec49c8SLang Hames 
3770aec49c8SLang Hames   BarRT->transferTo(*FooRT);
3780aec49c8SLang Hames 
3790aec49c8SLang Hames   EXPECT_TRUE(ResourceManagerGotTransfer)
3800aec49c8SLang Hames       << "ResourceManager did not receive transfer";
3810aec49c8SLang Hames   EXPECT_TRUE(BarRT->isDefunct()) << "BarRT should now be defunct";
3820aec49c8SLang Hames 
3830aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
3840aec49c8SLang Hames       << "Expected recorded resources for Foo only";
3850aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().count(FooRT->getKeyUnsafe()), 1U)
3860aec49c8SLang Hames       << "Expected recorded resources for Foo";
3870aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources()[FooRT->getKeyUnsafe()], 2U)
3880aec49c8SLang Hames       << "Expected resources value for for Foo to be '2'";
3890aec49c8SLang Hames }
3900aec49c8SLang Hames 
TEST_F(ResourceTrackerStandardTest,BasicDefineAndExplicitTransferWhileMaterializing)3910aec49c8SLang Hames TEST_F(ResourceTrackerStandardTest,
3920aec49c8SLang Hames        BasicDefineAndExplicitTransferWhileMaterializing) {
3930aec49c8SLang Hames 
3940aec49c8SLang Hames   bool ResourceManagerGotTransfer = false;
395d54c4e38SLang Hames   SimpleResourceManager<> SRM(ES);
396bf6d7ca9SLang Hames   SRM.setHandleTransfer(
397bf6d7ca9SLang Hames       [&](JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {
3980aec49c8SLang Hames         ResourceManagerGotTransfer = true;
399bf6d7ca9SLang Hames         SRM.transferResources(JD, DstKey, SrcKey);
4000aec49c8SLang Hames       });
4010aec49c8SLang Hames 
4020aec49c8SLang Hames   auto FooRT = JD.createResourceTracker();
4030aec49c8SLang Hames   std::unique_ptr<MaterializationResponsibility> FooMR;
4040aec49c8SLang Hames   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
4050aec49c8SLang Hames                          SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
4060aec49c8SLang Hames                          [&](std::unique_ptr<MaterializationResponsibility> R) {
4070aec49c8SLang Hames                            FooMR = std::move(R);
4080aec49c8SLang Hames                          }),
4090aec49c8SLang Hames                      FooRT));
4100aec49c8SLang Hames 
4110aec49c8SLang Hames   auto BarRT = JD.createResourceTracker();
4120aec49c8SLang Hames 
4130aec49c8SLang Hames   ES.lookup(
4140aec49c8SLang Hames       LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
4150aec49c8SLang Hames       SymbolState::Ready,
4160aec49c8SLang Hames       [](Expected<SymbolMap> Result) { cantFail(Result.takeError()); },
4170aec49c8SLang Hames       NoDependenciesToRegister);
4180aec49c8SLang Hames 
4190aec49c8SLang Hames   cantFail(FooMR->withResourceKeyDo([&](ResourceKey K) {
4200aec49c8SLang Hames     EXPECT_EQ(FooRT->getKeyUnsafe(), K)
4210aec49c8SLang Hames         << "Expected FooRT's ResourceKey for Foo here";
4220aec49c8SLang Hames     SRM.recordResource(K, 1);
4230aec49c8SLang Hames   }));
4240aec49c8SLang Hames 
4250aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
4260aec49c8SLang Hames       << "Expected one recorded resource here";
4270aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources()[FooRT->getKeyUnsafe()], 1U)
4280aec49c8SLang Hames       << "Expected Resource value for FooRT to be '1' here";
4290aec49c8SLang Hames 
4300aec49c8SLang Hames   FooRT->transferTo(*BarRT);
4310aec49c8SLang Hames 
4320aec49c8SLang Hames   EXPECT_TRUE(ResourceManagerGotTransfer)
4330aec49c8SLang Hames       << "Expected resource manager to receive handleTransferResources call";
4340aec49c8SLang Hames 
4350aec49c8SLang Hames   cantFail(FooMR->withResourceKeyDo([&](ResourceKey K) {
4360aec49c8SLang Hames     EXPECT_EQ(BarRT->getKeyUnsafe(), K)
4370aec49c8SLang Hames         << "Expected BarRT's ResourceKey for Foo here";
4380aec49c8SLang Hames     SRM.recordResource(K, 1);
4390aec49c8SLang Hames   }));
4400aec49c8SLang Hames 
4410aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().size(), 1U)
4420aec49c8SLang Hames       << "Expected one recorded resource here";
4430aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources().count(BarRT->getKeyUnsafe()), 1U)
4440aec49c8SLang Hames       << "Expected RecordedResources to contain an entry for BarRT";
4450aec49c8SLang Hames   EXPECT_EQ(SRM.getRecordedResources()[BarRT->getKeyUnsafe()], 2U)
4460aec49c8SLang Hames       << "Expected Resource value for BarRT to be '2' here";
4470aec49c8SLang Hames 
4480aec49c8SLang Hames   cantFail(FooMR->notifyResolved({{Foo, FooSym}}));
449*ebe8733aSlhames   cantFail(FooMR->notifyEmitted({}));
4500aec49c8SLang Hames }
4510aec49c8SLang Hames 
4520aec49c8SLang Hames } // namespace
453