1ff0cc061SDimitry Andric //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
2ff0cc061SDimitry Andric //
3ff0cc061SDimitry Andric // The LLVM Compiler Infrastructure
4ff0cc061SDimitry Andric //
5ff0cc061SDimitry Andric // This file is distributed under the University of Illinois Open Source
6ff0cc061SDimitry Andric // License. See LICENSE.TXT for details.
7ff0cc061SDimitry Andric //
8ff0cc061SDimitry Andric //===----------------------------------------------------------------------===//
9ff0cc061SDimitry Andric //
10ff0cc061SDimitry Andric // This file implements the section-based memory manager used by the MCJIT
11ff0cc061SDimitry Andric // execution engine and RuntimeDyld
12ff0cc061SDimitry Andric //
13ff0cc061SDimitry Andric //===----------------------------------------------------------------------===//
14ff0cc061SDimitry Andric
15ff0cc061SDimitry Andric #include "llvm/ExecutionEngine/SectionMemoryManager.h"
16db17bf38SDimitry Andric #include "llvm/Config/config.h"
17ff0cc061SDimitry Andric #include "llvm/Support/MathExtras.h"
187d523365SDimitry Andric #include "llvm/Support/Process.h"
19ff0cc061SDimitry Andric
20ff0cc061SDimitry Andric namespace llvm {
21ff0cc061SDimitry Andric
allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)22ff0cc061SDimitry Andric uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
23ff0cc061SDimitry Andric unsigned Alignment,
24ff0cc061SDimitry Andric unsigned SectionID,
25ff0cc061SDimitry Andric StringRef SectionName,
26ff0cc061SDimitry Andric bool IsReadOnly) {
27ff0cc061SDimitry Andric if (IsReadOnly)
282cab237bSDimitry Andric return allocateSection(SectionMemoryManager::AllocationPurpose::ROData,
292cab237bSDimitry Andric Size, Alignment);
302cab237bSDimitry Andric return allocateSection(SectionMemoryManager::AllocationPurpose::RWData, Size,
312cab237bSDimitry Andric Alignment);
32ff0cc061SDimitry Andric }
33ff0cc061SDimitry Andric
allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)34ff0cc061SDimitry Andric uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
35ff0cc061SDimitry Andric unsigned Alignment,
36ff0cc061SDimitry Andric unsigned SectionID,
37ff0cc061SDimitry Andric StringRef SectionName) {
382cab237bSDimitry Andric return allocateSection(SectionMemoryManager::AllocationPurpose::Code, Size,
392cab237bSDimitry Andric Alignment);
40ff0cc061SDimitry Andric }
41ff0cc061SDimitry Andric
allocateSection(SectionMemoryManager::AllocationPurpose Purpose,uintptr_t Size,unsigned Alignment)422cab237bSDimitry Andric uint8_t *SectionMemoryManager::allocateSection(
432cab237bSDimitry Andric SectionMemoryManager::AllocationPurpose Purpose, uintptr_t Size,
44ff0cc061SDimitry Andric unsigned Alignment) {
45ff0cc061SDimitry Andric if (!Alignment)
46ff0cc061SDimitry Andric Alignment = 16;
47ff0cc061SDimitry Andric
48ff0cc061SDimitry Andric assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
49ff0cc061SDimitry Andric
50ff0cc061SDimitry Andric uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1);
51ff0cc061SDimitry Andric uintptr_t Addr = 0;
52ff0cc061SDimitry Andric
532cab237bSDimitry Andric MemoryGroup &MemGroup = [&]() -> MemoryGroup & {
542cab237bSDimitry Andric switch (Purpose) {
552cab237bSDimitry Andric case AllocationPurpose::Code:
562cab237bSDimitry Andric return CodeMem;
572cab237bSDimitry Andric case AllocationPurpose::ROData:
582cab237bSDimitry Andric return RODataMem;
592cab237bSDimitry Andric case AllocationPurpose::RWData:
602cab237bSDimitry Andric return RWDataMem;
612cab237bSDimitry Andric }
622cab237bSDimitry Andric llvm_unreachable("Unknown SectionMemoryManager::AllocationPurpose");
632cab237bSDimitry Andric }();
642cab237bSDimitry Andric
65ff0cc061SDimitry Andric // Look in the list of free memory regions and use a block there if one
66ff0cc061SDimitry Andric // is available.
677d523365SDimitry Andric for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
687d523365SDimitry Andric if (FreeMB.Free.size() >= RequiredSize) {
697d523365SDimitry Andric Addr = (uintptr_t)FreeMB.Free.base();
707d523365SDimitry Andric uintptr_t EndOfBlock = Addr + FreeMB.Free.size();
71ff0cc061SDimitry Andric // Align the address.
72ff0cc061SDimitry Andric Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
737d523365SDimitry Andric
747d523365SDimitry Andric if (FreeMB.PendingPrefixIndex == (unsigned)-1) {
757d523365SDimitry Andric // The part of the block we're giving out to the user is now pending
767d523365SDimitry Andric MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
777d523365SDimitry Andric
787d523365SDimitry Andric // Remember this pending block, such that future allocations can just
797d523365SDimitry Andric // modify it rather than creating a new one
807d523365SDimitry Andric FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
817d523365SDimitry Andric } else {
822cab237bSDimitry Andric sys::MemoryBlock &PendingMB =
832cab237bSDimitry Andric MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
842cab237bSDimitry Andric PendingMB = sys::MemoryBlock(PendingMB.base(),
852cab237bSDimitry Andric Addr + Size - (uintptr_t)PendingMB.base());
867d523365SDimitry Andric }
877d523365SDimitry Andric
887d523365SDimitry Andric // Remember how much free space is now left in this block
892cab237bSDimitry Andric FreeMB.Free =
902cab237bSDimitry Andric sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
91ff0cc061SDimitry Andric return (uint8_t *)Addr;
92ff0cc061SDimitry Andric }
93ff0cc061SDimitry Andric }
94ff0cc061SDimitry Andric
95ff0cc061SDimitry Andric // No pre-allocated free block was large enough. Allocate a new memory region.
96ff0cc061SDimitry Andric // Note that all sections get allocated as read-write. The permissions will
97ff0cc061SDimitry Andric // be updated later based on memory group.
98ff0cc061SDimitry Andric //
99ff0cc061SDimitry Andric // FIXME: It would be useful to define a default allocation size (or add
100ff0cc061SDimitry Andric // it as a constructor parameter) to minimize the number of allocations.
101ff0cc061SDimitry Andric //
102ff0cc061SDimitry Andric // FIXME: Initialize the Near member for each memory group to avoid
103ff0cc061SDimitry Andric // interleaving.
104ff0cc061SDimitry Andric std::error_code ec;
1052cab237bSDimitry Andric sys::MemoryBlock MB = MMapper.allocateMappedMemory(
1062cab237bSDimitry Andric Purpose, RequiredSize, &MemGroup.Near,
1072cab237bSDimitry Andric sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec);
108ff0cc061SDimitry Andric if (ec) {
109ff0cc061SDimitry Andric // FIXME: Add error propagation to the interface.
110ff0cc061SDimitry Andric return nullptr;
111ff0cc061SDimitry Andric }
112ff0cc061SDimitry Andric
113ff0cc061SDimitry Andric // Save this address as the basis for our next request
114ff0cc061SDimitry Andric MemGroup.Near = MB;
115ff0cc061SDimitry Andric
1167d523365SDimitry Andric // Remember that we allocated this memory
117ff0cc061SDimitry Andric MemGroup.AllocatedMem.push_back(MB);
118ff0cc061SDimitry Andric Addr = (uintptr_t)MB.base();
119ff0cc061SDimitry Andric uintptr_t EndOfBlock = Addr + MB.size();
120ff0cc061SDimitry Andric
121ff0cc061SDimitry Andric // Align the address.
122ff0cc061SDimitry Andric Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
123ff0cc061SDimitry Andric
1247d523365SDimitry Andric // The part of the block we're giving out to the user is now pending
1257d523365SDimitry Andric MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
1267d523365SDimitry Andric
127ff0cc061SDimitry Andric // The allocateMappedMemory may allocate much more memory than we need. In
128ff0cc061SDimitry Andric // this case, we store the unused memory as a free memory block.
129ff0cc061SDimitry Andric unsigned FreeSize = EndOfBlock - Addr - Size;
1307d523365SDimitry Andric if (FreeSize > 16) {
1317d523365SDimitry Andric FreeMemBlock FreeMB;
1327d523365SDimitry Andric FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), FreeSize);
1337d523365SDimitry Andric FreeMB.PendingPrefixIndex = (unsigned)-1;
1347d523365SDimitry Andric MemGroup.FreeMem.push_back(FreeMB);
1357d523365SDimitry Andric }
136ff0cc061SDimitry Andric
137ff0cc061SDimitry Andric // Return aligned address
138ff0cc061SDimitry Andric return (uint8_t *)Addr;
139ff0cc061SDimitry Andric }
140ff0cc061SDimitry Andric
finalizeMemory(std::string * ErrMsg)1412cab237bSDimitry Andric bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) {
142ff0cc061SDimitry Andric // FIXME: Should in-progress permissions be reverted if an error occurs?
143ff0cc061SDimitry Andric std::error_code ec;
144ff0cc061SDimitry Andric
145ff0cc061SDimitry Andric // Make code memory executable.
146ff0cc061SDimitry Andric ec = applyMemoryGroupPermissions(CodeMem,
147ff0cc061SDimitry Andric sys::Memory::MF_READ | sys::Memory::MF_EXEC);
148ff0cc061SDimitry Andric if (ec) {
149ff0cc061SDimitry Andric if (ErrMsg) {
150ff0cc061SDimitry Andric *ErrMsg = ec.message();
151ff0cc061SDimitry Andric }
152ff0cc061SDimitry Andric return true;
153ff0cc061SDimitry Andric }
154ff0cc061SDimitry Andric
155ff0cc061SDimitry Andric // Make read-only data memory read-only.
156ff0cc061SDimitry Andric ec = applyMemoryGroupPermissions(RODataMem,
157ff0cc061SDimitry Andric sys::Memory::MF_READ | sys::Memory::MF_EXEC);
158ff0cc061SDimitry Andric if (ec) {
159ff0cc061SDimitry Andric if (ErrMsg) {
160ff0cc061SDimitry Andric *ErrMsg = ec.message();
161ff0cc061SDimitry Andric }
162ff0cc061SDimitry Andric return true;
163ff0cc061SDimitry Andric }
164ff0cc061SDimitry Andric
165ff0cc061SDimitry Andric // Read-write data memory already has the correct permissions
166ff0cc061SDimitry Andric
167ff0cc061SDimitry Andric // Some platforms with separate data cache and instruction cache require
168ff0cc061SDimitry Andric // explicit cache flush, otherwise JIT code manipulations (like resolved
169ff0cc061SDimitry Andric // relocations) will get to the data cache but not to the instruction cache.
170ff0cc061SDimitry Andric invalidateInstructionCache();
171ff0cc061SDimitry Andric
172ff0cc061SDimitry Andric return false;
173ff0cc061SDimitry Andric }
174ff0cc061SDimitry Andric
trimBlockToPageSize(sys::MemoryBlock M)1757d523365SDimitry Andric static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) {
1767d523365SDimitry Andric static const size_t PageSize = sys::Process::getPageSize();
1777d523365SDimitry Andric
1787d523365SDimitry Andric size_t StartOverlap =
1797d523365SDimitry Andric (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize;
1807d523365SDimitry Andric
1817d523365SDimitry Andric size_t TrimmedSize = M.size();
1827d523365SDimitry Andric TrimmedSize -= StartOverlap;
1837d523365SDimitry Andric TrimmedSize -= TrimmedSize % PageSize;
1847d523365SDimitry Andric
1852cab237bSDimitry Andric sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap),
1862cab237bSDimitry Andric TrimmedSize);
1877d523365SDimitry Andric
1887d523365SDimitry Andric assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
1897d523365SDimitry Andric assert((Trimmed.size() % PageSize) == 0);
1907d523365SDimitry Andric assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size());
1917d523365SDimitry Andric
1927d523365SDimitry Andric return Trimmed;
1937d523365SDimitry Andric }
1947d523365SDimitry Andric
195ff0cc061SDimitry Andric std::error_code
applyMemoryGroupPermissions(MemoryGroup & MemGroup,unsigned Permissions)196ff0cc061SDimitry Andric SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
197ff0cc061SDimitry Andric unsigned Permissions) {
1987d523365SDimitry Andric for (sys::MemoryBlock &MB : MemGroup.PendingMem)
1992cab237bSDimitry Andric if (std::error_code EC = MMapper.protectMappedMemory(MB, Permissions))
2007d523365SDimitry Andric return EC;
201ff0cc061SDimitry Andric
2027d523365SDimitry Andric MemGroup.PendingMem.clear();
2037d523365SDimitry Andric
2047d523365SDimitry Andric // Now go through free blocks and trim any of them that don't span the entire
2057d523365SDimitry Andric // page because one of the pending blocks may have overlapped it.
2067d523365SDimitry Andric for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
2077d523365SDimitry Andric FreeMB.Free = trimBlockToPageSize(FreeMB.Free);
2087d523365SDimitry Andric // We cleared the PendingMem list, so all these pointers are now invalid
2097d523365SDimitry Andric FreeMB.PendingPrefixIndex = (unsigned)-1;
210ff0cc061SDimitry Andric }
2117d523365SDimitry Andric
2127d523365SDimitry Andric // Remove all blocks which are now empty
2137d523365SDimitry Andric MemGroup.FreeMem.erase(
214d88c1a5aSDimitry Andric remove_if(MemGroup.FreeMem,
2157d523365SDimitry Andric [](FreeMemBlock &FreeMB) { return FreeMB.Free.size() == 0; }),
2167d523365SDimitry Andric MemGroup.FreeMem.end());
217ff0cc061SDimitry Andric
218ff0cc061SDimitry Andric return std::error_code();
219ff0cc061SDimitry Andric }
220ff0cc061SDimitry Andric
invalidateInstructionCache()221ff0cc061SDimitry Andric void SectionMemoryManager::invalidateInstructionCache() {
2227d523365SDimitry Andric for (sys::MemoryBlock &Block : CodeMem.PendingMem)
2237d523365SDimitry Andric sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
224ff0cc061SDimitry Andric }
225ff0cc061SDimitry Andric
~SectionMemoryManager()226ff0cc061SDimitry Andric SectionMemoryManager::~SectionMemoryManager() {
2277d523365SDimitry Andric for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) {
2287d523365SDimitry Andric for (sys::MemoryBlock &Block : Group->AllocatedMem)
2292cab237bSDimitry Andric MMapper.releaseMappedMemory(Block);
2307d523365SDimitry Andric }
231ff0cc061SDimitry Andric }
232ff0cc061SDimitry Andric
~MemoryMapper()2332cab237bSDimitry Andric SectionMemoryManager::MemoryMapper::~MemoryMapper() {}
2342cab237bSDimitry Andric
anchor()235*4ba319b5SDimitry Andric void SectionMemoryManager::anchor() {}
236*4ba319b5SDimitry Andric
2372cab237bSDimitry Andric namespace {
2382cab237bSDimitry Andric // Trivial implementation of SectionMemoryManager::MemoryMapper that just calls
2392cab237bSDimitry Andric // into sys::Memory.
2402cab237bSDimitry Andric class DefaultMMapper final : public SectionMemoryManager::MemoryMapper {
2412cab237bSDimitry Andric public:
2422cab237bSDimitry Andric sys::MemoryBlock
allocateMappedMemory(SectionMemoryManager::AllocationPurpose Purpose,size_t NumBytes,const sys::MemoryBlock * const NearBlock,unsigned Flags,std::error_code & EC)2432cab237bSDimitry Andric allocateMappedMemory(SectionMemoryManager::AllocationPurpose Purpose,
2442cab237bSDimitry Andric size_t NumBytes, const sys::MemoryBlock *const NearBlock,
2452cab237bSDimitry Andric unsigned Flags, std::error_code &EC) override {
2462cab237bSDimitry Andric return sys::Memory::allocateMappedMemory(NumBytes, NearBlock, Flags, EC);
2472cab237bSDimitry Andric }
2482cab237bSDimitry Andric
protectMappedMemory(const sys::MemoryBlock & Block,unsigned Flags)2492cab237bSDimitry Andric std::error_code protectMappedMemory(const sys::MemoryBlock &Block,
2502cab237bSDimitry Andric unsigned Flags) override {
2512cab237bSDimitry Andric return sys::Memory::protectMappedMemory(Block, Flags);
2522cab237bSDimitry Andric }
2532cab237bSDimitry Andric
releaseMappedMemory(sys::MemoryBlock & M)2542cab237bSDimitry Andric std::error_code releaseMappedMemory(sys::MemoryBlock &M) override {
2552cab237bSDimitry Andric return sys::Memory::releaseMappedMemory(M);
2562cab237bSDimitry Andric }
2572cab237bSDimitry Andric };
2582cab237bSDimitry Andric
2592cab237bSDimitry Andric DefaultMMapper DefaultMMapperInstance;
2602cab237bSDimitry Andric } // namespace
2612cab237bSDimitry Andric
SectionMemoryManager(MemoryMapper * MM)2622cab237bSDimitry Andric SectionMemoryManager::SectionMemoryManager(MemoryMapper *MM)
2632cab237bSDimitry Andric : MMapper(MM ? *MM : DefaultMMapperInstance) {}
2642cab237bSDimitry Andric
265ff0cc061SDimitry Andric } // namespace llvm
266