-
Notifications
You must be signed in to change notification settings - Fork 10.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[JITLink] Don't try to abandon non-existent allocations.
If JITLinkGeneric::linkPhase2 receives an Error rather than an InFlightAlloc then we need to call JITLinkContext::notifyFailed, rather than calling abandonAllocAndBailOut -- the latter asserts that there is an allocation to abandon, and this was turning allocation errors into assertion failures in debug mode.
- Loading branch information
Showing
5 changed files
with
349 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
//===--------- JITLinkMocks.cpp - Mock APIs for JITLink unit tests --------===// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "JITLinkMocks.h" | ||
#include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" | ||
|
||
#include "llvm/Testing/Support/Error.h" | ||
#include "gtest/gtest.h" | ||
|
||
using namespace llvm; | ||
using namespace llvm::orc; | ||
using namespace llvm::jitlink; | ||
|
||
void lookupResolveEverythingToNull( | ||
const llvm::jitlink::JITLinkContext::LookupMap &Symbols, | ||
std::unique_ptr<llvm::jitlink::JITLinkAsyncLookupContinuation> LC) { | ||
llvm::orc::ExecutorAddr Null; | ||
llvm::jitlink::AsyncLookupResult Result; | ||
for (auto &KV : Symbols) | ||
Result[KV.first] = {Null, llvm::JITSymbolFlags::Exported}; | ||
LC->run(std::move(Result)); | ||
} | ||
|
||
void lookupErrorOut( | ||
const llvm::jitlink::JITLinkContext::LookupMap &Symbols, | ||
std::unique_ptr<llvm::jitlink::JITLinkAsyncLookupContinuation> LC) { | ||
LC->run(llvm::make_error<llvm::StringError>("Lookup failed", | ||
llvm::inconvertibleErrorCode())); | ||
} | ||
|
||
std::unique_ptr<MockJITLinkContext> makeMockContext( | ||
llvm::unique_function<void(llvm::Error)> HandleFailed, | ||
llvm::unique_function<void(MockJITLinkMemoryManager &)> SetupMemMgr, | ||
llvm::unique_function<void(MockJITLinkContext &)> SetupContext) { | ||
auto MemMgr = std::make_unique<MockJITLinkMemoryManager>(); | ||
SetupMemMgr(*MemMgr); | ||
auto Ctx = std::make_unique<MockJITLinkContext>(std::move(MemMgr), | ||
std::move(HandleFailed)); | ||
SetupContext(*Ctx); | ||
return Ctx; | ||
} | ||
|
||
void defaultMemMgrSetup(MockJITLinkMemoryManager &) {} | ||
void defaultCtxSetup(MockJITLinkContext &) {} | ||
|
||
TEST(JITLinkMocks, SmokeTest) { | ||
// Check that the testing infrastructure defaults can "link" a graph | ||
// successfully. | ||
auto G = std::make_unique<LinkGraph>("foo", Triple("x86_64-apple-darwin"), 8, | ||
support::little, getGenericEdgeKindName); | ||
|
||
ArrayRef<char> Content = "hello, world!"; | ||
auto &Sec = | ||
G->createSection("__data", orc::MemProt::Read | orc::MemProt::Write); | ||
orc::ExecutorAddr B1Addr(0x1000); | ||
auto &B = G->createContentBlock(Sec, Content, B1Addr, 8, 0); | ||
G->addDefinedSymbol(B, 4, "S", 4, Linkage::Strong, Scope::Default, false, | ||
false); | ||
|
||
Error Err = Error::success(); | ||
auto Ctx = | ||
makeMockContext(JoinErrorsInto(Err), defaultMemMgrSetup, defaultCtxSetup); | ||
|
||
link_MachO_x86_64(std::move(G), std::move(Ctx)); | ||
|
||
EXPECT_THAT_ERROR(std::move(Err), Succeeded()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
//===----- 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 |
46 changes: 46 additions & 0 deletions
46
llvm/unittests/ExecutionEngine/JITLink/MemoryManagerErrorTests.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
//===---- MemoryManagerErrorTests.cpp - Test memory manager error paths ---===// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "JITLinkMocks.h" | ||
#include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" | ||
|
||
#include "llvm/Testing/Support/Error.h" | ||
#include "gtest/gtest.h" | ||
|
||
using namespace llvm; | ||
using namespace llvm::orc; | ||
using namespace llvm::jitlink; | ||
|
||
TEST(MemoryManagerErrorTest, ErrorOnFirstAllocate) { | ||
// Check that we can get addresses for blocks, symbols, and edges. | ||
auto G = std::make_unique<LinkGraph>("foo", Triple("x86_64-apple-darwin"), 8, | ||
support::little, getGenericEdgeKindName); | ||
|
||
ArrayRef<char> Content = "hello, world!"; | ||
auto &Sec = | ||
G->createSection("__data", orc::MemProt::Read | orc::MemProt::Write); | ||
orc::ExecutorAddr B1Addr(0x1000); | ||
auto &B = G->createContentBlock(Sec, Content, B1Addr, 8, 0); | ||
G->addDefinedSymbol(B, 4, "S", 4, Linkage::Strong, Scope::Default, false, | ||
false); | ||
|
||
Error Err = Error::success(); | ||
auto Ctx = makeMockContext( | ||
JoinErrorsInto(Err), | ||
[](MockJITLinkMemoryManager &MemMgr) { | ||
MemMgr.Allocate = [](const JITLinkDylib *JD, LinkGraph &G) { | ||
return make_error<StringError>("Failed to allocate", | ||
inconvertibleErrorCode()); | ||
}; | ||
}, | ||
defaultCtxSetup); | ||
|
||
link_MachO_x86_64(std::move(G), std::move(Ctx)); | ||
|
||
EXPECT_THAT_ERROR(std::move(Err), Failed()); | ||
} |