]>
Commit | Line | Data |
---|---|---|
970d7e83 LB |
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" | |
970d7e83 LB |
17 | #include "llvm/Support/MathExtras.h" |
18 | ||
970d7e83 LB |
19 | namespace llvm { |
20 | ||
21 | uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, | |
1a4d82fc JJ |
22 | unsigned Alignment, |
23 | unsigned SectionID, | |
24 | StringRef SectionName, | |
25 | bool IsReadOnly) { | |
970d7e83 LB |
26 | if (IsReadOnly) |
27 | return allocateSection(RODataMem, Size, Alignment); | |
28 | return allocateSection(RWDataMem, Size, Alignment); | |
29 | } | |
30 | ||
31 | uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, | |
32 | unsigned Alignment, | |
1a4d82fc JJ |
33 | unsigned SectionID, |
34 | StringRef SectionName) { | |
970d7e83 LB |
35 | return allocateSection(CodeMem, Size, Alignment); |
36 | } | |
37 | ||
38 | uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup, | |
39 | uintptr_t Size, | |
40 | unsigned Alignment) { | |
41 | if (!Alignment) | |
42 | Alignment = 16; | |
43 | ||
44 | assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); | |
45 | ||
46 | uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1); | |
47 | uintptr_t Addr = 0; | |
48 | ||
49 | // Look in the list of free memory regions and use a block there if one | |
50 | // is available. | |
51 | for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) { | |
52 | sys::MemoryBlock &MB = MemGroup.FreeMem[i]; | |
53 | if (MB.size() >= RequiredSize) { | |
54 | Addr = (uintptr_t)MB.base(); | |
55 | uintptr_t EndOfBlock = Addr + MB.size(); | |
56 | // Align the address. | |
57 | Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); | |
58 | // Store cutted free memory block. | |
59 | MemGroup.FreeMem[i] = sys::MemoryBlock((void*)(Addr + Size), | |
60 | EndOfBlock - Addr - Size); | |
61 | return (uint8_t*)Addr; | |
62 | } | |
63 | } | |
64 | ||
65 | // No pre-allocated free block was large enough. Allocate a new memory region. | |
66 | // Note that all sections get allocated as read-write. The permissions will | |
67 | // be updated later based on memory group. | |
68 | // | |
69 | // FIXME: It would be useful to define a default allocation size (or add | |
70 | // it as a constructor parameter) to minimize the number of allocations. | |
71 | // | |
72 | // FIXME: Initialize the Near member for each memory group to avoid | |
73 | // interleaving. | |
1a4d82fc | 74 | std::error_code ec; |
970d7e83 LB |
75 | sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize, |
76 | &MemGroup.Near, | |
77 | sys::Memory::MF_READ | | |
78 | sys::Memory::MF_WRITE, | |
79 | ec); | |
80 | if (ec) { | |
1a4d82fc JJ |
81 | // FIXME: Add error propagation to the interface. |
82 | return nullptr; | |
970d7e83 LB |
83 | } |
84 | ||
85 | // Save this address as the basis for our next request | |
86 | MemGroup.Near = MB; | |
87 | ||
88 | MemGroup.AllocatedMem.push_back(MB); | |
89 | Addr = (uintptr_t)MB.base(); | |
90 | uintptr_t EndOfBlock = Addr + MB.size(); | |
91 | ||
92 | // Align the address. | |
93 | Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); | |
94 | ||
95 | // The allocateMappedMemory may allocate much more memory than we need. In | |
96 | // this case, we store the unused memory as a free memory block. | |
97 | unsigned FreeSize = EndOfBlock-Addr-Size; | |
98 | if (FreeSize > 16) | |
99 | MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); | |
100 | ||
101 | // Return aligned address | |
102 | return (uint8_t*)Addr; | |
103 | } | |
104 | ||
1a4d82fc | 105 | bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) |
970d7e83 LB |
106 | { |
107 | // FIXME: Should in-progress permissions be reverted if an error occurs? | |
1a4d82fc JJ |
108 | std::error_code ec; |
109 | ||
110 | // Don't allow free memory blocks to be used after setting protection flags. | |
111 | CodeMem.FreeMem.clear(); | |
970d7e83 LB |
112 | |
113 | // Make code memory executable. | |
114 | ec = applyMemoryGroupPermissions(CodeMem, | |
115 | sys::Memory::MF_READ | sys::Memory::MF_EXEC); | |
116 | if (ec) { | |
117 | if (ErrMsg) { | |
118 | *ErrMsg = ec.message(); | |
119 | } | |
120 | return true; | |
121 | } | |
122 | ||
1a4d82fc JJ |
123 | // Don't allow free memory blocks to be used after setting protection flags. |
124 | RODataMem.FreeMem.clear(); | |
125 | ||
970d7e83 LB |
126 | // Make read-only data memory read-only. |
127 | ec = applyMemoryGroupPermissions(RODataMem, | |
128 | sys::Memory::MF_READ | sys::Memory::MF_EXEC); | |
129 | if (ec) { | |
130 | if (ErrMsg) { | |
131 | *ErrMsg = ec.message(); | |
132 | } | |
133 | return true; | |
134 | } | |
135 | ||
136 | // Read-write data memory already has the correct permissions | |
137 | ||
1a4d82fc JJ |
138 | // Some platforms with separate data cache and instruction cache require |
139 | // explicit cache flush, otherwise JIT code manipulations (like resolved | |
140 | // relocations) will get to the data cache but not to the instruction cache. | |
141 | invalidateInstructionCache(); | |
142 | ||
970d7e83 LB |
143 | return false; |
144 | } | |
145 | ||
1a4d82fc JJ |
146 | std::error_code |
147 | SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, | |
148 | unsigned Permissions) { | |
970d7e83 LB |
149 | |
150 | for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) { | |
1a4d82fc JJ |
151 | std::error_code ec; |
152 | ec = | |
153 | sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i], Permissions); | |
154 | if (ec) { | |
155 | return ec; | |
156 | } | |
970d7e83 LB |
157 | } |
158 | ||
1a4d82fc | 159 | return std::error_code(); |
970d7e83 LB |
160 | } |
161 | ||
162 | void SectionMemoryManager::invalidateInstructionCache() { | |
163 | for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) | |
164 | sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(), | |
165 | CodeMem.AllocatedMem[i].size()); | |
166 | } | |
167 | ||
970d7e83 LB |
168 | SectionMemoryManager::~SectionMemoryManager() { |
169 | for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) | |
170 | sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]); | |
171 | for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i) | |
172 | sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]); | |
173 | for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i) | |
174 | sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]); | |
175 | } | |
176 | ||
177 | } // namespace llvm | |
178 |