forked from Rosalie241/parallel-rsp
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathjit_allocator.cpp
109 lines (95 loc) · 2.47 KB
/
jit_allocator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <sys/mman.h>
#endif
#include <limits>
#include <algorithm>
#include "jit_allocator.hpp"
namespace RSP
{
namespace JIT
{
static constexpr bool huge_va = std::numeric_limits<size_t>::max() > 0x100000000ull;
// On 64-bit systems, we will never allocate more than one block, this is important since we must ensure that
// relative jumps are reachable in 32-bits.
// We won't actually allocate 1 GB on 64-bit, but just reserve VA space for it, which we have basically an infinite amount of.
static constexpr size_t block_size = huge_va ? (1024 * 1024 * 1024) : (2 * 1024 * 1024);
Allocator::~Allocator()
{
#ifdef _WIN32
for (auto &block : blocks)
VirtualFree(block.code, 0, MEM_RELEASE);
#else
for (auto &block : blocks)
munmap(block.code, block.size);
#endif
}
static size_t align_page(size_t offset)
{
return (offset + 4095) & ~size_t(4095);
}
static bool commit_read_write(void *ptr, size_t size)
{
#ifdef _WIN32
return VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) == ptr;
#else
return mprotect(ptr, size, PROT_READ | PROT_WRITE) == 0;
#endif
}
static bool commit_execute(void *ptr, size_t size)
{
#ifdef _WIN32
DWORD old_protect;
return VirtualProtect(ptr, align_page(size), PAGE_EXECUTE, &old_protect) != 0;
#else
return mprotect(ptr, size, PROT_EXEC) == 0;
#endif
}
bool Allocator::commit_code(void *code, size_t size)
{
return commit_execute(code, size);
}
void *Allocator::allocate_code(size_t size)
{
size = align_page(size);
if (blocks.empty())
blocks.push_back(reserve_block(std::max(size, block_size)));
auto *block = &blocks.back();
if (!block->code)
return nullptr;
block->offset = align_page(block->offset);
if (block->offset + size > block->size)
block = nullptr;
if (!block)
{
if (huge_va)
abort();
blocks.push_back(reserve_block(std::max(size, block_size)));
block = &blocks.back();
}
if (!block || !block->code)
return nullptr;
void *ret = block->code + block->offset;
block->offset += size;
if (!commit_read_write(ret, size))
return nullptr;
return ret;
}
Allocator::Block Allocator::reserve_block(size_t size)
{
Block block;
#ifdef _WIN32
block.code = static_cast<uint8_t *>(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE));
block.size = size;
return block;
#else
block.code = static_cast<uint8_t *>(mmap(nullptr, size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE,
-1, 0));
block.size = size;
return block;
#endif
}
}
}