Skip to content

Commit c0fdc74

Browse files
committed
[ORC] Add helper functions for running finalize / dealloc actions.
runFinalizeActions takes an AllocActions vector and attempts to run its finalize actions. If any finalize action fails then all paired dealloc actions up to the failing pair are run, and the error(s) returned. If all finalize actions succeed then a vector containing the dealloc actions is returned. runDeallocActions takes a vector<WrapperFunctionCall> containing dealloc action calls and runs them all, returning any error(s). These helpers are intended to simplify the implementation of JITLinkMemoryManager::InFlightAlloc::finalize and JITLinkMemoryManager::deallocate overrides by taking care of execution (and potential roll-back) of allocation actions.
1 parent b645bcd commit c0fdc74

File tree

6 files changed

+98
-22
lines changed

6 files changed

+98
-22
lines changed

llvm/include/llvm/ExecutionEngine/Orc/Shared/AllocationActions.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,33 @@ struct AllocActionCallPair {
4343
/// actions will be run in reverse order at deallocation time.
4444
using AllocActions = std::vector<AllocActionCallPair>;
4545

46+
/// Returns the number of deallocaton actions in the given AllocActions array.
47+
///
48+
/// This can be useful if clients want to pre-allocate room for deallocation
49+
/// actions with the rest of their memory.
50+
inline size_t numDeallocActions(const AllocActions &AAs) {
51+
return llvm::count_if(
52+
AAs, [](const AllocActionCallPair &P) { return !!P.Dealloc; });
53+
}
54+
55+
/// Run finalize actions.
56+
///
57+
/// If any finalize action fails then the corresponding dealloc actions will be
58+
/// run in reverse order (not including the deallocation action for the failed
59+
/// finalize action), and the error for the failing action will be returned.
60+
///
61+
/// If all finalize actions succeed then a vector of deallocation actions will
62+
/// be returned. The dealloc actions should be run by calling
63+
/// runDeallocationActions. If this function succeeds then the AA argument will
64+
/// be cleared before the function returns.
65+
Expected<std::vector<WrapperFunctionCall>>
66+
runFinalizeActions(AllocActions &AAs);
67+
68+
/// Run deallocation actions.
69+
/// Dealloc actions will be run in reverse order (from last element of DAs to
70+
/// first).
71+
Error runDeallocActions(ArrayRef<WrapperFunctionCall> DAs);
72+
4673
using SPSAllocActionCallPair =
4774
SPSTuple<SPSWrapperFunctionCall, SPSWrapperFunctionCall>;
4875

llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ class WrapperFunctionCall {
660660
explicit operator bool() const { return !!FnAddr; }
661661

662662
/// Run call returning raw WrapperFunctionResult.
663-
shared::WrapperFunctionResult run() {
663+
shared::WrapperFunctionResult run() const {
664664
using FnTy =
665665
shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
666666
return shared::WrapperFunctionResult(
@@ -670,7 +670,7 @@ class WrapperFunctionCall {
670670
/// Run call and deserialize result using SPS.
671671
template <typename SPSRetT, typename RetT>
672672
std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
673-
runWithSPSRet(RetT &RetVal) {
673+
runWithSPSRet(RetT &RetVal) const {
674674
auto WFR = run();
675675
if (const char *ErrMsg = WFR.getOutOfBandError())
676676
return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
@@ -684,14 +684,15 @@ class WrapperFunctionCall {
684684

685685
/// Overload for SPS functions returning void.
686686
template <typename SPSRetT>
687-
std::enable_if_t<std::is_same<SPSRetT, void>::value, Error> runWithSPSRet() {
687+
std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
688+
runWithSPSRet() const {
688689
shared::SPSEmpty E;
689690
return runWithSPSRet<shared::SPSEmpty>(E);
690691
}
691692

692693
/// Run call and deserialize an SPSError result. SPSError returns and
693694
/// deserialization failures are merged into the returned error.
694-
Error runWithSPSRetErrorMerged() {
695+
Error runWithSPSRetErrorMerged() const {
695696
detail::SPSSerializableError RetErr;
696697
if (auto Err = runWithSPSRet<SPSError>(RetErr))
697698
return Err;

llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -247,19 +247,11 @@ class InProcessMemoryManager::IPInFlightAlloc
247247
}
248248

249249
// Run finalization actions.
250-
// FIXME: Roll back previous successful actions on failure.
251-
std::vector<orc::shared::WrapperFunctionCall> DeallocActions;
252-
DeallocActions.reserve(G.allocActions().size());
253-
for (auto &ActPair : G.allocActions()) {
254-
if (ActPair.Finalize)
255-
if (auto Err = ActPair.Finalize.runWithSPSRetErrorMerged()) {
256-
OnFinalized(std::move(Err));
257-
return;
258-
}
259-
if (ActPair.Dealloc)
260-
DeallocActions.push_back(ActPair.Dealloc);
250+
auto DeallocActions = runFinalizeActions(G.allocActions());
251+
if (!DeallocActions) {
252+
OnFinalized(DeallocActions.takeError());
253+
return;
261254
}
262-
G.allocActions().clear();
263255

264256
// Release the finalize segments slab.
265257
if (auto EC = sys::Memory::releaseMappedMemory(FinalizationSegments)) {
@@ -269,7 +261,7 @@ class InProcessMemoryManager::IPInFlightAlloc
269261

270262
// Continue with finalized allocation.
271263
OnFinalized(MemMgr.createFinalizedAlloc(std::move(StandardSegments),
272-
std::move(DeallocActions)));
264+
std::move(*DeallocActions)));
273265
}
274266

275267
void abandon(OnAbandonedFunction OnAbandoned) override {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===----- AllocationActions.gpp -- JITLink allocation support calls -----===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/ExecutionEngine/Orc/Shared/AllocationActions.h"
10+
11+
namespace llvm {
12+
namespace orc {
13+
namespace shared {
14+
15+
Expected<std::vector<WrapperFunctionCall>>
16+
runFinalizeActions(AllocActions &AAs) {
17+
std::vector<WrapperFunctionCall> DeallocActions;
18+
DeallocActions.reserve(numDeallocActions(AAs));
19+
20+
for (auto &AA : AAs) {
21+
if (AA.Finalize)
22+
if (auto Err = AA.Finalize.runWithSPSRetErrorMerged())
23+
return joinErrors(std::move(Err), runDeallocActions(DeallocActions));
24+
25+
if (AA.Dealloc)
26+
DeallocActions.push_back(std::move(AA.Dealloc));
27+
}
28+
29+
AAs.clear();
30+
return DeallocActions;
31+
}
32+
33+
Error runDeallocActions(ArrayRef<WrapperFunctionCall> DAs) {
34+
Error Err = Error::success();
35+
while (!DAs.empty()) {
36+
Err = joinErrors(std::move(Err), DAs.back().runWithSPSRetErrorMerged());
37+
DAs = DAs.drop_back();
38+
}
39+
return Err;
40+
}
41+
42+
} // namespace shared
43+
} // namespace orc
44+
} // namespace llvm

llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_llvm_component_library(LLVMOrcShared
2+
AllocationActions.cpp
23
OrcError.cpp
34
OrcRTBridge.cpp
45
SimpleRemoteEPCUtils.cpp

llvm/tools/llvm-jitlink/llvm-jitlink.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) {
397397
class JITLinkSlabAllocator final : public JITLinkMemoryManager {
398398
private:
399399
struct FinalizedAllocInfo {
400+
FinalizedAllocInfo(sys::MemoryBlock Mem,
401+
std::vector<shared::WrapperFunctionCall> DeallocActions)
402+
: Mem(Mem), DeallocActions(std::move(DeallocActions)) {}
400403
sys::MemoryBlock Mem;
401404
std::vector<shared::WrapperFunctionCall> DeallocActions;
402405
};
@@ -430,12 +433,20 @@ class JITLinkSlabAllocator final : public JITLinkMemoryManager {
430433
return;
431434
}
432435

433-
// FIXME: Run finalize actions.
434-
assert(BL.graphAllocActions().empty() &&
435-
"Support function calls not supported yet");
436+
auto DeallocActions = runFinalizeActions(BL.graphAllocActions());
437+
if (!DeallocActions) {
438+
OnFinalized(DeallocActions.takeError());
439+
return;
440+
}
441+
442+
if (auto Err = Parent.freeBlock(FinalizeSegs)) {
443+
OnFinalized(
444+
joinErrors(std::move(Err), runDeallocActions(*DeallocActions)));
445+
return;
446+
}
436447

437-
OnFinalized(
438-
FinalizedAlloc(ExecutorAddr::fromPtr(new FinalizedAllocInfo())));
448+
OnFinalized(FinalizedAlloc(ExecutorAddr::fromPtr(
449+
new FinalizedAllocInfo(StandardSegs, std::move(*DeallocActions)))));
439450
}
440451

441452
void abandon(OnAbandonedFunction OnAbandoned) override {

0 commit comments

Comments
 (0)