Skip to content

Commit c85d0aa

Browse files
committed
[JITLink] Switch to slab allocation for InProcessMemoryManager, re-enable test.
InProcessMemoryManager used to make separate memory allocation calls for each permission level (RW, RX, RO), which could lead to target-out-of-range errors if data and code were placed too far apart (this was the source of failures in the JITLink/AArch64 testcase when it was first landed). This patch updates InProcessMemoryManager to allocate a single slab which is subdivided between text and data. This should guarantee that accesses remain in-range provided that individual object files do not exceed 1Mb in size. This patch also re-enables the JITLink/AArch64 testcase. llvm-svn: 374948
1 parent 74b285e commit c85d0aa

File tree

2 files changed

+42
-12
lines changed

2 files changed

+42
-12
lines changed

llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,21 @@ InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) {
3838
OnFinalize(applyProtections());
3939
}
4040
Error deallocate() override {
41-
for (auto &KV : SegBlocks)
42-
if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
43-
return errorCodeToError(EC);
41+
if (SegBlocks.empty())
42+
return Error::success();
43+
void *SlabStart = SegBlocks.begin()->second.base();
44+
char *SlabEnd = (char *)SlabStart;
45+
for (auto &KV : SegBlocks) {
46+
SlabStart = std::min(SlabStart, KV.second.base());
47+
SlabEnd = std::max(SlabEnd, (char *)(KV.second.base()) +
48+
KV.second.allocatedSize());
49+
}
50+
size_t SlabSize = SlabEnd - (char *)SlabStart;
51+
assert((SlabSize % sys::Process::getPageSizeEstimate()) == 0 &&
52+
"Slab size is not a multiple of page size");
53+
sys::MemoryBlock Slab(SlabStart, SlabSize);
54+
if (auto EC = sys::Memory::releaseMappedMemory(Slab))
55+
return errorCodeToError(EC);
4456
return Error::success();
4557
}
4658

@@ -70,22 +82,40 @@ InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) {
7082
static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
7183
sys::Memory::MF_WRITE);
7284

85+
// Compute the total number of pages to allocate.
86+
size_t TotalSize = 0;
7387
for (auto &KV : Request) {
74-
auto &Seg = KV.second;
88+
const auto &Seg = KV.second;
7589

7690
if (Seg.getAlignment() > sys::Process::getPageSizeEstimate())
7791
return make_error<StringError>("Cannot request higher than page "
7892
"alignment",
7993
inconvertibleErrorCode());
8094

81-
uint64_t SegmentSize = Seg.getContentSize() + Seg.getZeroFillSize();
95+
TotalSize = alignTo(TotalSize, sys::Process::getPageSizeEstimate());
96+
TotalSize += Seg.getContentSize();
97+
TotalSize += Seg.getZeroFillSize();
98+
}
99+
100+
// Allocate one slab to cover all the segments.
101+
std::error_code EC;
102+
auto SlabRemaining =
103+
sys::Memory::allocateMappedMemory(TotalSize, nullptr, ReadWrite, EC);
104+
105+
if (EC)
106+
return errorCodeToError(EC);
107+
108+
// Allocate segment memory from the slab.
109+
for (auto &KV : Request) {
110+
111+
const auto &Seg = KV.second;
82112

83-
std::error_code EC;
84-
auto SegMem =
85-
sys::Memory::allocateMappedMemory(SegmentSize, nullptr, ReadWrite, EC);
113+
uint64_t SegmentSize = alignTo(Seg.getContentSize() + Seg.getZeroFillSize(),
114+
sys::Process::getPageSizeEstimate());
86115

87-
if (EC)
88-
return errorCodeToError(EC);
116+
sys::MemoryBlock SegMem(SlabRemaining.base(), SegmentSize);
117+
SlabRemaining = sys::MemoryBlock((char *)SlabRemaining.base() + SegmentSize,
118+
SegmentSize);
89119

90120
// Zero out the zero-fill memory.
91121
memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 0,
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
# if not 'AArch64' in config.root.targets:
2-
config.unsupported = True
1+
if not 'AArch64' in config.root.targets:
2+
config.unsupported = True

0 commit comments

Comments
 (0)