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 9adaa0e5..165203fa 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 && LJ_HASJIT | ||
104 | /* Due to limitations in the x64 compiler backend. */ | ||
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 |
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; |