Skip to content

Commit 119743d

Browse files
lhamesakadutta
authored andcommitted
[orc-rt] Align SimpleNativeMemoryMap Segment with LLVM type. (llvm#162823)
This commit aims to align SimpleNativeMemoryMap::FinalizeRequest::Segment with llvm::orc::tpctypes::SegFinalizeRequest. This will simplify construction of a new LLVM JITLinkMemoryManager that's capable of using SimpleNativeMemoryMap as a backend.
1 parent d2af0f1 commit 119743d

File tree

3 files changed

+101
-88
lines changed

3 files changed

+101
-88
lines changed

orc-rt/include/orc-rt/SimpleNativeMemoryMap.h

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,10 @@ class SimpleNativeMemoryMap : public ResourceManager {
5454

5555
struct FinalizeRequest {
5656
struct Segment {
57-
enum class ContentType : uint8_t { Uninitialized, ZeroFill, Regular };
58-
59-
Segment() = default;
60-
Segment(void *Address, size_t Size, AllocGroup G, ContentType C)
61-
: Address(Address), Size(Size), G(G), C(C) {}
62-
63-
void *Address = nullptr;
57+
AllocGroup AG;
58+
char *Address = nullptr;
6459
size_t Size = 0;
65-
AllocGroup G;
66-
ContentType C = ContentType::Uninitialized;
67-
char *data() { return reinterpret_cast<char *>(Address); }
68-
size_t size() const { return Size; }
60+
span<const char> Content;
6961
};
7062

7163
std::vector<Segment> Segments;

orc-rt/lib/executor/SimpleNativeMemoryMap.cpp

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,36 +31,22 @@ struct SPSSimpleNativeMemoryMapSegment;
3131
template <>
3232
class SPSSerializationTraits<SPSSimpleNativeMemoryMapSegment,
3333
SimpleNativeMemoryMap::FinalizeRequest::Segment> {
34-
using SPSType = SPSTuple<SPSExecutorAddr, uint64_t, SPSAllocGroup, uint8_t>;
34+
using SPSType =
35+
SPSTuple<SPSAllocGroup, SPSExecutorAddr, uint64_t, SPSSequence<char>>;
3536

3637
public:
3738
static bool deserialize(SPSInputBuffer &IB,
3839
SimpleNativeMemoryMap::FinalizeRequest::Segment &S) {
39-
using ContentType =
40-
SimpleNativeMemoryMap::FinalizeRequest::Segment::ContentType;
41-
40+
AllocGroup AG;
4241
ExecutorAddr Address;
4342
uint64_t Size;
44-
AllocGroup G;
45-
uint8_t C;
46-
if (!SPSType::AsArgList::deserialize(IB, Address, Size, G, C))
43+
span<const char> Content;
44+
if (!SPSType::AsArgList::deserialize(IB, AG, Address, Size, Content))
4745
return false;
48-
if (Size >= std::numeric_limits<size_t>::max())
46+
if (Size > std::numeric_limits<size_t>::max())
4947
return false;
50-
S.Address = Address.toPtr<void *>();
51-
S.Size = Size;
52-
S.G = G;
53-
S.C = static_cast<ContentType>(C);
54-
switch (S.C) {
55-
case ContentType::Uninitialized:
56-
return true;
57-
case ContentType::ZeroFill:
58-
memset(reinterpret_cast<char *>(S.Address), 0, S.Size);
59-
return true;
60-
case ContentType::Regular:
61-
// Read content directly into target address.
62-
return IB.read(reinterpret_cast<char *>(S.Address), S.Size);
63-
}
48+
S = {AG, Address.toPtr<char *>(), static_cast<size_t>(Size), Content};
49+
return true;
6450
}
6551
};
6652

@@ -138,10 +124,31 @@ void SimpleNativeMemoryMap::finalize(OnFinalizeCompleteFn &&OnComplete,
138124
// TODO: Record finalize segments for release.
139125
// std::vector<std::pair<void*, size_t>> FinalizeSegments;
140126

127+
// Check segment validity before proceeding.
141128
for (auto &S : FR.Segments) {
142-
if (auto Err = hostOSMemoryProtect(S.Address, S.Size, S.G.getMemProt()))
129+
130+
if (S.Content.size() > S.Size) {
131+
return OnComplete(make_error<StringError>(
132+
(std::ostringstream()
133+
<< "For segment [" << (void *)S.Address << ".."
134+
<< (void *)(S.Address + S.Size) << "), "
135+
<< " content size (" << std::hex << S.Content.size()
136+
<< ") exceeds segment size (" << S.Size << ")")
137+
.str()));
138+
}
139+
140+
// Copy any requested content.
141+
if (!S.Content.empty())
142+
memcpy(S.Address, S.Content.data(), S.Content.size());
143+
144+
// Zero-fill the rest of the section.
145+
if (size_t ZeroFillSize = S.Size - S.Content.size())
146+
memset(S.Address + S.Content.size(), 0, ZeroFillSize);
147+
148+
if (auto Err = hostOSMemoryProtect(S.Address, S.Size, S.AG.getMemProt()))
143149
return OnComplete(std::move(Err));
144-
switch (S.G.getMemLifetime()) {
150+
151+
switch (S.AG.getMemLifetime()) {
145152
case MemLifetime::Standard:
146153
if (!Base || S.Address < Base)
147154
Base = S.Address;

orc-rt/unittests/SimpleNativeMemoryMapTest.cpp

Lines changed: 67 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -31,49 +31,32 @@ struct SPSSimpleNativeMemoryMapSegment;
3131
struct TestSNMMSegment
3232
: public SimpleNativeMemoryMap::FinalizeRequest::Segment {
3333

34-
enum TestSNMMSegmentContent { Uninitialized, ZeroFill };
35-
36-
TestSNMMSegment(void *Address, AllocGroup G, std::string Content)
37-
: SimpleNativeMemoryMap::FinalizeRequest::Segment(
38-
Address, Content.size(), G, ContentType::Regular),
39-
Content(std::move(Content)) {}
40-
41-
TestSNMMSegment(void *Address, size_t Size, AllocGroup G,
42-
TestSNMMSegmentContent Content)
34+
TestSNMMSegment(AllocGroup AG, char *Address, size_t Size,
35+
std::vector<char> C = {})
4336
: SimpleNativeMemoryMap::FinalizeRequest::Segment(
44-
Address, Size, G,
45-
Content == ZeroFill ? ContentType::ZeroFill
46-
: ContentType::Uninitialized) {}
37+
{AG, Address, Size, {}}),
38+
OwnedContent(std::move(C)) {
39+
this->Content = {OwnedContent.data(), OwnedContent.size()};
40+
}
4741

48-
std::string Content;
42+
std::vector<char> OwnedContent;
4943
};
5044

5145
template <>
5246
class SPSSerializationTraits<SPSSimpleNativeMemoryMapSegment, TestSNMMSegment> {
53-
using SPSType = SPSTuple<SPSExecutorAddr, uint64_t, SPSAllocGroup, uint8_t>;
47+
using SPSType =
48+
SPSTuple<SPSAllocGroup, SPSExecutorAddr, uint64_t, SPSSequence<char>>;
5449

5550
public:
5651
static size_t size(const TestSNMMSegment &S) {
57-
using ContentType =
58-
SimpleNativeMemoryMap::FinalizeRequest::Segment::ContentType;
59-
assert((S.C != ContentType::Regular || S.Size == S.Content.size()));
60-
return SPSType::AsArgList::size(ExecutorAddr::fromPtr(S.Address),
61-
static_cast<uint64_t>(S.Size), S.G,
62-
static_cast<uint8_t>(S.C)) +
63-
(S.C == ContentType::Regular ? S.Size : 0);
52+
return SPSType::AsArgList::size(S.AG, ExecutorAddr::fromPtr(S.Address),
53+
static_cast<uint64_t>(S.Size), S.Content);
6454
}
6555

6656
static bool serialize(SPSOutputBuffer &OB, const TestSNMMSegment &S) {
67-
using ContentType =
68-
SimpleNativeMemoryMap::FinalizeRequest::Segment::ContentType;
69-
assert((S.C != ContentType::Regular || S.Size == S.Content.size()));
70-
if (!SPSType::AsArgList::serialize(OB, ExecutorAddr::fromPtr(S.Address),
71-
static_cast<uint64_t>(S.Size), S.G,
72-
static_cast<uint8_t>(S.C)))
73-
return false;
74-
if (S.C == ContentType::Regular)
75-
return OB.write(S.Content.data(), S.Content.size());
76-
return true;
57+
return SPSType::AsArgList::serialize(
58+
OB, S.AG, ExecutorAddr::fromPtr(S.Address),
59+
static_cast<uint64_t>(S.Size), S.Content);
7760
}
7861
};
7962

@@ -207,30 +190,61 @@ TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) {
207190

208191
std::future<Expected<Expected<void *>>> FinalizeKey;
209192
TestSNMMFinalizeRequest FR;
210-
void *FinalizeBase = // Finalize addr at non-zero (64kb) offset from base.
211-
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Addr) + 64 * 1024);
212-
uint64_t SentinelValue = 0;
213-
214-
FR.Segments.push_back({FinalizeBase, 64 * 1024,
215-
MemProt::Read | MemProt::Write,
216-
TestSNMMSegment::ZeroFill});
193+
char *FinalizeBase = // Finalize addr at non-zero (64kb) offset from base.
194+
reinterpret_cast<char *>(Addr) + 64 * 1024;
195+
uint64_t SentinelValue1 = 0; // Read from pre-filled content
196+
uint64_t SentinelValue2 = 0; // Written in finalize, read back during dealloc.
197+
uint64_t SentinelValue3 = 42; // Read from zero-filled region.
198+
199+
// Build initial content vector.
200+
std::vector<char> Content;
201+
Content.resize(sizeof(uint64_t) * 2);
202+
memcpy(Content.data(), &SentinelValue3, sizeof(uint64_t));
203+
memcpy(Content.data() + sizeof(uint64_t), &SentinelValue1, sizeof(uint64_t));
204+
205+
FR.Segments.push_back({MemProt::Read | MemProt::Write, FinalizeBase,
206+
64 * 1024, std::move(Content)});
207+
208+
// Read initial content into Sentinel 1.
209+
FR.AAPs.push_back({
210+
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
211+
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue1),
212+
ExecutorAddr::fromPtr(FinalizeBase)),
213+
{} // No dealloc action.
214+
});
215+
216+
// Write value in finalize action, then read back into Sentinel 2.
217217
FR.AAPs.push_back(
218218
{*MakeAllocAction<SPSExecutorAddr, uint64_t>::from(
219-
write_value_sps_allocaction, ExecutorAddr::fromPtr(FinalizeBase),
219+
write_value_sps_allocaction,
220+
ExecutorAddr::fromPtr(FinalizeBase) + sizeof(uint64_t),
220221
uint64_t(42)),
221222
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
222-
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue),
223-
ExecutorAddr::fromPtr(FinalizeBase))});
223+
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue2),
224+
ExecutorAddr::fromPtr(FinalizeBase) + sizeof(uint64_t))});
225+
226+
// Read first 64 bits of the zero-fill region.
227+
FR.AAPs.push_back({
228+
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
229+
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue3),
230+
ExecutorAddr::fromPtr(FinalizeBase) + sizeof(uint64_t) * 2),
231+
{} // No dealloc action.
232+
});
233+
224234
snmm_finalize(waitFor(FinalizeKey), SNMM.get(), std::move(FR));
225235
void *FinalizeKeyAddr = cantFail(cantFail(FinalizeKey.get()));
226236

227-
EXPECT_EQ(SentinelValue, 0U);
237+
EXPECT_EQ(SentinelValue1, 42U);
238+
EXPECT_EQ(SentinelValue2, 0U);
239+
EXPECT_EQ(SentinelValue3, 0U);
228240

229241
std::future<Expected<Error>> DeallocResult;
230242
snmm_deallocate(waitFor(DeallocResult), SNMM.get(), FinalizeKeyAddr);
231243
cantFail(cantFail(DeallocResult.get()));
232244

233-
EXPECT_EQ(SentinelValue, 42);
245+
EXPECT_EQ(SentinelValue1, 42U);
246+
EXPECT_EQ(SentinelValue2, 42U);
247+
EXPECT_EQ(SentinelValue3, 0U);
234248

235249
std::future<Expected<Error>> ReleaseResult;
236250
snmm_release(waitFor(ReleaseResult), SNMM.get(), Addr);
@@ -248,13 +262,13 @@ TEST(SimpleNativeMemoryMap, ReserveFinalizeShutdown) {
248262

249263
std::future<Expected<Expected<void *>>> FinalizeKey;
250264
TestSNMMFinalizeRequest FR;
251-
void *FinalizeBase = // Finalize addr at non-zero (64kb) offset from base.
252-
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Addr) + 64 * 1024);
265+
char *FinalizeBase = // Finalize addr at non-zero (64kb) offset from base.
266+
reinterpret_cast<char *>(Addr) + 64 * 1024;
253267
uint64_t SentinelValue = 0;
254268

255-
FR.Segments.push_back({FinalizeBase, 64 * 1024,
256-
MemProt::Read | MemProt::Write,
257-
TestSNMMSegment::ZeroFill});
269+
FR.Segments.push_back(
270+
{MemProt::Read | MemProt::Write, FinalizeBase, 64 * 1024});
271+
258272
FR.AAPs.push_back(
259273
{*MakeAllocAction<SPSExecutorAddr, uint64_t>::from(
260274
write_value_sps_allocaction, ExecutorAddr::fromPtr(FinalizeBase),
@@ -285,13 +299,13 @@ TEST(SimpleNativeMemoryMap, ReserveFinalizeDetachShutdown) {
285299

286300
std::future<Expected<Expected<void *>>> FinalizeKey;
287301
TestSNMMFinalizeRequest FR;
288-
void *FinalizeBase = // Finalize addr at non-zero (64kb) offset from base.
289-
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Addr) + 64 * 1024);
302+
char *FinalizeBase = // Finalize addr at non-zero (64kb) offset from base.
303+
reinterpret_cast<char *>(Addr) + 64 * 1024;
290304
uint64_t SentinelValue = 0;
291305

292-
FR.Segments.push_back({FinalizeBase, 64 * 1024,
293-
MemProt::Read | MemProt::Write,
294-
TestSNMMSegment::ZeroFill});
306+
FR.Segments.push_back(
307+
{MemProt::Read | MemProt::Write, FinalizeBase, 64 * 1024});
308+
295309
FR.AAPs.push_back(
296310
{*MakeAllocAction<SPSExecutorAddr, uint64_t>::from(
297311
write_value_sps_allocaction, ExecutorAddr::fromPtr(FinalizeBase),

0 commit comments

Comments
 (0)