alternative JIT memory allocation if MAP_32BIT isn't sufficient
This commit is contained in:
parent
7600431fa6
commit
751652c392
@ -4,6 +4,7 @@
|
|||||||
#include "../utils/file.h"
|
#include "../utils/file.h"
|
||||||
#include "../utils/talloc.h"
|
#include "../utils/talloc.h"
|
||||||
#include "../utils/mut.h"
|
#include "../utils/mut.h"
|
||||||
|
#include "../utils/wyhash.h"
|
||||||
#include "../vm.h"
|
#include "../vm.h"
|
||||||
|
|
||||||
#ifndef USE_PERF
|
#ifndef USE_PERF
|
||||||
@ -24,8 +25,37 @@ u64 mmX_ctrs[64];
|
|||||||
#include "../opt/mm_buddyTemplate.h"
|
#include "../opt/mm_buddyTemplate.h"
|
||||||
#define MMI(X) X
|
#define MMI(X) X
|
||||||
#define ALSZ 17
|
#define ALSZ 17
|
||||||
#define PROT PROT_READ|PROT_WRITE|PROT_EXEC
|
|
||||||
#define FLAGS MAP_NORESERVE|MAP_PRIVATE|MAP_ANON|MAP_32BIT
|
static u64 nvm_mmap_seed = 0;
|
||||||
|
#ifdef __clang__
|
||||||
|
#if __clang_major__ < 11 // clang 10 gets stuck in an infinite loop while optimizing this
|
||||||
|
__attribute__((optnone))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
static void* mmap_nvm(u64 sz) {
|
||||||
|
u64 near = (u64)&bqn_exec;
|
||||||
|
u64 MAX_DIST = 1ULL<<30;
|
||||||
|
if (near < MAX_DIST) return mmap(NULL, sz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON|MAP_32BIT, -1, 0);
|
||||||
|
u64 ps = getPageSize();
|
||||||
|
|
||||||
|
i32 attempt = 0;
|
||||||
|
// printf("binary at %p\n", &bqn_exec);
|
||||||
|
while(true) {
|
||||||
|
if (attempt++ > 200) err("Failed to allocate memory for JIT 200 times; stopping trying");
|
||||||
|
u64 randOff = wyrand(&nvm_mmap_seed) & (MAX_DIST>>1)-1;
|
||||||
|
u64 loc = near+randOff & ~(ps-1);
|
||||||
|
// printf("request %d: %p\n", attempt, (void*)loc);
|
||||||
|
|
||||||
|
void* c = mmap((void*)loc, sz, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON|MAP_FIXED_NOREPLACE, -1, 0);
|
||||||
|
if (c==NULL) continue;
|
||||||
|
|
||||||
|
i64 dist = (i64)near - (i64)c;
|
||||||
|
if ((dist<0?-dist:dist) < MAX_DIST) return c;
|
||||||
|
munmap(c, sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MMAP(SZ) mmap_nvm(sz);
|
||||||
#include "../opt/mm_buddyTemplate.c"
|
#include "../opt/mm_buddyTemplate.c"
|
||||||
static void* mmX_allocN(usz sz, u8 type) { assert(sz>=16); return mmX_allocL(64-CLZ(sz-1ull), type); }
|
static void* mmX_allocN(usz sz, u8 type) { assert(sz>=16); return mmX_allocL(64-CLZ(sz-1ull), type); }
|
||||||
#undef BN
|
#undef BN
|
||||||
@ -512,8 +542,7 @@ Nvm_res m_nvm(Body* body) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((u64)i_RETD > I32_MAX || (u64)&gStack > I32_MAX || (u64)&envEnd > I32_MAX) thrM("JIT: Refusing to run with CBQN code outside of the 32-bit address range");
|
#define CCALL(F) CALLi((u64)(F))
|
||||||
#define CCALL(F) { u64 f=(u64)(F); if(f>I32_MAX)thrM("JIT: Function address too large for call"); CALLi(f); }
|
|
||||||
u32* origBC = body->bc;
|
u32* origBC = body->bc;
|
||||||
OptRes optRes = opt(origBC);
|
OptRes optRes = opt(origBC);
|
||||||
i32 depth = 0;
|
i32 depth = 0;
|
||||||
|
|||||||
@ -500,6 +500,6 @@ ASMI(PUSH, Reg O) { nREX4(O,0); ASM1(0x50+((O)&7)); }
|
|||||||
ASMI(POP , Reg O) { nREX4(O,0); ASM1(0x58+((O)&7)); }
|
ASMI(POP , Reg O) { nREX4(O,0); ASM1(0x58+((O)&7)); }
|
||||||
|
|
||||||
ASMI(CALL, Reg i) { nREX4(i,0); ASM1(0xFF); nA_REG(i,2); }
|
ASMI(CALL, Reg i) { nREX4(i,0); ASM1(0xFF); nA_REG(i,2); }
|
||||||
ASMI(CALLi, u64 pos) { ASM1(0xE8); if (pos>I32_MAX)err("immediate call outside of 32-bit range!"); ASM4(pos-4); }
|
ASMI(CALLi, u64 pos) { ASM1(0xE8); ASM4(pos-4); }
|
||||||
|
|
||||||
#define IMM(A,B) MOVi(A,(u64)(B))
|
#define IMM(A,B) MOVi(A,(u64)(B))
|
||||||
|
|||||||
@ -4,11 +4,8 @@
|
|||||||
#define alCap BN(alCap)
|
#define alCap BN(alCap)
|
||||||
#define alSize BN(alSize)
|
#define alSize BN(alSize)
|
||||||
#define str(X) #X
|
#define str(X) #X
|
||||||
#ifndef PROT
|
#ifndef MMAP
|
||||||
#define PROT PROT_READ|PROT_WRITE
|
#define MMAP(SZ) mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0)
|
||||||
#endif
|
|
||||||
#ifndef FLAGS
|
|
||||||
#define FLAGS MAP_NORESERVE|MAP_PRIVATE|MAP_ANON
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct AllocInfo {
|
typedef struct AllocInfo {
|
||||||
@ -35,7 +32,7 @@ static inline void BN(guaranteeEmpty)(u8 bucket) {
|
|||||||
if (mm_heapAlloc+sz >= mm_heapMax) { printf("Heap size limit reached\n"); exit(1); }
|
if (mm_heapAlloc+sz >= mm_heapMax) { printf("Heap size limit reached\n"); exit(1); }
|
||||||
mm_heapAlloc+= sz;
|
mm_heapAlloc+= sz;
|
||||||
// gc_maybeGC();
|
// gc_maybeGC();
|
||||||
c = mmap(NULL, sz, PROT, FLAGS, -1, 0);
|
c = MMAP(sz);
|
||||||
#ifdef USE_VALGRIND
|
#ifdef USE_VALGRIND
|
||||||
VALGRIND_MAKE_MEM_UNDEFINED(c, sz);
|
VALGRIND_MAKE_MEM_UNDEFINED(c, sz);
|
||||||
#endif
|
#endif
|
||||||
@ -80,8 +77,7 @@ void BN(forHeap)(V2v f) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef FLAGS
|
#undef MMAP
|
||||||
#undef PROT
|
|
||||||
#undef AllocInfo
|
#undef AllocInfo
|
||||||
#undef buckets
|
#undef buckets
|
||||||
#undef al
|
#undef al
|
||||||
|
|||||||
13
src/vm.c
13
src/vm.c
@ -935,13 +935,18 @@ B block_decompose(B x) { return m_v2(m_i32(1), x); }
|
|||||||
B bl_m1d(B m, B f ) { Md1Block* c = c(Md1Block,m); Block* bl=c(Md1Block, m)->bl; return c->bl->imm? execBlock(bl, bl->bodies[0], c(Md1Block, m)->sc, 2, (B[]){m, f }) : m_md1D(m,f ); }
|
B bl_m1d(B m, B f ) { Md1Block* c = c(Md1Block,m); Block* bl=c(Md1Block, m)->bl; return c->bl->imm? execBlock(bl, bl->bodies[0], c(Md1Block, m)->sc, 2, (B[]){m, f }) : m_md1D(m,f ); }
|
||||||
B bl_m2d(B m, B f, B g) { Md2Block* c = c(Md2Block,m); Block* bl=c(Md2Block, m)->bl; return c->bl->imm? execBlock(bl, bl->bodies[0], c(Md2Block, m)->sc, 3, (B[]){m, f, g}) : m_md2D(m,f,g); }
|
B bl_m2d(B m, B f, B g) { Md2Block* c = c(Md2Block,m); Block* bl=c(Md2Block, m)->bl; return c->bl->imm? execBlock(bl, bl->bodies[0], c(Md2Block, m)->sc, 3, (B[]){m, f, g}) : m_md2D(m,f,g); }
|
||||||
|
|
||||||
|
static usz pageSizeV;
|
||||||
|
usz getPageSize() {
|
||||||
|
if (pageSizeV==0) pageSizeV = sysconf(_SC_PAGESIZE);
|
||||||
|
return pageSizeV;
|
||||||
|
}
|
||||||
void allocStack(void** curr, void** start, void** end, i32 elSize, i32 count) {
|
void allocStack(void** curr, void** start, void** end, i32 elSize, i32 count) {
|
||||||
usz pageSize = sysconf(_SC_PAGESIZE);
|
usz ps = getPageSize();
|
||||||
u64 sz = (elSize*count + pageSize-1)/pageSize * pageSize;
|
u64 sz = (elSize*count + ps-1)/ps * ps;
|
||||||
assert(sz%elSize == 0);
|
assert(sz%elSize == 0);
|
||||||
*curr = *start = mmap(NULL, sz+pageSize, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0);
|
*curr = *start = mmap(NULL, sz+ps, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0);
|
||||||
*end = ((char*)*start)+sz;
|
*end = ((char*)*start)+sz;
|
||||||
mprotect(*end, pageSize, PROT_NONE); // idk first way i found to force erroring on overflow
|
mprotect(*end, ps, PROT_NONE); // idk first way i found to force erroring on overflow
|
||||||
}
|
}
|
||||||
void print_vmStack() {
|
void print_vmStack() {
|
||||||
#ifdef DEBUG_VM
|
#ifdef DEBUG_VM
|
||||||
|
|||||||
1
src/vm.h
1
src/vm.h
@ -231,6 +231,7 @@ NOINLINE B vm_fmtPoint(B src, B prepend, B path, usz cs, usz ce); // consumes pr
|
|||||||
NOINLINE void printErrMsg(B msg);
|
NOINLINE void printErrMsg(B msg);
|
||||||
NOINLINE void unwindEnv(Env* envNew); // envNew==envStart-1 for emptying the env stack
|
NOINLINE void unwindEnv(Env* envNew); // envNew==envStart-1 for emptying the env stack
|
||||||
NOINLINE void unwindCompiler(void); // unwind to the env of the invocation of the compiler; UB when not in compiler!
|
NOINLINE void unwindCompiler(void); // unwind to the env of the invocation of the compiler; UB when not in compiler!
|
||||||
|
usz getPageSize();
|
||||||
|
|
||||||
|
|
||||||
typedef struct FldAlias {
|
typedef struct FldAlias {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user