diff options
Diffstat (limited to 'src/lj_alloc.c')
| -rw-r--r-- | src/lj_alloc.c | 275 |
1 files changed, 182 insertions, 93 deletions
diff --git a/src/lj_alloc.c b/src/lj_alloc.c index 0c0c0c4f..f4d3a7da 100644 --- a/src/lj_alloc.c +++ b/src/lj_alloc.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include "lj_def.h" | 31 | #include "lj_def.h" |
| 32 | #include "lj_arch.h" | 32 | #include "lj_arch.h" |
| 33 | #include "lj_alloc.h" | 33 | #include "lj_alloc.h" |
| 34 | #include "lj_prng.h" | ||
| 34 | 35 | ||
| 35 | #ifndef LUAJIT_USE_SYSMALLOC | 36 | #ifndef LUAJIT_USE_SYSMALLOC |
| 36 | 37 | ||
| @@ -72,15 +73,58 @@ | |||
| 72 | 73 | ||
| 73 | #define IS_DIRECT_BIT (SIZE_T_ONE) | 74 | #define IS_DIRECT_BIT (SIZE_T_ONE) |
| 74 | 75 | ||
| 76 | |||
| 77 | /* Determine system-specific block allocation method. */ | ||
| 75 | #if LJ_TARGET_WINDOWS | 78 | #if LJ_TARGET_WINDOWS |
| 76 | 79 | ||
| 77 | #define WIN32_LEAN_AND_MEAN | 80 | #define WIN32_LEAN_AND_MEAN |
| 78 | #include <windows.h> | 81 | #include <windows.h> |
| 79 | 82 | ||
| 83 | #define LJ_ALLOC_VIRTUALALLOC 1 | ||
| 84 | |||
| 85 | #if LJ_64 && !LJ_GC64 | ||
| 86 | #define LJ_ALLOC_NTAVM 1 | ||
| 87 | #endif | ||
| 88 | |||
| 89 | #else | ||
| 90 | |||
| 91 | #include <errno.h> | ||
| 92 | /* If this include fails, then rebuild with: -DLUAJIT_USE_SYSMALLOC */ | ||
| 93 | #include <sys/mman.h> | ||
| 94 | |||
| 95 | #define LJ_ALLOC_MMAP 1 | ||
| 96 | |||
| 80 | #if LJ_64 | 97 | #if LJ_64 |
| 81 | 98 | ||
| 99 | #define LJ_ALLOC_MMAP_PROBE 1 | ||
| 100 | |||
| 101 | #if LJ_GC64 | ||
| 102 | #define LJ_ALLOC_MBITS 47 /* 128 TB in LJ_GC64 mode. */ | ||
| 103 | #elif LJ_TARGET_X64 | ||
| 104 | /* Due to limitations in the x64 non-GC64 VM. */ | ||
| 105 | #define LJ_ALLOC_MBITS 31 /* 2 GB on x64 with !LJ_GC64. */ | ||
| 106 | #else | ||
| 107 | #define LJ_ALLOC_MBITS 32 /* 4 GB on other archs with !LJ_GC64. */ | ||
| 108 | #endif | ||
| 109 | |||
| 110 | #endif | ||
| 111 | |||
| 112 | #if LJ_64 && !LJ_GC64 && defined(MAP_32BIT) | ||
| 113 | #define LJ_ALLOC_MMAP32 1 | ||
| 114 | #endif | ||
| 115 | |||
| 116 | #if LJ_TARGET_LINUX | ||
| 117 | #define LJ_ALLOC_MREMAP 1 | ||
| 118 | #endif | ||
| 119 | |||
| 120 | #endif | ||
| 121 | |||
| 122 | |||
| 123 | #if LJ_ALLOC_VIRTUALALLOC | ||
| 124 | |||
| 125 | #if LJ_ALLOC_NTAVM | ||
| 82 | /* Undocumented, but hey, that's what we all love so much about Windows. */ | 126 | /* Undocumented, but hey, that's what we all love so much about Windows. */ |
| 83 | typedef long (*PNTAVM)(HANDLE handle, void **addr, ULONG zbits, | 127 | typedef long (*PNTAVM)(HANDLE handle, void **addr, ULONG_PTR zbits, |
| 84 | size_t *size, ULONG alloctype, ULONG prot); | 128 | size_t *size, ULONG alloctype, ULONG prot); |
| 85 | static PNTAVM ntavm; | 129 | static PNTAVM ntavm; |
| 86 | 130 | ||
| @@ -89,14 +133,15 @@ static PNTAVM ntavm; | |||
| 89 | */ | 133 | */ |
| 90 | #define NTAVM_ZEROBITS 1 | 134 | #define NTAVM_ZEROBITS 1 |
| 91 | 135 | ||
| 92 | static void INIT_MMAP(void) | 136 | static void init_mmap(void) |
| 93 | { | 137 | { |
| 94 | ntavm = (PNTAVM)GetProcAddress(GetModuleHandleA("ntdll.dll"), | 138 | ntavm = (PNTAVM)GetProcAddress(GetModuleHandleA("ntdll.dll"), |
| 95 | "NtAllocateVirtualMemory"); | 139 | "NtAllocateVirtualMemory"); |
| 96 | } | 140 | } |
| 141 | #define INIT_MMAP() init_mmap() | ||
| 97 | 142 | ||
| 98 | /* Win64 32 bit MMAP via NtAllocateVirtualMemory. */ | 143 | /* Win64 32 bit MMAP via NtAllocateVirtualMemory. */ |
| 99 | static LJ_AINLINE void *CALL_MMAP(size_t size) | 144 | static void *mmap_plain(size_t size) |
| 100 | { | 145 | { |
| 101 | DWORD olderr = GetLastError(); | 146 | DWORD olderr = GetLastError(); |
| 102 | void *ptr = NULL; | 147 | void *ptr = NULL; |
| @@ -107,7 +152,7 @@ static LJ_AINLINE void *CALL_MMAP(size_t size) | |||
| 107 | } | 152 | } |
| 108 | 153 | ||
| 109 | /* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ | 154 | /* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ |
| 110 | static LJ_AINLINE void *DIRECT_MMAP(size_t size) | 155 | static void *direct_mmap(size_t size) |
| 111 | { | 156 | { |
| 112 | DWORD olderr = GetLastError(); | 157 | DWORD olderr = GetLastError(); |
| 113 | void *ptr = NULL; | 158 | void *ptr = NULL; |
| @@ -119,31 +164,32 @@ static LJ_AINLINE void *DIRECT_MMAP(size_t size) | |||
| 119 | 164 | ||
| 120 | #else | 165 | #else |
| 121 | 166 | ||
| 122 | #define INIT_MMAP() ((void)0) | ||
| 123 | |||
| 124 | /* Win32 MMAP via VirtualAlloc */ | 167 | /* Win32 MMAP via VirtualAlloc */ |
| 125 | static LJ_AINLINE void *CALL_MMAP(size_t size) | 168 | static void *mmap_plain(size_t size) |
| 126 | { | 169 | { |
| 127 | DWORD olderr = GetLastError(); | 170 | DWORD olderr = GetLastError(); |
| 128 | void *ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); | 171 | void *ptr = LJ_WIN_VALLOC(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); |
| 129 | SetLastError(olderr); | 172 | SetLastError(olderr); |
| 130 | return ptr ? ptr : MFAIL; | 173 | return ptr ? ptr : MFAIL; |
| 131 | } | 174 | } |
| 132 | 175 | ||
| 133 | /* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ | 176 | /* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ |
| 134 | static LJ_AINLINE void *DIRECT_MMAP(size_t size) | 177 | static void *direct_mmap(size_t size) |
| 135 | { | 178 | { |
| 136 | DWORD olderr = GetLastError(); | 179 | DWORD olderr = GetLastError(); |
| 137 | void *ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, | 180 | void *ptr = LJ_WIN_VALLOC(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, |
| 138 | PAGE_READWRITE); | 181 | PAGE_READWRITE); |
| 139 | SetLastError(olderr); | 182 | SetLastError(olderr); |
| 140 | return ptr ? ptr : MFAIL; | 183 | return ptr ? ptr : MFAIL; |
| 141 | } | 184 | } |
| 142 | 185 | ||
| 143 | #endif | 186 | #endif |
| 144 | 187 | ||
| 188 | #define CALL_MMAP(prng, size) mmap_plain(size) | ||
| 189 | #define DIRECT_MMAP(prng, size) direct_mmap(size) | ||
| 190 | |||
| 145 | /* This function supports releasing coalesed segments */ | 191 | /* This function supports releasing coalesed segments */ |
| 146 | static LJ_AINLINE int CALL_MUNMAP(void *ptr, size_t size) | 192 | static int CALL_MUNMAP(void *ptr, size_t size) |
| 147 | { | 193 | { |
| 148 | DWORD olderr = GetLastError(); | 194 | DWORD olderr = GetLastError(); |
| 149 | MEMORY_BASIC_INFORMATION minfo; | 195 | MEMORY_BASIC_INFORMATION minfo; |
| @@ -163,10 +209,7 @@ static LJ_AINLINE int CALL_MUNMAP(void *ptr, size_t size) | |||
| 163 | return 0; | 209 | return 0; |
| 164 | } | 210 | } |
| 165 | 211 | ||
| 166 | #else | 212 | #elif LJ_ALLOC_MMAP |
| 167 | |||
| 168 | #include <errno.h> | ||
| 169 | #include <sys/mman.h> | ||
| 170 | 213 | ||
| 171 | #define MMAP_PROT (PROT_READ|PROT_WRITE) | 214 | #define MMAP_PROT (PROT_READ|PROT_WRITE) |
| 172 | #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) | 215 | #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
| @@ -174,105 +217,134 @@ static LJ_AINLINE int CALL_MUNMAP(void *ptr, size_t size) | |||
| 174 | #endif | 217 | #endif |
| 175 | #define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) | 218 | #define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) |
| 176 | 219 | ||
| 177 | #if LJ_64 | 220 | #if LJ_ALLOC_MMAP_PROBE |
| 178 | /* 64 bit mode needs special support for allocating memory in the lower 2GB. */ | ||
| 179 | 221 | ||
| 180 | #if defined(MAP_32BIT) | 222 | #ifdef MAP_TRYFIXED |
| 181 | 223 | #define MMAP_FLAGS_PROBE (MMAP_FLAGS|MAP_TRYFIXED) | |
| 182 | #if defined(__sun__) | ||
| 183 | #define MMAP_REGION_START ((uintptr_t)0x1000) | ||
| 184 | #else | 224 | #else |
| 185 | /* Actually this only gives us max. 1GB in current Linux kernels. */ | 225 | #define MMAP_FLAGS_PROBE MMAP_FLAGS |
| 186 | #define MMAP_REGION_START ((uintptr_t)0) | ||
| 187 | #endif | 226 | #endif |
| 188 | 227 | ||
| 189 | static LJ_AINLINE void *CALL_MMAP(size_t size) | 228 | #define LJ_ALLOC_MMAP_PROBE_MAX 30 |
| 229 | #define LJ_ALLOC_MMAP_PROBE_LINEAR 5 | ||
| 230 | |||
| 231 | #define LJ_ALLOC_MMAP_PROBE_LOWER ((uintptr_t)0x4000) | ||
| 232 | |||
| 233 | static void *mmap_probe(PRNGState *rs, size_t size) | ||
| 190 | { | 234 | { |
| 235 | /* Hint for next allocation. Doesn't need to be thread-safe. */ | ||
| 236 | static uintptr_t hint_addr = 0; | ||
| 191 | int olderr = errno; | 237 | int olderr = errno; |
| 192 | void *ptr = mmap((void *)MMAP_REGION_START, size, MMAP_PROT, MAP_32BIT|MMAP_FLAGS, -1, 0); | 238 | int retry; |
| 239 | for (retry = 0; retry < LJ_ALLOC_MMAP_PROBE_MAX; retry++) { | ||
| 240 | void *p = mmap((void *)hint_addr, size, MMAP_PROT, MMAP_FLAGS_PROBE, -1, 0); | ||
| 241 | uintptr_t addr = (uintptr_t)p; | ||
| 242 | if ((addr >> LJ_ALLOC_MBITS) == 0 && addr >= LJ_ALLOC_MMAP_PROBE_LOWER && | ||
| 243 | ((addr + size) >> LJ_ALLOC_MBITS) == 0) { | ||
| 244 | /* We got a suitable address. Bump the hint address. */ | ||
| 245 | hint_addr = addr + size; | ||
| 246 | errno = olderr; | ||
| 247 | return p; | ||
| 248 | } | ||
| 249 | if (p != MFAIL) { | ||
| 250 | munmap(p, size); | ||
| 251 | } else if (errno == ENOMEM) { | ||
| 252 | return MFAIL; | ||
| 253 | } | ||
| 254 | if (hint_addr) { | ||
| 255 | /* First, try linear probing. */ | ||
| 256 | if (retry < LJ_ALLOC_MMAP_PROBE_LINEAR) { | ||
| 257 | hint_addr += 0x1000000; | ||
| 258 | if (((hint_addr + size) >> LJ_ALLOC_MBITS) != 0) | ||
| 259 | hint_addr = 0; | ||
| 260 | continue; | ||
| 261 | } else if (retry == LJ_ALLOC_MMAP_PROBE_LINEAR) { | ||
| 262 | /* Next, try a no-hint probe to get back an ASLR address. */ | ||
| 263 | hint_addr = 0; | ||
| 264 | continue; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | /* Finally, try pseudo-random probing. */ | ||
| 268 | do { | ||
| 269 | hint_addr = lj_prng_u64(rs) & (((uintptr_t)1<<LJ_ALLOC_MBITS)-LJ_PAGESIZE); | ||
| 270 | } while (hint_addr < LJ_ALLOC_MMAP_PROBE_LOWER); | ||
| 271 | } | ||
| 193 | errno = olderr; | 272 | errno = olderr; |
| 194 | return ptr; | 273 | return MFAIL; |
| 195 | } | 274 | } |
| 196 | 275 | ||
| 197 | #elif LJ_TARGET_OSX || LJ_TARGET_PS4 || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun__) || LJ_TARGET_CYGWIN | 276 | #endif |
| 277 | |||
| 278 | #if LJ_ALLOC_MMAP32 | ||
| 198 | 279 | ||
| 199 | /* OSX and FreeBSD mmap() use a naive first-fit linear search. | 280 | #if LJ_TARGET_SOLARIS |
| 200 | ** That's perfect for us. Except that -pagezero_size must be set for OSX, | 281 | #define LJ_ALLOC_MMAP32_START ((uintptr_t)0x1000) |
| 201 | ** otherwise the lower 4GB are blocked. And the 32GB RLIMIT_DATA needs | ||
| 202 | ** to be reduced to 250MB on FreeBSD. | ||
| 203 | */ | ||
| 204 | #if LJ_TARGET_OSX || defined(__DragonFly__) | ||
| 205 | #define MMAP_REGION_START ((uintptr_t)0x10000) | ||
| 206 | #elif LJ_TARGET_PS4 | ||
| 207 | #define MMAP_REGION_START ((uintptr_t)0x4000) | ||
| 208 | #else | 282 | #else |
| 209 | #define MMAP_REGION_START ((uintptr_t)0x10000000) | 283 | #define LJ_ALLOC_MMAP32_START ((uintptr_t)0) |
| 210 | #endif | 284 | #endif |
| 211 | #define MMAP_REGION_END ((uintptr_t)0x80000000) | ||
| 212 | 285 | ||
| 213 | #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && !LJ_TARGET_PS4 | 286 | #if LJ_ALLOC_MMAP_PROBE |
| 214 | #include <sys/resource.h> | 287 | static void *mmap_map32(PRNGState *rs, size_t size) |
| 288 | #else | ||
| 289 | static void *mmap_map32(size_t size) | ||
| 215 | #endif | 290 | #endif |
| 216 | |||
| 217 | static LJ_AINLINE void *CALL_MMAP(size_t size) | ||
| 218 | { | 291 | { |
| 219 | int olderr = errno; | 292 | #if LJ_ALLOC_MMAP_PROBE |
| 220 | /* Hint for next allocation. Doesn't need to be thread-safe. */ | 293 | static int fallback = 0; |
| 221 | static uintptr_t alloc_hint = MMAP_REGION_START; | 294 | if (fallback) |
| 222 | int retry = 0; | 295 | return mmap_probe(rs, size); |
| 223 | #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && !LJ_TARGET_PS4 | ||
| 224 | static int rlimit_modified = 0; | ||
| 225 | if (LJ_UNLIKELY(rlimit_modified == 0)) { | ||
| 226 | struct rlimit rlim; | ||
| 227 | rlim.rlim_cur = rlim.rlim_max = MMAP_REGION_START; | ||
| 228 | setrlimit(RLIMIT_DATA, &rlim); /* Ignore result. May fail below. */ | ||
| 229 | rlimit_modified = 1; | ||
| 230 | } | ||
| 231 | #endif | 296 | #endif |
| 232 | for (;;) { | 297 | { |
| 233 | void *p = mmap((void *)alloc_hint, size, MMAP_PROT, MMAP_FLAGS, -1, 0); | 298 | int olderr = errno; |
| 234 | if ((uintptr_t)p >= MMAP_REGION_START && | 299 | void *ptr = mmap((void *)LJ_ALLOC_MMAP32_START, size, MMAP_PROT, MAP_32BIT|MMAP_FLAGS, -1, 0); |
| 235 | (uintptr_t)p + size < MMAP_REGION_END) { | 300 | errno = olderr; |
| 236 | alloc_hint = (uintptr_t)p + size; | 301 | /* This only allows 1GB on Linux. So fallback to probing to get 2GB. */ |
| 237 | errno = olderr; | 302 | #if LJ_ALLOC_MMAP_PROBE |
| 238 | return p; | 303 | if (ptr == MFAIL) { |
| 304 | fallback = 1; | ||
| 305 | return mmap_probe(rs, size); | ||
| 239 | } | 306 | } |
| 240 | if (p != CMFAIL) munmap(p, size); | ||
| 241 | #if defined(__sun__) || defined(__DragonFly__) | ||
| 242 | alloc_hint += 0x1000000; /* Need near-exhaustive linear scan. */ | ||
| 243 | if (alloc_hint + size < MMAP_REGION_END) continue; | ||
| 244 | #endif | 307 | #endif |
| 245 | if (retry) break; | 308 | return ptr; |
| 246 | retry = 1; | ||
| 247 | alloc_hint = MMAP_REGION_START; | ||
| 248 | } | 309 | } |
| 249 | errno = olderr; | ||
| 250 | return CMFAIL; | ||
| 251 | } | 310 | } |
| 252 | 311 | ||
| 253 | #else | ||
| 254 | |||
| 255 | #error "NYI: need an equivalent of MAP_32BIT for this 64 bit OS" | ||
| 256 | |||
| 257 | #endif | 312 | #endif |
| 258 | 313 | ||
| 314 | #if LJ_ALLOC_MMAP32 | ||
| 315 | #if LJ_ALLOC_MMAP_PROBE | ||
| 316 | #define CALL_MMAP(prng, size) mmap_map32(prng, size) | ||
| 259 | #else | 317 | #else |
| 260 | 318 | #define CALL_MMAP(prng, size) mmap_map32(size) | |
| 261 | /* 32 bit mode is easy. */ | 319 | #endif |
| 262 | static LJ_AINLINE void *CALL_MMAP(size_t size) | 320 | #elif LJ_ALLOC_MMAP_PROBE |
| 321 | #define CALL_MMAP(prng, size) mmap_probe(prng, size) | ||
| 322 | #else | ||
| 323 | static void *mmap_plain(size_t size) | ||
| 263 | { | 324 | { |
| 264 | int olderr = errno; | 325 | int olderr = errno; |
| 265 | void *ptr = mmap(NULL, size, MMAP_PROT, MMAP_FLAGS, -1, 0); | 326 | void *ptr = mmap(NULL, size, MMAP_PROT, MMAP_FLAGS, -1, 0); |
| 266 | errno = olderr; | 327 | errno = olderr; |
| 267 | return ptr; | 328 | return ptr; |
| 268 | } | 329 | } |
| 269 | 330 | #define CALL_MMAP(prng, size) mmap_plain(size) | |
| 270 | #endif | 331 | #endif |
| 271 | 332 | ||
| 272 | #define INIT_MMAP() ((void)0) | 333 | #if LJ_64 && !LJ_GC64 && ((defined(__FreeBSD__) && __FreeBSD__ < 10) || defined(__FreeBSD_kernel__)) && !LJ_TARGET_PS4 && !LJ_TARGET_PS5 |
| 273 | #define DIRECT_MMAP(s) CALL_MMAP(s) | 334 | |
| 335 | #include <sys/resource.h> | ||
| 274 | 336 | ||
| 275 | static LJ_AINLINE int CALL_MUNMAP(void *ptr, size_t size) | 337 | static void init_mmap(void) |
| 338 | { | ||
| 339 | struct rlimit rlim; | ||
| 340 | rlim.rlim_cur = rlim.rlim_max = 0x10000; | ||
| 341 | setrlimit(RLIMIT_DATA, &rlim); /* Ignore result. May fail later. */ | ||
| 342 | } | ||
| 343 | #define INIT_MMAP() init_mmap() | ||
| 344 | |||
| 345 | #endif | ||
| 346 | |||
| 347 | static int CALL_MUNMAP(void *ptr, size_t size) | ||
| 276 | { | 348 | { |
| 277 | int olderr = errno; | 349 | int olderr = errno; |
| 278 | int ret = munmap(ptr, size); | 350 | int ret = munmap(ptr, size); |
| @@ -280,10 +352,9 @@ static LJ_AINLINE int CALL_MUNMAP(void *ptr, size_t size) | |||
| 280 | return ret; | 352 | return ret; |
| 281 | } | 353 | } |
| 282 | 354 | ||
| 283 | #if LJ_TARGET_LINUX | 355 | #if LJ_ALLOC_MREMAP |
| 284 | /* Need to define _GNU_SOURCE to get the mremap prototype. */ | 356 | /* Need to define _GNU_SOURCE to get the mremap prototype. */ |
| 285 | static LJ_AINLINE void *CALL_MREMAP_(void *ptr, size_t osz, size_t nsz, | 357 | static void *CALL_MREMAP_(void *ptr, size_t osz, size_t nsz, int flags) |
| 286 | int flags) | ||
| 287 | { | 358 | { |
| 288 | int olderr = errno; | 359 | int olderr = errno; |
| 289 | ptr = mremap(ptr, osz, nsz, flags); | 360 | ptr = mremap(ptr, osz, nsz, flags); |
| @@ -294,7 +365,7 @@ static LJ_AINLINE void *CALL_MREMAP_(void *ptr, size_t osz, size_t nsz, | |||
| 294 | #define CALL_MREMAP(addr, osz, nsz, mv) CALL_MREMAP_((addr), (osz), (nsz), (mv)) | 365 | #define CALL_MREMAP(addr, osz, nsz, mv) CALL_MREMAP_((addr), (osz), (nsz), (mv)) |
| 295 | #define CALL_MREMAP_NOMOVE 0 | 366 | #define CALL_MREMAP_NOMOVE 0 |
| 296 | #define CALL_MREMAP_MAYMOVE 1 | 367 | #define CALL_MREMAP_MAYMOVE 1 |
| 297 | #if LJ_64 | 368 | #if LJ_64 && (!LJ_GC64 || LJ_TARGET_ARM64) |
| 298 | #define CALL_MREMAP_MV CALL_MREMAP_NOMOVE | 369 | #define CALL_MREMAP_MV CALL_MREMAP_NOMOVE |
| 299 | #else | 370 | #else |
| 300 | #define CALL_MREMAP_MV CALL_MREMAP_MAYMOVE | 371 | #define CALL_MREMAP_MV CALL_MREMAP_MAYMOVE |
| @@ -303,6 +374,15 @@ static LJ_AINLINE void *CALL_MREMAP_(void *ptr, size_t osz, size_t nsz, | |||
| 303 | 374 | ||
| 304 | #endif | 375 | #endif |
| 305 | 376 | ||
| 377 | |||
| 378 | #ifndef INIT_MMAP | ||
| 379 | #define INIT_MMAP() ((void)0) | ||
| 380 | #endif | ||
| 381 | |||
| 382 | #ifndef DIRECT_MMAP | ||
| 383 | #define DIRECT_MMAP(prng, s) CALL_MMAP(prng, s) | ||
| 384 | #endif | ||
| 385 | |||
| 306 | #ifndef CALL_MREMAP | 386 | #ifndef CALL_MREMAP |
| 307 | #define CALL_MREMAP(addr, osz, nsz, mv) ((void)osz, MFAIL) | 387 | #define CALL_MREMAP(addr, osz, nsz, mv) ((void)osz, MFAIL) |
| 308 | #endif | 388 | #endif |
| @@ -459,6 +539,7 @@ struct malloc_state { | |||
| 459 | mchunkptr smallbins[(NSMALLBINS+1)*2]; | 539 | mchunkptr smallbins[(NSMALLBINS+1)*2]; |
| 460 | tbinptr treebins[NTREEBINS]; | 540 | tbinptr treebins[NTREEBINS]; |
| 461 | msegment seg; | 541 | msegment seg; |
| 542 | PRNGState *prng; | ||
| 462 | }; | 543 | }; |
| 463 | 544 | ||
| 464 | typedef struct malloc_state *mstate; | 545 | typedef struct malloc_state *mstate; |
| @@ -516,7 +597,7 @@ static int has_segment_link(mstate m, msegmentptr ss) | |||
| 516 | noncontiguous segments are added. | 597 | noncontiguous segments are added. |
| 517 | */ | 598 | */ |
| 518 | #define TOP_FOOT_SIZE\ | 599 | #define TOP_FOOT_SIZE\ |
| 519 | (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) | 600 | (align_offset(TWO_SIZE_T_SIZES)+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) |
| 520 | 601 | ||
| 521 | /* ---------------------------- Indexing Bins ---------------------------- */ | 602 | /* ---------------------------- Indexing Bins ---------------------------- */ |
| 522 | 603 | ||
| @@ -741,11 +822,11 @@ static int has_segment_link(mstate m, msegmentptr ss) | |||
| 741 | 822 | ||
| 742 | /* ----------------------- Direct-mmapping chunks ----------------------- */ | 823 | /* ----------------------- Direct-mmapping chunks ----------------------- */ |
| 743 | 824 | ||
| 744 | static void *direct_alloc(size_t nb) | 825 | static void *direct_alloc(mstate m, size_t nb) |
| 745 | { | 826 | { |
| 746 | size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); | 827 | size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); |
| 747 | if (LJ_LIKELY(mmsize > nb)) { /* Check for wrap around 0 */ | 828 | if (LJ_LIKELY(mmsize > nb)) { /* Check for wrap around 0 */ |
| 748 | char *mm = (char *)(DIRECT_MMAP(mmsize)); | 829 | char *mm = (char *)(DIRECT_MMAP(m->prng, mmsize)); |
| 749 | if (mm != CMFAIL) { | 830 | if (mm != CMFAIL) { |
| 750 | size_t offset = align_offset(chunk2mem(mm)); | 831 | size_t offset = align_offset(chunk2mem(mm)); |
| 751 | size_t psize = mmsize - offset - DIRECT_FOOT_PAD; | 832 | size_t psize = mmsize - offset - DIRECT_FOOT_PAD; |
| @@ -757,6 +838,7 @@ static void *direct_alloc(size_t nb) | |||
| 757 | return chunk2mem(p); | 838 | return chunk2mem(p); |
| 758 | } | 839 | } |
| 759 | } | 840 | } |
| 841 | UNUSED(m); | ||
| 760 | return NULL; | 842 | return NULL; |
| 761 | } | 843 | } |
| 762 | 844 | ||
| @@ -905,7 +987,7 @@ static void *alloc_sys(mstate m, size_t nb) | |||
| 905 | 987 | ||
| 906 | /* Directly map large chunks */ | 988 | /* Directly map large chunks */ |
| 907 | if (LJ_UNLIKELY(nb >= DEFAULT_MMAP_THRESHOLD)) { | 989 | if (LJ_UNLIKELY(nb >= DEFAULT_MMAP_THRESHOLD)) { |
| 908 | void *mem = direct_alloc(nb); | 990 | void *mem = direct_alloc(m, nb); |
| 909 | if (mem != 0) | 991 | if (mem != 0) |
| 910 | return mem; | 992 | return mem; |
| 911 | } | 993 | } |
| @@ -914,7 +996,7 @@ static void *alloc_sys(mstate m, size_t nb) | |||
| 914 | size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; | 996 | size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; |
| 915 | size_t rsize = granularity_align(req); | 997 | size_t rsize = granularity_align(req); |
| 916 | if (LJ_LIKELY(rsize > nb)) { /* Fail if wraps around zero */ | 998 | if (LJ_LIKELY(rsize > nb)) { /* Fail if wraps around zero */ |
| 917 | char *mp = (char *)(CALL_MMAP(rsize)); | 999 | char *mp = (char *)(CALL_MMAP(m->prng, rsize)); |
| 918 | if (mp != CMFAIL) { | 1000 | if (mp != CMFAIL) { |
| 919 | tbase = mp; | 1001 | tbase = mp; |
| 920 | tsize = rsize; | 1002 | tsize = rsize; |
| @@ -1141,12 +1223,13 @@ static void *tmalloc_small(mstate m, size_t nb) | |||
| 1141 | 1223 | ||
| 1142 | /* ----------------------------------------------------------------------- */ | 1224 | /* ----------------------------------------------------------------------- */ |
| 1143 | 1225 | ||
| 1144 | void *lj_alloc_create(void) | 1226 | void *lj_alloc_create(PRNGState *rs) |
| 1145 | { | 1227 | { |
| 1146 | size_t tsize = DEFAULT_GRANULARITY; | 1228 | size_t tsize = DEFAULT_GRANULARITY; |
| 1147 | char *tbase; | 1229 | char *tbase; |
| 1148 | INIT_MMAP(); | 1230 | INIT_MMAP(); |
| 1149 | tbase = (char *)(CALL_MMAP(tsize)); | 1231 | UNUSED(rs); |
| 1232 | tbase = (char *)(CALL_MMAP(rs, tsize)); | ||
| 1150 | if (tbase != CMFAIL) { | 1233 | if (tbase != CMFAIL) { |
| 1151 | size_t msize = pad_request(sizeof(struct malloc_state)); | 1234 | size_t msize = pad_request(sizeof(struct malloc_state)); |
| 1152 | mchunkptr mn; | 1235 | mchunkptr mn; |
| @@ -1165,6 +1248,12 @@ void *lj_alloc_create(void) | |||
| 1165 | return NULL; | 1248 | return NULL; |
| 1166 | } | 1249 | } |
| 1167 | 1250 | ||
| 1251 | void lj_alloc_setprng(void *msp, PRNGState *rs) | ||
| 1252 | { | ||
| 1253 | mstate ms = (mstate)msp; | ||
| 1254 | ms->prng = rs; | ||
| 1255 | } | ||
| 1256 | |||
| 1168 | void lj_alloc_destroy(void *msp) | 1257 | void lj_alloc_destroy(void *msp) |
| 1169 | { | 1258 | { |
| 1170 | mstate ms = (mstate)msp; | 1259 | mstate ms = (mstate)msp; |
