Skip to content

Commit 7e36b83

Browse files
author
git apple-llvm automerger
committed
Merge commit '35b2b24e624b' from llvm.org/main into next
2 parents 0091a9e + 35b2b24 commit 7e36b83

File tree

3 files changed

+363
-15
lines changed

3 files changed

+363
-15
lines changed

llvm/include/llvm/ExecutionEngine/SectionMemoryManager.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,24 @@ class LLVM_ABI SectionMemoryManager : public RTDyldMemoryManager {
105105
/// Creates a SectionMemoryManager instance with \p MM as the associated
106106
/// memory mapper. If \p MM is nullptr then a default memory mapper is used
107107
/// that directly calls into the operating system.
108-
SectionMemoryManager(MemoryMapper *MM = nullptr);
108+
///
109+
/// If \p ReserveAlloc is true all memory will be pre-allocated, and any
110+
/// attempts to allocate beyond pre-allocated memory will fail.
111+
SectionMemoryManager(MemoryMapper *MM = nullptr, bool ReserveAlloc = false);
109112
SectionMemoryManager(const SectionMemoryManager &) = delete;
110113
void operator=(const SectionMemoryManager &) = delete;
111114
~SectionMemoryManager() override;
112115

116+
/// Enable reserveAllocationSpace when requested.
117+
bool needsToReserveAllocationSpace() override { return ReserveAllocation; }
118+
119+
/// Implements allocating all memory in a single block. This is required to
120+
/// limit memory offsets to fit the ARM ABI; large memory systems may
121+
/// otherwise allocate separate sections too far apart.
122+
void reserveAllocationSpace(uintptr_t CodeSize, Align CodeAlign,
123+
uintptr_t RODataSize, Align RODataAlign,
124+
uintptr_t RWDataSize, Align RWDataAlign) override;
125+
113126
/// Allocates a memory block of (at least) the given size suitable for
114127
/// executable code.
115128
///
@@ -181,13 +194,16 @@ class LLVM_ABI SectionMemoryManager : public RTDyldMemoryManager {
181194
std::error_code applyMemoryGroupPermissions(MemoryGroup &MemGroup,
182195
unsigned Permissions);
183196

197+
bool hasSpace(const MemoryGroup &MemGroup, uintptr_t Size) const;
198+
184199
void anchor() override;
185200

186201
MemoryGroup CodeMem;
187202
MemoryGroup RWDataMem;
188203
MemoryGroup RODataMem;
189204
MemoryMapper *MMapper;
190205
std::unique_ptr<MemoryMapper> OwnedMMapper;
206+
bool ReserveAllocation;
191207
};
192208

193209
} // end namespace llvm

llvm/lib/ExecutionEngine/SectionMemoryManager.cpp

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,97 @@
1717

1818
namespace llvm {
1919

20+
bool SectionMemoryManager::hasSpace(const MemoryGroup &MemGroup,
21+
uintptr_t Size) const {
22+
for (const FreeMemBlock &FreeMB : MemGroup.FreeMem) {
23+
if (FreeMB.Free.allocatedSize() >= Size)
24+
return true;
25+
}
26+
return false;
27+
}
28+
29+
void SectionMemoryManager::reserveAllocationSpace(
30+
uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize,
31+
Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) {
32+
if (CodeSize == 0 && RODataSize == 0 && RWDataSize == 0)
33+
return;
34+
35+
static const size_t PageSize = sys::Process::getPageSizeEstimate();
36+
37+
// Code alignment needs to be at least the stub alignment - however, we
38+
// don't have an easy way to get that here so as a workaround, we assume
39+
// it's 8, which is the largest value I observed across all platforms.
40+
constexpr uint64_t StubAlign = 8;
41+
CodeAlign = Align(std::max(CodeAlign.value(), StubAlign));
42+
RODataAlign = Align(std::max(RODataAlign.value(), StubAlign));
43+
RWDataAlign = Align(std::max(RWDataAlign.value(), StubAlign));
44+
45+
// Get space required for each section. Use the same calculation as
46+
// allocateSection because we need to be able to satisfy it.
47+
uint64_t RequiredCodeSize = alignTo(CodeSize, CodeAlign) + CodeAlign.value();
48+
uint64_t RequiredRODataSize =
49+
alignTo(RODataSize, RODataAlign) + RODataAlign.value();
50+
uint64_t RequiredRWDataSize =
51+
alignTo(RWDataSize, RWDataAlign) + RWDataAlign.value();
52+
53+
if (hasSpace(CodeMem, RequiredCodeSize) &&
54+
hasSpace(RODataMem, RequiredRODataSize) &&
55+
hasSpace(RWDataMem, RequiredRWDataSize)) {
56+
// Sufficient space in contiguous block already available.
57+
return;
58+
}
59+
60+
// MemoryManager does not have functions for releasing memory after it's
61+
// allocated. Normally it tries to use any excess blocks that were allocated
62+
// due to page alignment, but if we have insufficient free memory for the
63+
// request this can lead to allocating disparate memory that can violate the
64+
// ARM ABI. Clear free memory so only the new allocations are used, but do
65+
// not release allocated memory as it may still be in-use.
66+
CodeMem.FreeMem.clear();
67+
RODataMem.FreeMem.clear();
68+
RWDataMem.FreeMem.clear();
69+
70+
// Round up to the nearest page size. Blocks must be page-aligned.
71+
RequiredCodeSize = alignTo(RequiredCodeSize, PageSize);
72+
RequiredRODataSize = alignTo(RequiredRODataSize, PageSize);
73+
RequiredRWDataSize = alignTo(RequiredRWDataSize, PageSize);
74+
uint64_t RequiredSize =
75+
RequiredCodeSize + RequiredRODataSize + RequiredRWDataSize;
76+
77+
std::error_code ec;
78+
sys::MemoryBlock MB = MMapper->allocateMappedMemory(
79+
AllocationPurpose::RWData, RequiredSize, nullptr,
80+
sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec);
81+
if (ec) {
82+
return;
83+
}
84+
// CodeMem will arbitrarily own this MemoryBlock to handle cleanup.
85+
CodeMem.AllocatedMem.push_back(MB);
86+
uintptr_t Addr = (uintptr_t)MB.base();
87+
FreeMemBlock FreeMB;
88+
FreeMB.PendingPrefixIndex = (unsigned)-1;
89+
90+
if (CodeSize > 0) {
91+
assert(isAddrAligned(CodeAlign, (void *)Addr));
92+
FreeMB.Free = sys::MemoryBlock((void *)Addr, RequiredCodeSize);
93+
CodeMem.FreeMem.push_back(FreeMB);
94+
Addr += RequiredCodeSize;
95+
}
96+
97+
if (RODataSize > 0) {
98+
assert(isAddrAligned(RODataAlign, (void *)Addr));
99+
FreeMB.Free = sys::MemoryBlock((void *)Addr, RequiredRODataSize);
100+
RODataMem.FreeMem.push_back(FreeMB);
101+
Addr += RequiredRODataSize;
102+
}
103+
104+
if (RWDataSize > 0) {
105+
assert(isAddrAligned(RWDataAlign, (void *)Addr));
106+
FreeMB.Free = sys::MemoryBlock((void *)Addr, RequiredRWDataSize);
107+
RWDataMem.FreeMem.push_back(FreeMB);
108+
}
109+
}
110+
20111
uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
21112
unsigned Alignment,
22113
unsigned SectionID,
@@ -264,8 +355,10 @@ class DefaultMMapper final : public SectionMemoryManager::MemoryMapper {
264355
};
265356
} // namespace
266357

267-
SectionMemoryManager::SectionMemoryManager(MemoryMapper *UnownedMM)
268-
: MMapper(UnownedMM), OwnedMMapper(nullptr) {
358+
SectionMemoryManager::SectionMemoryManager(MemoryMapper *UnownedMM,
359+
bool ReserveAlloc)
360+
: MMapper(UnownedMM), OwnedMMapper(nullptr),
361+
ReserveAllocation(ReserveAlloc) {
269362
if (!MMapper) {
270363
OwnedMMapper = std::make_unique<DefaultMMapper>();
271364
MMapper = OwnedMMapper.get();

0 commit comments

Comments
 (0)