Skip to content

Commit 0fed7aa

Browse files
author
Hans-Kristian Arntzen
committedJun 26, 2020
Use a custom executable memory allocator.
1 parent cce9bf5 commit 0fed7aa

5 files changed

+160
-7
lines changed
 

‎CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ endif()
1212
add_library(parallel-rsp STATIC
1313
rsp/vfunctions.cpp
1414
rsp_jit.cpp rsp_jit.hpp
15+
jit_allocator.cpp jit_allocator.hpp
1516
rsp_disasm.cpp rsp_disasm.hpp
1617
rsp/ls.cpp rsp/pipeline.h
1718
rsp/reciprocal.cpp rsp/reciprocal.h

‎jit_allocator.cpp

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#ifdef _WIN32
2+
#define WIN32_LEAN_AND_MEAN
3+
#include <windows.h>
4+
#else
5+
#include <sys/mman.h>
6+
#endif
7+
#include <limits>
8+
#include <algorithm>
9+
10+
#include "jit_allocator.hpp"
11+
12+
namespace RSP
13+
{
14+
namespace JIT
15+
{
16+
static constexpr bool huge_va = std::numeric_limits<size_t>::max() > 0x100000000ull;
17+
// On 64-bit systems, we will never allocate more than one block, this is important since we must ensure that
18+
// relative jumps are reachable in 32-bits.
19+
static constexpr size_t block_size = huge_va ? (256 * 1024 * 1024) : (2 * 1024 * 1024);
20+
Allocator::~Allocator()
21+
{
22+
#ifdef _WIN32
23+
for (auto &block : blocks)
24+
VirtualFree(block.code, 0, MEM_RELEASE);
25+
#else
26+
#endif
27+
}
28+
29+
static size_t align_page(size_t offset)
30+
{
31+
return (offset + 4095) & ~size_t(4095);
32+
}
33+
34+
static bool commit_read_write(void *ptr, size_t size)
35+
{
36+
#ifdef _WIN32
37+
return VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) == ptr;
38+
#else
39+
#endif
40+
}
41+
42+
static bool commit_execute(void *ptr, size_t size)
43+
{
44+
#ifdef _WIN32
45+
DWORD old_protect;
46+
return VirtualProtect(ptr, align_page(size), PAGE_EXECUTE, &old_protect) != 0;
47+
#else
48+
#endif
49+
}
50+
51+
bool Allocator::commit_code(void *code, size_t size)
52+
{
53+
return commit_execute(code, size);
54+
}
55+
56+
void *Allocator::allocate_code(size_t size)
57+
{
58+
size = align_page(size);
59+
if (blocks.empty())
60+
blocks.push_back(reserve_block(std::max(size, block_size)));
61+
62+
auto *block = &blocks.back();
63+
if (!block->code)
64+
return nullptr;
65+
66+
block->offset = align_page(block->offset);
67+
if (block->offset + size > block->size)
68+
block = nullptr;
69+
70+
if (!block)
71+
{
72+
if (huge_va)
73+
abort();
74+
blocks.push_back(reserve_block(std::max(size, block_size)));
75+
block = &blocks.back();
76+
}
77+
78+
if (!block)
79+
return nullptr;
80+
81+
void *ret = block->code + block->offset;
82+
block->offset += size;
83+
84+
if (!commit_read_write(ret, size))
85+
return nullptr;
86+
return ret;
87+
}
88+
89+
Allocator::Block Allocator::reserve_block(size_t size)
90+
{
91+
Block block;
92+
#ifdef _WIN32
93+
block.code = static_cast<uint8_t *>(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE));
94+
block.size = size;
95+
return block;
96+
#else
97+
#endif
98+
}
99+
}
100+
}

‎jit_allocator.hpp

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <stdint.h>
5+
6+
namespace RSP
7+
{
8+
namespace JIT
9+
{
10+
class Allocator
11+
{
12+
public:
13+
Allocator() = default;
14+
~Allocator();
15+
void operator=(const Allocator &) = delete;
16+
Allocator(const Allocator &) = delete;
17+
18+
void *allocate_code(size_t size);
19+
static bool commit_code(void *code, size_t size);
20+
21+
private:
22+
struct Block
23+
{
24+
uint8_t *code = nullptr;
25+
size_t size = 0;
26+
size_t offset = 0;
27+
};
28+
std::vector<Block> blocks;
29+
30+
static Block reserve_block(size_t size);
31+
};
32+
}
33+
}

‎rsp_jit.cpp

+24-5
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,12 @@ namespace JIT
3232
{
3333
CPU::CPU()
3434
{
35-
cleanup_jit_states.reserve(16 * 1024);
3635
init_jit("RSP");
3736
init_jit_thunks();
3837
}
3938

4039
CPU::~CPU()
4140
{
42-
for (auto *_jit : cleanup_jit_states)
43-
jit_destroy_state();
4441
finish_jit();
4542
}
4643

@@ -426,6 +423,14 @@ void CPU::init_jit_thunks()
426423
// Return status. This register is considered common for all thunks.
427424
jit_retr(JIT_REGISTER_MODE);
428425

426+
jit_realize();
427+
jit_word_t code_size;
428+
jit_get_code(&code_size);
429+
void *thunk_code = allocator.allocate_code(code_size);
430+
if (!thunk_code)
431+
abort();
432+
jit_set_code(thunk_code, code_size);
433+
429434
thunks.enter_frame = reinterpret_cast<int (*)(void *)>(jit_emit());
430435
thunks.enter_thunk = jit_address(entry_label);
431436
thunks.return_thunk = jit_address(return_label);
@@ -434,7 +439,10 @@ void CPU::init_jit_thunks()
434439
//jit_disassemble();
435440
jit_clear_state();
436441
//printf(" === END DISASM ===\n");
437-
cleanup_jit_states.push_back(_jit);
442+
jit_destroy_state();
443+
444+
if (!Allocator::commit_code(thunk_code, code_size))
445+
abort();
438446
}
439447

440448
Func CPU::get_jit_block(uint32_t pc)
@@ -1882,6 +1890,14 @@ Func CPU::jit_region(uint64_t hash, unsigned pc_word, unsigned instruction_count
18821890
for (auto &b : local_branches)
18831891
jit_patch_at(b.node, branch_targets[b.local_index]);
18841892

1893+
jit_realize();
1894+
jit_word_t code_size;
1895+
jit_get_code(&code_size);
1896+
auto *block_code = allocator.allocate_code(code_size);
1897+
if (!block_code)
1898+
abort();
1899+
jit_set_code(block_code, code_size);
1900+
18851901
auto ret = reinterpret_cast<Func>(jit_emit());
18861902

18871903
#ifdef TRACE_DISASM
@@ -1891,7 +1907,10 @@ Func CPU::jit_region(uint64_t hash, unsigned pc_word, unsigned instruction_count
18911907
printf(" === DISASM END ===\n\n");
18921908
#endif
18931909
jit_clear_state();
1894-
cleanup_jit_states.push_back(_jit);
1910+
jit_destroy_state();
1911+
1912+
if (!Allocator::commit_code(block_code, code_size))
1913+
abort();
18951914
return ret;
18961915
}
18971916

‎rsp_jit.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "rsp_op.hpp"
1212
#include "state.hpp"
13+
#include "jit_allocator.hpp"
1314

1415
extern "C"
1516
{
@@ -135,8 +136,6 @@ class alignas(64) CPU
135136

136137
int enter(uint32_t pc);
137138

138-
std::vector<jit_state_t *> cleanup_jit_states;
139-
140139
void init_jit_thunks();
141140

142141
struct
@@ -198,6 +197,7 @@ class alignas(64) CPU
198197
std::vector<Link> local_branches;
199198

200199
RegisterCache regs;
200+
Allocator allocator;
201201
};
202202
} // namespace JIT
203203
} // namespace RSP

0 commit comments

Comments
 (0)
Please sign in to comment.