Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
numba
GitHub Repository: numba/llvmlite
Path: blob/main/ffi/memorymanager.h
1154 views
1
//===----- memorymanager.h - Memory manager for MCJIT/RtDyld -*- C++ -*----===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file contains the declaration of a section-based memory manager used by
10
// the MCJIT execution engine and RuntimeDyld.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#pragma once
15
16
// Force default visibility of the llvm::ErrorInfoBase class. The conda
17
// compilers use the -fvisibility-inlines-hidden flag, which seems to
18
// erroneously result in ErrorInfoBase::isA() being hidden (and not exported) on
19
// PowerPC. The reason for this is not conclusively known, but the circumstances
20
// appear similar to those reported in GCC Bug 45065
21
// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=45066) - ErrorInfoBase has
22
// both a template and non-template version, and the non-template version is
23
// overridden by the derived class ErrorInfo; the template vs. non-template
24
// versions may have different inlining decisions applied, and this could create
25
// a similar circumstance to that described in the bug.
26
//
27
// The workaround here adds the default visiblity attribute to ErrorInfoBase
28
// before its definition, which precludes it from being inferred to be hidden
29
// later on.
30
#if not defined(_MSC_VER)
31
namespace llvm {
32
class __attribute__((visibility("default"))) ErrorInfoBase;
33
}
34
#endif
35
36
#include "core.h"
37
#include "llvm/ADT/SmallVector.h"
38
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
39
#include "llvm/Support/Alignment.h"
40
#include "llvm/Support/Memory.h"
41
#include <cstdint>
42
#include <string>
43
#include <system_error>
44
45
namespace llvm {
46
47
/// This is a simple memory manager which implements the methods called by
48
/// the RuntimeDyld class to allocate memory for section-based loading of
49
/// objects, usually those generated by the MCJIT execution engine.
50
///
51
/// This memory manager allocates all section memory as read-write. The
52
/// RuntimeDyld will copy JITed section memory into these allocated blocks
53
/// and perform any necessary linking and relocations.
54
///
55
/// Any client using this memory manager MUST ensure that section-specific
56
/// page permissions have been applied before attempting to execute functions
57
/// in the JITed object. Permissions can be applied either by calling
58
/// MCJIT::finalizeObject or by calling LlvmliteMemoryManager::finalizeMemory
59
/// directly. Clients of MCJIT should call MCJIT::finalizeObject.
60
class API_EXPORT(LlvmliteMemoryManager : public RTDyldMemoryManager) {
61
public:
62
/// This enum describes the various reasons to allocate pages from
63
/// allocateMappedMemory.
64
enum class AllocationPurpose {
65
Code,
66
ROData,
67
RWData,
68
};
69
70
/// Implementations of this interface are used by LlvmliteMemoryManager to
71
/// request pages from the operating system.
72
class MemoryMapper {
73
public:
74
/// This method attempts to allocate \p NumBytes bytes of virtual memory
75
/// for \p Purpose. \p NearBlock may point to an existing allocation,
76
/// in which case an attempt is made to allocate more memory near the
77
/// existing block. The actual allocated address is not guaranteed to be
78
/// near the requested address. \p Flags is used to set the initial
79
/// protection flags for the block of the memory. \p EC [out] returns
80
/// an object describing any error that occurs.
81
///
82
/// This method may allocate more than the number of bytes requested.
83
/// The actual number of bytes allocated is indicated in the returned
84
/// MemoryBlock.
85
///
86
/// The start of the allocated block must be aligned with the system
87
/// allocation granularity (64K on Windows, page size on Linux). If the
88
/// address following \p NearBlock is not so aligned, it will be rounded
89
/// up to the next allocation granularity boundary.
90
///
91
/// \r a non-null MemoryBlock if the function was successful, otherwise
92
/// a null MemoryBlock with \p EC describing the error.
93
virtual sys::MemoryBlock
94
allocateMappedMemory(AllocationPurpose Purpose, size_t NumBytes,
95
const sys::MemoryBlock *const NearBlock,
96
unsigned Flags, std::error_code &EC) = 0;
97
98
/// This method sets the protection flags for a block of memory to the
99
/// state specified by \p Flags. The behavior is not specified if the
100
/// memory was not allocated using the allocateMappedMemory method. \p
101
/// Block describes the memory block to be protected. \p Flags specifies
102
/// the new protection state to be assigned to the block.
103
///
104
/// If \p Flags is MF_WRITE, the actual behavior varies with the
105
/// operating system (i.e. MF_READ | MF_WRITE on Windows) and the target
106
/// architecture (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).
107
///
108
/// \r error_success if the function was successful, or an error_code
109
/// describing the failure if an error occurred.
110
virtual std::error_code
111
protectMappedMemory(const sys::MemoryBlock &Block, unsigned Flags) = 0;
112
113
/// This method releases a block of memory that was allocated with the
114
/// allocateMappedMemory method. It should not be used to release any
115
/// memory block allocated any other way. \p Block describes the memory
116
/// to be released.
117
///
118
/// \r error_success if the function was successful, or an error_code
119
/// describing the failure if an error occurred.
120
virtual std::error_code releaseMappedMemory(sys::MemoryBlock &M) = 0;
121
122
virtual ~MemoryMapper();
123
};
124
125
/// Creates a LlvmliteMemoryManager instance with \p MM as the associated
126
/// memory mapper. If \p MM is nullptr then a default memory mapper is used
127
/// that directly calls into the operating system.
128
LlvmliteMemoryManager(MemoryMapper *MM = nullptr);
129
LlvmliteMemoryManager(const LlvmliteMemoryManager &) = delete;
130
void operator=(const LlvmliteMemoryManager &) = delete;
131
~LlvmliteMemoryManager() override;
132
133
/// Allocates a memory block of (at least) the given size suitable for
134
/// executable code.
135
///
136
/// The value of \p Alignment must be a power of two. If \p Alignment is
137
/// zero a default alignment of 16 will be used.
138
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
139
unsigned SectionID,
140
StringRef SectionName) override;
141
142
/// Allocates a memory block of (at least) the given size suitable for
143
/// executable code.
144
///
145
/// The value of \p Alignment must be a power of two. If \p Alignment is
146
/// zero a default alignment of 16 will be used.
147
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
148
unsigned SectionID, StringRef SectionName,
149
bool isReadOnly) override;
150
151
/// Update section-specific memory permissions and other attributes.
152
///
153
/// This method is called when object loading is complete and section page
154
/// permissions can be applied. It is up to the memory manager
155
/// implementation to decide whether or not to act on this method. The
156
/// memory manager will typically allocate all sections as read-write and
157
/// then apply specific permissions when this method is called. Code
158
/// sections cannot be executed until this function has been called. In
159
/// addition, any cache coherency operations needed to reliably use the
160
/// memory are also performed.
161
///
162
/// \returns true if an error occurred, false otherwise.
163
bool finalizeMemory(std::string *ErrMsg = nullptr) override;
164
165
/// Invalidate instruction cache for code sections.
166
///
167
/// Some platforms with separate data cache and instruction cache require
168
/// explicit cache flush, otherwise JIT code manipulations (like resolved
169
/// relocations) will get to the data cache but not to the instruction
170
/// cache.
171
///
172
/// This method is called from finalizeMemory.
173
virtual void invalidateInstructionCache();
174
175
virtual bool needsToReserveAllocationSpace() override { return true; }
176
177
virtual void reserveAllocationSpace(uintptr_t CodeSize, Align CodeAlign,
178
uintptr_t RODataSize, Align RODataAlign,
179
uintptr_t RWDataSize,
180
Align RWDataAlign) override;
181
182
private:
183
struct FreeMemBlock {
184
// The actual block of free memory
185
sys::MemoryBlock Free;
186
// If there is a pending allocation from the same reservation right
187
// before this block, store it's index in PendingMem, to be able to
188
// update the pending region if part of this block is allocated, rather
189
// than having to create a new one
190
unsigned PendingPrefixIndex;
191
};
192
193
struct MemoryGroup {
194
// PendingMem contains all blocks of memory (subblocks of AllocatedMem)
195
// which have not yet had their permissions applied, but have been given
196
// out to the user. FreeMem contains all block of memory, which have
197
// neither had their permissions applied, nor been given out to the
198
// user.
199
SmallVector<sys::MemoryBlock, 16> PendingMem;
200
SmallVector<FreeMemBlock, 16> FreeMem;
201
202
// All memory blocks that have been requested from the system
203
SmallVector<sys::MemoryBlock, 16> AllocatedMem;
204
205
sys::MemoryBlock Near;
206
};
207
208
uint8_t *allocateSection(AllocationPurpose Purpose, uintptr_t Size,
209
unsigned Alignment);
210
211
std::error_code applyMemoryGroupPermissions(MemoryGroup &MemGroup,
212
unsigned Permissions);
213
214
bool hasSpace(const MemoryGroup &MemGroup, uintptr_t Size) const;
215
216
void anchor() override;
217
218
MemoryGroup CodeMem;
219
MemoryGroup RWDataMem;
220
MemoryGroup RODataMem;
221
MemoryMapper &MMapper;
222
};
223
224
} // end namespace llvm
225
226