Skip to content

Commit dad60f8

Browse files
committed
[ORC] Add EPCGenericJITLinkMemoryManager: memory management via EPC calls.
All ExecutorProcessControl subclasses must provide a JITLinkMemoryManager object that can be used to allocate memory in the executor process. The EPCGenericJITLinkMemoryManager class provides an off-the-shelf JITLinkMemoryManager implementation for JITs that do not need (or cannot provide) a specialized JITLinkMemoryManager implementation. This simplifies the process of creating new ExecutorProcessControl implementations.
1 parent f38cfda commit dad60f8

File tree

8 files changed

+439
-52
lines changed

8 files changed

+439
-52
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===- EPCGenericJITLinkMemoryManager.h - EPC-based mem manager -*- C++ -*-===//
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+
// Implements JITLinkMemoryManager by making remove calls via
10+
// ExecutorProcessControl::callWrapperAsync.
11+
//
12+
// This simplifies the implementaton of new ExecutorProcessControl instances,
13+
// as this implementation will always work (at the cost of some performance
14+
// overhead for the calls).
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef LLVM_EXECUTIONENGINE_ORC_EPCGENERICJITLINKMEMORYMANAGER_H
19+
#define LLVM_EXECUTIONENGINE_ORC_EPCGENERICJITLINKMEMORYMANAGER_H
20+
21+
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
22+
#include "llvm/ExecutionEngine/Orc/Core.h"
23+
24+
namespace llvm {
25+
namespace orc {
26+
27+
class EPCGenericJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
28+
public:
29+
/// Function addresses for memory access.
30+
struct FuncAddrs {
31+
ExecutorAddress Reserve;
32+
ExecutorAddress Finalize;
33+
ExecutorAddress Deallocate;
34+
};
35+
36+
/// Create an EPCGenericJITLinkMemoryManager instance from a given set of
37+
/// function addrs.
38+
EPCGenericJITLinkMemoryManager(ExecutorProcessControl &EPC, FuncAddrs FAs)
39+
: EPC(EPC), FAs(FAs) {}
40+
41+
/// Create using the standard memory access function names from the ORC
42+
/// runtime.
43+
static Expected<std::unique_ptr<EPCGenericJITLinkMemoryManager>>
44+
CreateUsingOrcRTFuncs(ExecutionSession &ES, JITDylib &OrcRuntimeJD);
45+
46+
Expected<std::unique_ptr<Allocation>>
47+
allocate(const jitlink::JITLinkDylib *JD,
48+
const SegmentsRequestMap &Request) override;
49+
50+
private:
51+
class Alloc;
52+
53+
ExecutorProcessControl &EPC;
54+
FuncAddrs FAs;
55+
};
56+
57+
} // end namespace orc
58+
} // end namespace llvm
59+
60+
#endif // LLVM_EXECUTIONENGINE_ORC_EPCGENERICJITLINKMEMORYMANAGER_H

llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class OrcRPCEPCJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
8080
auto &HA = KV.second;
8181
auto &TA = TargetAllocs[KV.first];
8282
BufferWrites.push_back({TA.Address, StringRef(HA.Mem.get(), HA.Size)});
83-
FMR.push_back({orcrpctpc::toWireProtectionFlags(
83+
FMR.push_back({tpctypes::toWireProtectionFlags(
8484
static_cast<sys::Memory::ProtectionFlags>(KV.first)),
8585
TA.Address, TA.AllocatedSize});
8686
}
@@ -92,9 +92,7 @@ class OrcRPCEPCJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
9292
auto Prot = FMRI->Prot;
9393
++FMRI;
9494
dbgs() << " Writing " << formatv("{0:x16}", B.Buffer.size())
95-
<< " bytes to " << ((Prot & orcrpctpc::WPF_Read) ? 'R' : '-')
96-
<< ((Prot & orcrpctpc::WPF_Write) ? 'W' : '-')
97-
<< ((Prot & orcrpctpc::WPF_Exec) ? 'X' : '-')
95+
<< " bytes to " << tpctypes::getWireProtectionFlagsStr(Prot)
9896
<< " segment: local " << (const void *)B.Buffer.data()
9997
<< " -> target " << formatv("{0:x16}", B.Address) << "\n";
10098
}
@@ -132,7 +130,7 @@ class OrcRPCEPCJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
132130
Error deallocate() override {
133131
orcrpctpc::ReleaseOrFinalizeMemRequest RMR;
134132
for (auto &KV : TargetAllocs)
135-
RMR.push_back({orcrpctpc::toWireProtectionFlags(
133+
RMR.push_back({tpctypes::toWireProtectionFlags(
136134
static_cast<sys::Memory::ProtectionFlags>(KV.first)),
137135
KV.second.Address, KV.second.AllocatedSize});
138136
TargetAllocs.clear();
@@ -158,7 +156,7 @@ class OrcRPCEPCJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
158156
assert(KV.second.getContentSize() <= std::numeric_limits<size_t>::max() &&
159157
"Content size is out-of-range for host");
160158

161-
RMR.push_back({orcrpctpc::toWireProtectionFlags(
159+
RMR.push_back({tpctypes::toWireProtectionFlags(
162160
static_cast<sys::Memory::ProtectionFlags>(KV.first)),
163161
KV.second.getContentSize() + KV.second.getZeroFillSize(),
164162
KV.second.getAlignment()});
@@ -196,7 +194,7 @@ class OrcRPCEPCJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
196194

197195
TargetAllocMap TargetAllocs;
198196
for (auto &E : *TmpTargetAllocs)
199-
TargetAllocs[orcrpctpc::fromWireProtectionFlags(E.Prot)] = {
197+
TargetAllocs[tpctypes::fromWireProtectionFlags(E.Prot)] = {
200198
E.Address, E.AllocatedSize};
201199

202200
DEBUG_WITH_TYPE("orc", {

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

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,66 @@
1717
#include "llvm/ADT/ArrayRef.h"
1818
#include "llvm/ADT/StringRef.h"
1919
#include "llvm/ExecutionEngine/JITSymbol.h"
20+
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
2021
#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
22+
#include "llvm/Support/Memory.h"
2123

2224
#include <vector>
2325

2426
namespace llvm {
2527
namespace orc {
2628
namespace tpctypes {
2729

30+
enum WireProtectionFlags : uint8_t {
31+
WPF_None = 0,
32+
WPF_Read = 1U << 0,
33+
WPF_Write = 1U << 1,
34+
WPF_Exec = 1U << 2,
35+
LLVM_MARK_AS_BITMASK_ENUM(WPF_Exec)
36+
};
37+
38+
/// Convert from sys::Memory::ProtectionFlags
39+
inline WireProtectionFlags
40+
toWireProtectionFlags(sys::Memory::ProtectionFlags PF) {
41+
WireProtectionFlags WPF = WPF_None;
42+
if (PF & sys::Memory::MF_READ)
43+
WPF |= WPF_Read;
44+
if (PF & sys::Memory::MF_WRITE)
45+
WPF |= WPF_Write;
46+
if (PF & sys::Memory::MF_EXEC)
47+
WPF |= WPF_Exec;
48+
return WPF;
49+
}
50+
51+
inline sys::Memory::ProtectionFlags
52+
fromWireProtectionFlags(WireProtectionFlags WPF) {
53+
int PF = 0;
54+
if (WPF & WPF_Read)
55+
PF |= sys::Memory::MF_READ;
56+
if (WPF & WPF_Write)
57+
PF |= sys::Memory::MF_WRITE;
58+
if (WPF & WPF_Exec)
59+
PF |= sys::Memory::MF_EXEC;
60+
return static_cast<sys::Memory::ProtectionFlags>(PF);
61+
}
62+
63+
inline std::string getWireProtectionFlagsStr(WireProtectionFlags WPF) {
64+
std::string Result;
65+
Result += (WPF & WPF_Read) ? 'R' : '-';
66+
Result += (WPF & WPF_Write) ? 'W' : '-';
67+
Result += (WPF & WPF_Exec) ? 'X' : '-';
68+
return Result;
69+
}
70+
71+
struct SegFinalizeRequest {
72+
WireProtectionFlags Prot;
73+
ExecutorAddress Addr;
74+
uint64_t Size;
75+
ArrayRef<char> Content;
76+
};
77+
78+
using FinalizeRequest = std::vector<SegFinalizeRequest>;
79+
2880
template <typename T> struct UIntWrite {
2981
UIntWrite() = default;
3082
UIntWrite(JITTargetAddress Address, T Value)
@@ -66,6 +118,14 @@ using LookupResult = std::vector<JITTargetAddress>;
66118

67119
namespace shared {
68120

121+
class SPSMemoryProtectionFlags {};
122+
123+
using SPSSegFinalizeRequest =
124+
SPSTuple<SPSMemoryProtectionFlags, SPSExecutorAddress, uint64_t,
125+
SPSSequence<char>>;
126+
127+
using SPSFinalizeRequest = SPSSequence<SPSSegFinalizeRequest>;
128+
69129
template <typename T>
70130
using SPSMemoryAccessUIntWrite = SPSTuple<SPSExecutorAddress, T>;
71131

@@ -77,6 +137,50 @@ using SPSMemoryAccessUInt64Write = SPSMemoryAccessUIntWrite<uint64_t>;
77137
using SPSMemoryAccessBufferWrite =
78138
SPSTuple<SPSExecutorAddress, SPSSequence<char>>;
79139

140+
template <>
141+
class SPSSerializationTraits<SPSMemoryProtectionFlags,
142+
tpctypes::WireProtectionFlags> {
143+
public:
144+
static size_t size(const tpctypes::WireProtectionFlags &WPF) {
145+
return SPSArgList<uint8_t>::size(static_cast<uint8_t>(WPF));
146+
}
147+
148+
static bool serialize(SPSOutputBuffer &OB,
149+
const tpctypes::WireProtectionFlags &WPF) {
150+
return SPSArgList<uint8_t>::serialize(OB, static_cast<uint8_t>(WPF));
151+
}
152+
153+
static bool deserialize(SPSInputBuffer &IB,
154+
tpctypes::WireProtectionFlags &WPF) {
155+
uint8_t Val;
156+
if (!SPSArgList<uint8_t>::deserialize(IB, Val))
157+
return false;
158+
WPF = static_cast<tpctypes::WireProtectionFlags>(Val);
159+
return true;
160+
}
161+
};
162+
163+
template <>
164+
class SPSSerializationTraits<SPSSegFinalizeRequest,
165+
tpctypes::SegFinalizeRequest> {
166+
using SFRAL = SPSSegFinalizeRequest::AsArgList;
167+
168+
public:
169+
static size_t size(const tpctypes::SegFinalizeRequest &SFR) {
170+
return SFRAL::size(SFR.Prot, SFR.Addr, SFR.Size, SFR.Content);
171+
}
172+
173+
static bool serialize(SPSOutputBuffer &OB,
174+
const tpctypes::SegFinalizeRequest &SFR) {
175+
return SFRAL::serialize(OB, SFR.Prot, SFR.Addr, SFR.Size, SFR.Content);
176+
}
177+
178+
static bool deserialize(SPSInputBuffer &IB,
179+
tpctypes::SegFinalizeRequest &SFR) {
180+
return SFRAL::deserialize(IB, SFR.Prot, SFR.Addr, SFR.Size, SFR.Content);
181+
}
182+
};
183+
80184
template <typename T>
81185
class SPSSerializationTraits<SPSMemoryAccessUIntWrite<T>,
82186
tpctypes::UIntWrite<T>> {
@@ -118,6 +222,10 @@ class SPSSerializationTraits<SPSMemoryAccessBufferWrite,
118222
}
119223
};
120224

225+
using SPSOrcTargetProcessAllocate = SPSExpected<SPSExecutorAddress>(uint64_t);
226+
using SPSOrcTargetProcessFinalize = SPSError(SPSFinalizeRequest);
227+
using SPSOrcTargetProcessDeallocate = SPSError(SPSExecutorAddress, uint64_t);
228+
121229
} // end namespace shared
122230
} // end namespace orc
123231
} // end namespace llvm

llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -33,64 +33,31 @@ namespace orc {
3333

3434
namespace orcrpctpc {
3535

36-
enum WireProtectionFlags : uint8_t {
37-
WPF_None = 0,
38-
WPF_Read = 1U << 0,
39-
WPF_Write = 1U << 1,
40-
WPF_Exec = 1U << 2,
41-
LLVM_MARK_AS_BITMASK_ENUM(WPF_Exec)
42-
};
43-
4436
struct ExecutorProcessInfo {
4537
std::string Triple;
4638
unsigned PageSize;
4739
JITTargetAddress DispatchFuncAddr;
4840
JITTargetAddress DispatchCtxAddr;
4941
};
5042

51-
/// Convert from sys::Memory::ProtectionFlags
52-
inline WireProtectionFlags
53-
toWireProtectionFlags(sys::Memory::ProtectionFlags PF) {
54-
WireProtectionFlags WPF = WPF_None;
55-
if (PF & sys::Memory::MF_READ)
56-
WPF |= WPF_Read;
57-
if (PF & sys::Memory::MF_WRITE)
58-
WPF |= WPF_Write;
59-
if (PF & sys::Memory::MF_EXEC)
60-
WPF |= WPF_Exec;
61-
return WPF;
62-
}
63-
64-
inline sys::Memory::ProtectionFlags
65-
fromWireProtectionFlags(WireProtectionFlags WPF) {
66-
int PF = 0;
67-
if (WPF & WPF_Read)
68-
PF |= sys::Memory::MF_READ;
69-
if (WPF & WPF_Write)
70-
PF |= sys::Memory::MF_WRITE;
71-
if (WPF & WPF_Exec)
72-
PF |= sys::Memory::MF_EXEC;
73-
return static_cast<sys::Memory::ProtectionFlags>(PF);
74-
}
75-
7643
struct ReserveMemRequestElement {
77-
WireProtectionFlags Prot = WPF_None;
44+
tpctypes::WireProtectionFlags Prot = tpctypes::WPF_None;
7845
uint64_t Size = 0;
7946
uint64_t Alignment = 0;
8047
};
8148

8249
using ReserveMemRequest = std::vector<ReserveMemRequestElement>;
8350

8451
struct ReserveMemResultElement {
85-
WireProtectionFlags Prot = WPF_None;
52+
tpctypes::WireProtectionFlags Prot = tpctypes::WPF_None;
8653
JITTargetAddress Address = 0;
8754
uint64_t AllocatedSize = 0;
8855
};
8956

9057
using ReserveMemResult = std::vector<ReserveMemResultElement>;
9158

9259
struct ReleaseOrFinalizeMemRequestElement {
93-
WireProtectionFlags Prot = WPF_None;
60+
tpctypes::WireProtectionFlags Prot = tpctypes::WPF_None;
9461
JITTargetAddress Address = 0;
9562
uint64_t Size = 0;
9663
};
@@ -492,14 +459,6 @@ template <typename RPCEndpointT> class OrcRPCTPCServer {
492459
*jitTargetAddressToPointer<ValueT *>(W.Address) = W.Value;
493460
}
494461

495-
std::string getProtStr(orcrpctpc::WireProtectionFlags WPF) {
496-
std::string Result;
497-
Result += (WPF & orcrpctpc::WPF_Read) ? 'R' : '-';
498-
Result += (WPF & orcrpctpc::WPF_Write) ? 'W' : '-';
499-
Result += (WPF & orcrpctpc::WPF_Exec) ? 'X' : '-';
500-
return Result;
501-
}
502-
503462
static void handleWriteBuffer(const std::vector<tpctypes::BufferWrite> &Ws) {
504463
for (auto &W : Ws) {
505464
memcpy(jitTargetAddressToPointer<char *>(W.Address), W.Buffer.data(),
@@ -554,7 +513,7 @@ template <typename RPCEndpointT> class OrcRPCTPCServer {
554513
for (const auto &E : FMR) {
555514
sys::MemoryBlock MB(jitTargetAddressToPointer<void *>(E.Address), E.Size);
556515

557-
auto PF = orcrpctpc::fromWireProtectionFlags(E.Prot);
516+
auto PF = tpctypes::fromWireProtectionFlags(E.Prot);
558517
if (auto EC =
559518
sys::Memory::protectMappedMemory(MB, static_cast<unsigned>(PF)))
560519
return make_error<StringError>("error protecting memory: " +

llvm/lib/ExecutionEngine/Orc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_llvm_component_library(LLVMOrcJIT
77
EPCDynamicLibrarySearchGenerator.cpp
88
EPCDebugObjectRegistrar.cpp
99
EPCEHFrameRegistrar.cpp
10+
EPCGenericJITLinkMemoryManager.cpp
1011
EPCGenericMemoryAccess.cpp
1112
EPCIndirectionUtils.cpp
1213
ExecutionUtils.cpp

0 commit comments

Comments
 (0)