Commit 5cae67fb authored by Marius Wachtler's avatar Marius Wachtler

runtime ICs: use mmap instead of malloc for executable code

we should not execute memory which got allocated using malloc
(crashes a lot of memory inspection tools and also the windows subsystem for linux)
I replaced it with a trivial mmap allocator which never unmaps the memory
(but reuses the memory if a runtime ICs gets deleted)
I think this is fine for now:
- there are <100 runtime ICs used per test
- because all runtime ICs have the same size there is no problem with fragmentation
parent 81c744b5
......@@ -14,9 +14,7 @@
#include "runtime/ics.h"
#ifndef NVALGRIND
#include <sys/mman.h>
#endif
#include "asm_writing/icinfo.h"
#include "asm_writing/rewriter.h"
......@@ -188,8 +186,36 @@ static void writeTrivialEhFrame(void* eh_frame_addr, void* func_addr, uint64_t f
#define SCRATCH_BYTES 0x30
#endif
RuntimeIC::RuntimeIC(void* func_addr, int patchable_size) {
static StatCounter sc("runtime_ics_num");
template <int chunk_size> class RuntimeICMemoryManager {
private:
static constexpr int region_size = 4096;
static_assert(chunk_size < region_size, "");
static_assert(region_size % chunk_size == 0, "");
std::vector<void*> memory_regions;
llvm::SmallVector<void*, region_size / chunk_size> free_chunks;
public:
void* alloc() {
if (free_chunks.empty()) {
int protection = PROT_READ | PROT_WRITE | PROT_EXEC;
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT;
char* addr = (char*)mmap(NULL, region_size, protection, flags, -1, 0);
for (int i = 0; i < region_size / chunk_size; ++i) {
free_chunks.push_back(&addr[i * chunk_size]);
}
}
return free_chunks.pop_back_val();
}
void dealloc(void* ptr) {
free_chunks.push_back(ptr); // TODO: we should probably delete some regions if this list gets to large
}
};
static RuntimeICMemoryManager<512> memory_manager_512b;
RuntimeIC::RuntimeIC(void* func_addr, int total_size) {
static StatCounter sc("num_runtime_ics");
sc.log();
if (ENABLE_RUNTIME_ICS) {
......@@ -228,17 +254,13 @@ RuntimeIC::RuntimeIC(void* func_addr, int patchable_size) {
#endif
static const int CALL_SIZE = 13;
int total_code_size = PROLOGUE_SIZE + patchable_size + CALL_SIZE + EPILOGUE_SIZE;
int total_code_size = total_size - EH_FRAME_SIZE;
int patchable_size = total_code_size - (PROLOGUE_SIZE + CALL_SIZE + EPILOGUE_SIZE);
#ifdef NVALGRIND
int total_size = total_code_size + EH_FRAME_SIZE;
addr = malloc(total_size);
#else
total_size = total_code_size + EH_FRAME_SIZE;
addr = mmap(NULL, (total_size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
RELEASE_ASSERT(addr != MAP_FAILED, "");
#endif
assert(total_size == 512 && "we currently only have a 512 byte block memory manager");
addr = memory_manager_512b.alloc();
// the memory block contains the EH frame directly followed by the generated machine code.
void* eh_frame_addr = addr;
addr = (char*)addr + EH_FRAME_SIZE;
......@@ -302,11 +324,7 @@ RuntimeIC::~RuntimeIC() {
deregisterCompiledPatchpoint(icinfo.get());
uint8_t* eh_frame_addr = (uint8_t*)addr - EH_FRAME_SIZE;
deregisterEHFrames(eh_frame_addr, (uint64_t)eh_frame_addr, EH_FRAME_SIZE);
#ifdef NVALGRIND
free(eh_frame_addr);
#else
munmap(eh_frame_addr, total_size);
#endif
memory_manager_512b.dealloc(eh_frame_addr);
} else {
}
}
......
......@@ -25,9 +25,6 @@ class ICInfo;
class RuntimeIC {
private:
void* addr; // points to function start not the start of the allocated memory block.
#ifndef NVALGRIND
size_t total_size;
#endif
std::unique_ptr<ICInfo> icinfo;
......@@ -35,7 +32,7 @@ private:
void operator=(const RuntimeIC&) = delete;
protected:
RuntimeIC(void* addr, int patchable_size);
RuntimeIC(void* addr, int total_size);
~RuntimeIC();
template <class... Args> uint64_t call_int(Args... args) {
......@@ -57,7 +54,7 @@ protected:
class CallattrIC : public RuntimeIC {
public:
CallattrIC() : RuntimeIC((void*)callattr, 320) {}
CallattrIC() : RuntimeIC((void*)callattr, 512) {}
Box* call(Box* obj, BoxedString* attr, CallattrFlags flags, Box* arg0, Box* arg1, Box* arg2, Box** args,
const std::vector<BoxedString*>* keyword_names) {
......@@ -67,7 +64,7 @@ public:
class CallattrCapiIC : public RuntimeIC {
public:
CallattrCapiIC() : RuntimeIC((void*)callattrCapi, 320) {}
CallattrCapiIC() : RuntimeIC((void*)callattrCapi, 512) {}
Box* call(Box* obj, BoxedString* attr, CallattrFlags flags, Box* arg0, Box* arg1, Box* arg2, Box** args,
const std::vector<BoxedString*>* keyword_names) {
......@@ -78,7 +75,7 @@ public:
class BinopIC : public RuntimeIC {
public:
BinopIC() : RuntimeIC((void*)binop, 2 * 240) {}
BinopIC() : RuntimeIC((void*)binop, 512) {}
Box* call(Box* lhs, Box* rhs, int op_type) { return (Box*)call_ptr(lhs, rhs, op_type); }
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment