| //===----- JITLinkMocks.h - Mock APIs for JITLink unit tests ----*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Mock APIs for JITLink unit tests. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_UNITTESTS_EXECUTIONENGINE_JITLINK_JITLINKMOCKS_H |
| #define LLVM_UNITTESTS_EXECUTIONENGINE_JITLINK_JITLINKMOCKS_H |
| |
| #include "llvm/ExecutionEngine/JITLink/JITLink.h" |
| |
| class MockJITLinkMemoryManager : public llvm::jitlink::JITLinkMemoryManager { |
| public: |
| class Alloc { |
| public: |
| virtual ~Alloc() {} |
| }; |
| |
| class SimpleAlloc : public Alloc { |
| public: |
| SimpleAlloc(const llvm::jitlink::JITLinkDylib *JD, |
| llvm::jitlink::LinkGraph &G) { |
| for (auto *B : G.blocks()) |
| (void)B->getMutableContent(G); |
| } |
| }; |
| |
| class MockInFlightAlloc : public InFlightAlloc { |
| public: |
| MockInFlightAlloc(MockJITLinkMemoryManager &MJMM, std::unique_ptr<Alloc> A) |
| : MJMM(MJMM), A(std::move(A)) {} |
| |
| void abandon(OnAbandonedFunction OnAbandoned) override { |
| OnAbandoned(MJMM.Abandon(std::move(A))); |
| } |
| |
| void finalize(OnFinalizedFunction OnFinalized) override { |
| OnFinalized(MJMM.Finalize(std::move(A))); |
| } |
| |
| private: |
| MockJITLinkMemoryManager &MJMM; |
| std::unique_ptr<Alloc> A; |
| }; |
| |
| MockJITLinkMemoryManager() { |
| Allocate = [this](const llvm::jitlink::JITLinkDylib *JD, |
| llvm::jitlink::LinkGraph &G) { |
| return defaultAllocate(JD, G); |
| }; |
| |
| Deallocate = [this](std::vector<FinalizedAlloc> Allocs) { |
| return defaultDeallocate(std::move(Allocs)); |
| }; |
| |
| Abandon = [this](std::unique_ptr<Alloc> A) { |
| return defaultAbandon(std::move(A)); |
| }; |
| |
| Finalize = [this](std::unique_ptr<Alloc> A) { |
| return defaultFinalize(std::move(A)); |
| }; |
| } |
| |
| void allocate(const llvm::jitlink::JITLinkDylib *JD, |
| llvm::jitlink::LinkGraph &G, |
| OnAllocatedFunction OnAllocated) override { |
| auto A = Allocate(JD, G); |
| if (!A) |
| OnAllocated(A.takeError()); |
| else |
| OnAllocated(std::make_unique<MockInFlightAlloc>(*this, std::move(*A))); |
| } |
| |
| void deallocate(std::vector<FinalizedAlloc> Allocs, |
| OnDeallocatedFunction OnDeallocated) override { |
| OnDeallocated(Deallocate(std::move(Allocs))); |
| } |
| |
| using JITLinkMemoryManager::allocate; |
| using JITLinkMemoryManager::deallocate; |
| |
| llvm::Expected<std::unique_ptr<Alloc>> |
| defaultAllocate(const llvm::jitlink::JITLinkDylib *JD, |
| llvm::jitlink::LinkGraph &G) { |
| return std::make_unique<SimpleAlloc>(JD, G); |
| } |
| |
| llvm::Error defaultDeallocate(std::vector<FinalizedAlloc> Allocs) { |
| for (auto &A : Allocs) |
| delete A.release().toPtr<Alloc *>(); |
| return llvm::Error::success(); |
| } |
| |
| llvm::Error defaultAbandon(std::unique_ptr<Alloc> A) { |
| return llvm::Error::success(); |
| } |
| |
| llvm::Expected<FinalizedAlloc> defaultFinalize(std::unique_ptr<Alloc> A) { |
| return FinalizedAlloc(llvm::orc::ExecutorAddr::fromPtr(A.release())); |
| } |
| |
| llvm::unique_function<llvm::Expected<std::unique_ptr<Alloc>>( |
| const llvm::jitlink::JITLinkDylib *, llvm::jitlink::LinkGraph &)> |
| Allocate; |
| llvm::unique_function<llvm::Error(std::vector<FinalizedAlloc>)> Deallocate; |
| llvm::unique_function<llvm::Error(std::unique_ptr<Alloc>)> Abandon; |
| llvm::unique_function<llvm::Expected<FinalizedAlloc>(std::unique_ptr<Alloc>)> |
| Finalize; |
| }; |
| |
| void lookupResolveEverythingToNull( |
| const llvm::jitlink::JITLinkContext::LookupMap &Symbols, |
| std::unique_ptr<llvm::jitlink::JITLinkAsyncLookupContinuation> LC); |
| |
| void lookupErrorOut( |
| const llvm::jitlink::JITLinkContext::LookupMap &Symbols, |
| std::unique_ptr<llvm::jitlink::JITLinkAsyncLookupContinuation> LC); |
| |
| class MockJITLinkContext : public llvm::jitlink::JITLinkContext { |
| public: |
| using HandleFailedFn = llvm::unique_function<void(llvm::Error)>; |
| |
| MockJITLinkContext(std::unique_ptr<MockJITLinkMemoryManager> MJMM, |
| HandleFailedFn HandleFailed) |
| : JITLinkContext(&JD), MJMM(std::move(MJMM)), |
| HandleFailed(std::move(HandleFailed)) {} |
| |
| ~MockJITLinkContext() { |
| if (auto Err = MJMM->deallocate(std::move(FinalizedAllocs))) |
| notifyFailed(std::move(Err)); |
| } |
| |
| llvm::jitlink::JITLinkMemoryManager &getMemoryManager() override { |
| return *MJMM; |
| } |
| |
| void notifyFailed(llvm::Error Err) override { HandleFailed(std::move(Err)); } |
| |
| void lookup(const LookupMap &Symbols, |
| std::unique_ptr<llvm::jitlink::JITLinkAsyncLookupContinuation> LC) |
| override { |
| Lookup(Symbols, std::move(LC)); |
| } |
| |
| llvm::Error notifyResolved(llvm::jitlink::LinkGraph &G) override { |
| return NotifyResolved ? NotifyResolved(G) : llvm::Error::success(); |
| } |
| |
| void notifyFinalized( |
| llvm::jitlink::JITLinkMemoryManager::FinalizedAlloc Alloc) override { |
| if (NotifyFinalized) |
| NotifyFinalized(std::move(Alloc)); |
| else |
| FinalizedAllocs.push_back(std::move(Alloc)); |
| } |
| |
| bool shouldAddDefaultTargetPasses(const llvm::Triple &TT) const override { |
| return true; |
| } |
| |
| llvm::jitlink::LinkGraphPassFunction |
| getMarkLivePass(const llvm::Triple &TT) const override { |
| return MarkLivePass ? llvm::jitlink::LinkGraphPassFunction( |
| [this](llvm::jitlink::LinkGraph &G) { |
| return MarkLivePass(G); |
| }) |
| : llvm::jitlink::LinkGraphPassFunction( |
| [](llvm::jitlink::LinkGraph &G) { |
| return markAllSymbolsLive(G); |
| }); |
| } |
| |
| llvm::Error |
| modifyPassConfig(llvm::jitlink::LinkGraph &G, |
| llvm::jitlink::PassConfiguration &Config) override { |
| if (ModifyPassConfig) |
| return ModifyPassConfig(G, Config); |
| return llvm::Error::success(); |
| } |
| |
| llvm::jitlink::JITLinkDylib JD{"JD"}; |
| std::unique_ptr<MockJITLinkMemoryManager> MJMM; |
| HandleFailedFn HandleFailed; |
| llvm::unique_function<void( |
| const LookupMap &, |
| std::unique_ptr<llvm::jitlink::JITLinkAsyncLookupContinuation>)> |
| Lookup; |
| llvm::unique_function<llvm::Error(llvm::jitlink::LinkGraph &)> NotifyResolved; |
| llvm::unique_function<void( |
| llvm::jitlink::JITLinkMemoryManager::FinalizedAlloc)> |
| NotifyFinalized; |
| mutable llvm::unique_function<llvm::Error(llvm::jitlink::LinkGraph &)> |
| MarkLivePass; |
| llvm::unique_function<llvm::Error(llvm::jitlink::LinkGraph &, |
| llvm::jitlink::PassConfiguration &)> |
| ModifyPassConfig; |
| |
| std::vector<llvm::jitlink::JITLinkMemoryManager::FinalizedAlloc> |
| FinalizedAllocs; |
| }; |
| |
| std::unique_ptr<MockJITLinkContext> makeMockContext( |
| llvm::unique_function<void(llvm::Error)> HandleFailed, |
| llvm::unique_function<void(MockJITLinkMemoryManager &)> SetupMemMgr, |
| llvm::unique_function<void(MockJITLinkContext &)> SetupContext); |
| |
| void defaultMemMgrSetup(MockJITLinkMemoryManager &); |
| void defaultCtxSetup(MockJITLinkContext &); |
| |
| class JoinErrorsInto { |
| public: |
| JoinErrorsInto(llvm::Error &Err) : Err(Err) {} |
| void operator()(llvm::Error E2) { |
| Err = llvm::joinErrors(std::move(Err), std::move(E2)); |
| } |
| |
| private: |
| llvm::Error &Err; |
| }; |
| |
| #endif // LLVM_UNITTESTS_EXECUTIONENGINE_JITLINK_JITLINKMOCKS_H |