source: icGREP/icgrep-devel/llvm-3.8.0.src/lib/ExecutionEngine/SectionMemoryManager.cpp @ 5667

Last change on this file since 5667 was 5027, checked in by cameron, 3 years ago

Upgrade to llvm 3.8

File size: 7.9 KB
Line 
1//===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the section-based memory manager used by the MCJIT
11// execution engine and RuntimeDyld
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Config/config.h"
16#include "llvm/ExecutionEngine/SectionMemoryManager.h"
17#include "llvm/Support/MathExtras.h"
18#include "llvm/Support/Process.h"
19
20namespace llvm {
21
22uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
23                                                   unsigned Alignment,
24                                                   unsigned SectionID,
25                                                   StringRef SectionName,
26                                                   bool IsReadOnly) {
27  if (IsReadOnly)
28    return allocateSection(RODataMem, Size, Alignment);
29  return allocateSection(RWDataMem, Size, Alignment);
30}
31
32uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
33                                                   unsigned Alignment,
34                                                   unsigned SectionID,
35                                                   StringRef SectionName) {
36  return allocateSection(CodeMem, Size, Alignment);
37}
38
39uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
40                                               uintptr_t Size,
41                                               unsigned Alignment) {
42  if (!Alignment)
43    Alignment = 16;
44
45  assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
46
47  uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1);
48  uintptr_t Addr = 0;
49
50  // Look in the list of free memory regions and use a block there if one
51  // is available.
52  for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
53    if (FreeMB.Free.size() >= RequiredSize) {
54      Addr = (uintptr_t)FreeMB.Free.base();
55      uintptr_t EndOfBlock = Addr + FreeMB.Free.size();
56      // Align the address.
57      Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
58
59      if (FreeMB.PendingPrefixIndex == (unsigned)-1) {
60        // The part of the block we're giving out to the user is now pending
61        MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
62
63        // Remember this pending block, such that future allocations can just
64        // modify it rather than creating a new one
65        FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
66      } else {
67        sys::MemoryBlock &PendingMB = MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
68        PendingMB = sys::MemoryBlock(PendingMB.base(), Addr + Size - (uintptr_t)PendingMB.base());
69      }
70
71      // Remember how much free space is now left in this block
72      FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
73      return (uint8_t*)Addr;
74    }
75  }
76
77  // No pre-allocated free block was large enough. Allocate a new memory region.
78  // Note that all sections get allocated as read-write.  The permissions will
79  // be updated later based on memory group.
80  //
81  // FIXME: It would be useful to define a default allocation size (or add
82  // it as a constructor parameter) to minimize the number of allocations.
83  //
84  // FIXME: Initialize the Near member for each memory group to avoid
85  // interleaving.
86  std::error_code ec;
87  sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize,
88                                                          &MemGroup.Near,
89                                                          sys::Memory::MF_READ |
90                                                            sys::Memory::MF_WRITE,
91                                                          ec);
92  if (ec) {
93    // FIXME: Add error propagation to the interface.
94    return nullptr;
95  }
96
97  // Save this address as the basis for our next request
98  MemGroup.Near = MB;
99
100  // Remember that we allocated this memory
101  MemGroup.AllocatedMem.push_back(MB);
102  Addr = (uintptr_t)MB.base();
103  uintptr_t EndOfBlock = Addr + MB.size();
104
105  // Align the address.
106  Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
107
108  // The part of the block we're giving out to the user is now pending
109  MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
110
111  // The allocateMappedMemory may allocate much more memory than we need. In
112  // this case, we store the unused memory as a free memory block.
113  unsigned FreeSize = EndOfBlock-Addr-Size;
114  if (FreeSize > 16) {
115    FreeMemBlock FreeMB;
116    FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize);
117    FreeMB.PendingPrefixIndex = (unsigned)-1;
118    MemGroup.FreeMem.push_back(FreeMB);
119  }
120
121  // Return aligned address
122  return (uint8_t*)Addr;
123}
124
125bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
126{
127  // FIXME: Should in-progress permissions be reverted if an error occurs?
128  std::error_code ec;
129
130  // Make code memory executable.
131  ec = applyMemoryGroupPermissions(CodeMem,
132                                   sys::Memory::MF_READ | sys::Memory::MF_EXEC);
133  if (ec) {
134    if (ErrMsg) {
135      *ErrMsg = ec.message();
136    }
137    return true;
138  }
139
140  // Make read-only data memory read-only.
141  ec = applyMemoryGroupPermissions(RODataMem,
142                                   sys::Memory::MF_READ | sys::Memory::MF_EXEC);
143  if (ec) {
144    if (ErrMsg) {
145      *ErrMsg = ec.message();
146    }
147    return true;
148  }
149
150  // Read-write data memory already has the correct permissions
151
152  // Some platforms with separate data cache and instruction cache require
153  // explicit cache flush, otherwise JIT code manipulations (like resolved
154  // relocations) will get to the data cache but not to the instruction cache.
155  invalidateInstructionCache();
156
157  return false;
158}
159
160static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) {
161  static const size_t PageSize = sys::Process::getPageSize();
162
163  size_t StartOverlap =
164      (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize;
165
166  size_t TrimmedSize = M.size();
167  TrimmedSize -= StartOverlap;
168  TrimmedSize -= TrimmedSize % PageSize;
169
170  sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), TrimmedSize);
171
172  assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
173  assert((Trimmed.size() % PageSize) == 0);
174  assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size());
175
176  return Trimmed;
177}
178
179
180std::error_code
181SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
182                                                  unsigned Permissions) {
183  for (sys::MemoryBlock &MB : MemGroup.PendingMem)
184    if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions))
185      return EC;
186
187  MemGroup.PendingMem.clear();
188
189  // Now go through free blocks and trim any of them that don't span the entire
190  // page because one of the pending blocks may have overlapped it.
191  for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
192    FreeMB.Free = trimBlockToPageSize(FreeMB.Free);
193    // We cleared the PendingMem list, so all these pointers are now invalid
194    FreeMB.PendingPrefixIndex = (unsigned)-1;
195  }
196
197  // Remove all blocks which are now empty
198  MemGroup.FreeMem.erase(
199      std::remove_if(MemGroup.FreeMem.begin(), MemGroup.FreeMem.end(),
200                     [](FreeMemBlock &FreeMB) { return FreeMB.Free.size() == 0; }),
201      MemGroup.FreeMem.end());
202
203  return std::error_code();
204}
205
206void SectionMemoryManager::invalidateInstructionCache() {
207  for (sys::MemoryBlock &Block : CodeMem.PendingMem)
208    sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
209}
210
211SectionMemoryManager::~SectionMemoryManager() {
212  for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) {
213    for (sys::MemoryBlock &Block : Group->AllocatedMem)
214      sys::Memory::releaseMappedMemory(Block);
215  }
216}
217
218} // namespace llvm
Note: See TracBrowser for help on using the repository browser.