//===----- 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 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 A; }; MockJITLinkMemoryManager() { Allocate = [this](const llvm::jitlink::JITLinkDylib *JD, llvm::jitlink::LinkGraph &G) { return defaultAllocate(JD, G); }; Deallocate = [this](std::vector Allocs) { return defaultDeallocate(std::move(Allocs)); }; Abandon = [this](std::unique_ptr A) { return defaultAbandon(std::move(A)); }; Finalize = [this](std::unique_ptr 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(*this, std::move(*A))); } void deallocate(std::vector Allocs, OnDeallocatedFunction OnDeallocated) override { OnDeallocated(Deallocate(std::move(Allocs))); } using JITLinkMemoryManager::allocate; using JITLinkMemoryManager::deallocate; llvm::Expected> defaultAllocate(const llvm::jitlink::JITLinkDylib *JD, llvm::jitlink::LinkGraph &G) { return std::make_unique(JD, G); } llvm::Error defaultDeallocate(std::vector Allocs) { for (auto &A : Allocs) delete A.release().toPtr(); return llvm::Error::success(); } llvm::Error defaultAbandon(std::unique_ptr A) { return llvm::Error::success(); } llvm::Expected defaultFinalize(std::unique_ptr A) { return FinalizedAlloc(llvm::orc::ExecutorAddr::fromPtr(A.release())); } llvm::unique_function>( const llvm::jitlink::JITLinkDylib *, llvm::jitlink::LinkGraph &)> Allocate; llvm::unique_function)> Deallocate; llvm::unique_function)> Abandon; llvm::unique_function(std::unique_ptr)> Finalize; }; void lookupResolveEverythingToNull( const llvm::jitlink::JITLinkContext::LookupMap &Symbols, std::unique_ptr LC); void lookupErrorOut( const llvm::jitlink::JITLinkContext::LookupMap &Symbols, std::unique_ptr LC); class MockJITLinkContext : public llvm::jitlink::JITLinkContext { public: using HandleFailedFn = llvm::unique_function; MockJITLinkContext(std::unique_ptr 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 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 MJMM; HandleFailedFn HandleFailed; llvm::unique_function)> Lookup; llvm::unique_function NotifyResolved; llvm::unique_function NotifyFinalized; mutable llvm::unique_function MarkLivePass; llvm::unique_function ModifyPassConfig; std::vector FinalizedAllocs; }; std::unique_ptr makeMockContext( llvm::unique_function HandleFailed, llvm::unique_function SetupMemMgr, llvm::unique_function 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