| author | |
| committer | |
| log | 284de7d957037c8a7032bd6e2a95bd5f55b73666 |
| tree | 852d4ef1e8fd8c052485fd38d0dcdfafd28594bb |
| parent | 439667be0476f5bf60f3efbb82a3c4d5aae96ee4 |
* fix merge conflicts
* rename the declarations
* reword documentation
* extract FixedBufferAllocator to separate file
* take advantage of locals
* remove the assertion about max alignment in Allocator API, leaving it
Allocator implementation defined
* fix non-inline function call in start logic
The GeneralPurposeAllocator implementation is totally broken because it
uses global state but I didn't address that in this commit.23 files changed, 703 insertions(+), 698 deletions(-)
lib/fuzzer.zig+1-1| ... | @@ -480,7 +480,7 @@ pub const MemoryMappedList = struct { | ... | @@ -480,7 +480,7 @@ pub const MemoryMappedList = struct { |
| 480 | /// of this ArrayList in accordance with the respective documentation. In | 480 | /// of this ArrayList in accordance with the respective documentation. In |
| 481 | /// all cases, "invalidated" means that the memory has been passed to this | 481 | /// all cases, "invalidated" means that the memory has been passed to this |
| 482 | /// allocator's resize or free function. | 482 | /// allocator's resize or free function. |
| 483 | items: []align(std.heap.min_page_size) volatile u8, | 483 | items: []align(std.heap.page_size_min) volatile u8, |
| 484 | /// How many bytes this list can hold without allocating additional memory. | 484 | /// How many bytes this list can hold without allocating additional memory. |
| 485 | capacity: usize, | 485 | capacity: usize, |
| 486 | 486 |
lib/std/Build/Fuzz/WebServer.zig+1-1| ... | @@ -41,7 +41,7 @@ const fuzzer_arch_os_abi = "wasm32-freestanding"; | ... | @@ -41,7 +41,7 @@ const fuzzer_arch_os_abi = "wasm32-freestanding"; |
| 41 | const fuzzer_cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext"; | 41 | const fuzzer_cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext"; |
| 42 | 42 | ||
| 43 | const CoverageMap = struct { | 43 | const CoverageMap = struct { |
| 44 | mapped_memory: []align(std.heap.min_page_size) const u8, | 44 | mapped_memory: []align(std.heap.page_size_min) const u8, |
| 45 | coverage: Coverage, | 45 | coverage: Coverage, |
| 46 | source_locations: []Coverage.SourceLocation, | 46 | source_locations: []Coverage.SourceLocation, |
| 47 | /// Elements are indexes into `source_locations` pointing to the unit tests that are being fuzz tested. | 47 | /// Elements are indexes into `source_locations` pointing to the unit tests that are being fuzz tested. |
lib/std/Thread.zig+1-1| ... | @@ -1155,7 +1155,7 @@ const LinuxThreadImpl = struct { | ... | @@ -1155,7 +1155,7 @@ const LinuxThreadImpl = struct { |
| 1155 | completion: Completion = Completion.init(.running), | 1155 | completion: Completion = Completion.init(.running), |
| 1156 | child_tid: std.atomic.Value(i32) = std.atomic.Value(i32).init(1), | 1156 | child_tid: std.atomic.Value(i32) = std.atomic.Value(i32).init(1), |
| 1157 | parent_tid: i32 = undefined, | 1157 | parent_tid: i32 = undefined, |
| 1158 | mapped: []align(std.heap.min_page_size) u8, | 1158 | mapped: []align(std.heap.page_size_min) u8, |
| 1159 | 1159 | ||
| 1160 | /// Calls `munmap(mapped.ptr, mapped.len)` then `exit(1)` without touching the stack (which lives in `mapped.ptr`). | 1160 | /// Calls `munmap(mapped.ptr, mapped.len)` then `exit(1)` without touching the stack (which lives in `mapped.ptr`). |
| 1161 | /// Ported over from musl libc's pthread detached implementation: | 1161 | /// Ported over from musl libc's pthread detached implementation: |
lib/std/c.zig+10-10| ... | @@ -3,7 +3,7 @@ const builtin = @import("builtin"); | ... | @@ -3,7 +3,7 @@ const builtin = @import("builtin"); |
| 3 | const c = @This(); | 3 | const c = @This(); |
| 4 | const maxInt = std.math.maxInt; | 4 | const maxInt = std.math.maxInt; |
| 5 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 6 | const min_page_size = std.heap.min_page_size; | 6 | const page_size = std.heap.page_size_min; |
| 7 | const native_abi = builtin.abi; | 7 | const native_abi = builtin.abi; |
| 8 | const native_arch = builtin.cpu.arch; | 8 | const native_arch = builtin.cpu.arch; |
| 9 | const native_os = builtin.os.tag; | 9 | const native_os = builtin.os.tag; |
| ... | @@ -2229,7 +2229,7 @@ pub const SC = switch (native_os) { | ... | @@ -2229,7 +2229,7 @@ pub const SC = switch (native_os) { |
| 2229 | }; | 2229 | }; |
| 2230 | 2230 | ||
| 2231 | pub const _SC = switch (native_os) { | 2231 | pub const _SC = switch (native_os) { |
| 2232 | .bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => enum(c_int) { | 2232 | .driverkit, .ios, .macos, .tvos, .visionos, .watchos => enum(c_int) { |
| 2233 | PAGESIZE = 29, | 2233 | PAGESIZE = 29, |
| 2234 | }, | 2234 | }, |
| 2235 | .dragonfly => enum(c_int) { | 2235 | .dragonfly => enum(c_int) { |
| ... | @@ -9265,7 +9265,7 @@ pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd; | ... | @@ -9265,7 +9265,7 @@ pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd; |
| 9265 | pub extern "c" fn getpwuid(uid: uid_t) ?*passwd; | 9265 | pub extern "c" fn getpwuid(uid: uid_t) ?*passwd; |
| 9266 | pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int; | 9266 | pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int; |
| 9267 | pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64; | 9267 | pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64; |
| 9268 | pub extern "c" fn mmap64(addr: ?*align(min_page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque; | 9268 | pub extern "c" fn mmap64(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque; |
| 9269 | pub extern "c" fn open64(path: [*:0]const u8, oflag: O, ...) c_int; | 9269 | pub extern "c" fn open64(path: [*:0]const u8, oflag: O, ...) c_int; |
| 9270 | pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int; | 9270 | pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int; |
| 9271 | pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize; | 9271 | pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize; |
| ... | @@ -9357,13 +9357,13 @@ pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int; | ... | @@ -9357,13 +9357,13 @@ pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int; |
| 9357 | 9357 | ||
| 9358 | pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int; | 9358 | pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int; |
| 9359 | pub extern "c" fn mincore( | 9359 | pub extern "c" fn mincore( |
| 9360 | addr: *align(min_page_size) anyopaque, | 9360 | addr: *align(page_size) anyopaque, |
| 9361 | length: usize, | 9361 | length: usize, |
| 9362 | vec: [*]u8, | 9362 | vec: [*]u8, |
| 9363 | ) c_int; | 9363 | ) c_int; |
| 9364 | 9364 | ||
| 9365 | pub extern "c" fn madvise( | 9365 | pub extern "c" fn madvise( |
| 9366 | addr: *align(min_page_size) anyopaque, | 9366 | addr: *align(page_size) anyopaque, |
| 9367 | length: usize, | 9367 | length: usize, |
| 9368 | advice: u32, | 9368 | advice: u32, |
| 9369 | ) c_int; | 9369 | ) c_int; |
| ... | @@ -9506,9 +9506,9 @@ pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) i | ... | @@ -9506,9 +9506,9 @@ pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) i |
| 9506 | pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize; | 9506 | pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize; |
| 9507 | pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize; | 9507 | pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize; |
| 9508 | pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize; | 9508 | pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize; |
| 9509 | pub extern "c" fn mmap(addr: ?*align(min_page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: fd_t, offset: off_t) *anyopaque; | 9509 | pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: fd_t, offset: off_t) *anyopaque; |
| 9510 | pub extern "c" fn munmap(addr: *align(min_page_size) const anyopaque, len: usize) c_int; | 9510 | pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int; |
| 9511 | pub extern "c" fn mprotect(addr: *align(min_page_size) anyopaque, len: usize, prot: c_uint) c_int; | 9511 | pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int; |
| 9512 | pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8) c_int; | 9512 | pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8) c_int; |
| 9513 | pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int; | 9513 | pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int; |
| 9514 | pub extern "c" fn unlink(path: [*:0]const u8) c_int; | 9514 | pub extern "c" fn unlink(path: [*:0]const u8) c_int; |
| ... | @@ -10191,7 +10191,7 @@ const private = struct { | ... | @@ -10191,7 +10191,7 @@ const private = struct { |
| 10191 | }; | 10191 | }; |
| 10192 | extern "c" fn getrusage(who: c_int, usage: *rusage) c_int; | 10192 | extern "c" fn getrusage(who: c_int, usage: *rusage) c_int; |
| 10193 | extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; | 10193 | extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; |
| 10194 | extern "c" fn msync(addr: *align(min_page_size) const anyopaque, len: usize, flags: c_int) c_int; | 10194 | extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int; |
| 10195 | extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; | 10195 | extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; |
| 10196 | extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int; | 10196 | extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int; |
| 10197 | extern "c" fn readdir(dir: *DIR) ?*dirent; | 10197 | extern "c" fn readdir(dir: *DIR) ?*dirent; |
| ... | @@ -10239,7 +10239,7 @@ const private = struct { | ... | @@ -10239,7 +10239,7 @@ const private = struct { |
| 10239 | extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int; | 10239 | extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int; |
| 10240 | extern "c" fn __gettimeofday50(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; | 10240 | extern "c" fn __gettimeofday50(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; |
| 10241 | extern "c" fn __libc_thr_yield() c_int; | 10241 | extern "c" fn __libc_thr_yield() c_int; |
| 10242 | extern "c" fn __msync13(addr: *align(min_page_size) const anyopaque, len: usize, flags: c_int) c_int; | 10242 | extern "c" fn __msync13(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int; |
| 10243 | extern "c" fn __nanosleep50(rqtp: *const timespec, rmtp: ?*timespec) c_int; | 10243 | extern "c" fn __nanosleep50(rqtp: *const timespec, rmtp: ?*timespec) c_int; |
| 10244 | extern "c" fn __sigaction14(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; | 10244 | extern "c" fn __sigaction14(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; |
| 10245 | extern "c" fn __sigfillset14(set: ?*sigset_t) void; | 10245 | extern "c" fn __sigfillset14(set: ?*sigset_t) void; |
lib/std/crypto/tlcsprng.zig+5-6| ... | @@ -6,7 +6,6 @@ | ... | @@ -6,7 +6,6 @@ |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const mem = std.mem; | 8 | const mem = std.mem; |
| 9 | const heap = std.heap; | ||
| 10 | const native_os = builtin.os.tag; | 9 | const native_os = builtin.os.tag; |
| 11 | const posix = std.posix; | 10 | const posix = std.posix; |
| 12 | 11 | ||
| ... | @@ -43,7 +42,7 @@ var install_atfork_handler = std.once(struct { | ... | @@ -43,7 +42,7 @@ var install_atfork_handler = std.once(struct { |
| 43 | } | 42 | } |
| 44 | }.do); | 43 | }.do); |
| 45 | 44 | ||
| 46 | threadlocal var wipe_mem: []align(heap.min_page_size) u8 = &[_]u8{}; | 45 | threadlocal var wipe_mem: []align(std.heap.page_size_min) u8 = &[_]u8{}; |
| 47 | 46 | ||
| 48 | fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { | 47 | fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { |
| 49 | if (os_has_arc4random) { | 48 | if (os_has_arc4random) { |
| ... | @@ -78,7 +77,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { | ... | @@ -78,7 +77,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { |
| 78 | } else { | 77 | } else { |
| 79 | // Use a static thread-local buffer. | 78 | // Use a static thread-local buffer. |
| 80 | const S = struct { | 79 | const S = struct { |
| 81 | threadlocal var buf: Context align(heap.min_page_size) = .{ | 80 | threadlocal var buf: Context align(std.heap.page_size_min) = .{ |
| 82 | .init_state = .uninitialized, | 81 | .init_state = .uninitialized, |
| 83 | .rng = undefined, | 82 | .rng = undefined, |
| 84 | }; | 83 | }; |
| ... | @@ -86,7 +85,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { | ... | @@ -86,7 +85,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { |
| 86 | wipe_mem = mem.asBytes(&S.buf); | 85 | wipe_mem = mem.asBytes(&S.buf); |
| 87 | } | 86 | } |
| 88 | } | 87 | } |
| 89 | const ctx = @as(*Context, @ptrCast(wipe_mem.ptr)); | 88 | const ctx: *Context = @ptrCast(wipe_mem.ptr); |
| 90 | 89 | ||
| 91 | switch (ctx.init_state) { | 90 | switch (ctx.init_state) { |
| 92 | .uninitialized => { | 91 | .uninitialized => { |
| ... | @@ -142,7 +141,7 @@ fn childAtForkHandler() callconv(.c) void { | ... | @@ -142,7 +141,7 @@ fn childAtForkHandler() callconv(.c) void { |
| 142 | } | 141 | } |
| 143 | 142 | ||
| 144 | fn fillWithCsprng(buffer: []u8) void { | 143 | fn fillWithCsprng(buffer: []u8) void { |
| 145 | const ctx = @as(*Context, @ptrCast(wipe_mem.ptr)); | 144 | const ctx: *Context = @ptrCast(wipe_mem.ptr); |
| 146 | return ctx.rng.fill(buffer); | 145 | return ctx.rng.fill(buffer); |
| 147 | } | 146 | } |
| 148 | 147 | ||
| ... | @@ -158,7 +157,7 @@ fn initAndFill(buffer: []u8) void { | ... | @@ -158,7 +157,7 @@ fn initAndFill(buffer: []u8) void { |
| 158 | // the `std.options.cryptoRandomSeed` function is provided. | 157 | // the `std.options.cryptoRandomSeed` function is provided. |
| 159 | std.options.cryptoRandomSeed(&seed); | 158 | std.options.cryptoRandomSeed(&seed); |
| 160 | 159 | ||
| 161 | const ctx = @as(*Context, @ptrCast(wipe_mem.ptr)); | 160 | const ctx: *Context = @ptrCast(wipe_mem.ptr); |
| 162 | ctx.rng = Rng.init(seed); | 161 | ctx.rng = Rng.init(seed); |
| 163 | std.crypto.secureZero(u8, &seed); | 162 | std.crypto.secureZero(u8, &seed); |
| 164 | 163 |
lib/std/debug.zig+7-8| ... | @@ -2,7 +2,6 @@ const builtin = @import("builtin"); | ... | @@ -2,7 +2,6 @@ const builtin = @import("builtin"); |
| 2 | const std = @import("std.zig"); | 2 | const std = @import("std.zig"); |
| 3 | const math = std.math; | 3 | const math = std.math; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const heap = std.heap; | ||
| 6 | const io = std.io; | 5 | const io = std.io; |
| 7 | const posix = std.posix; | 6 | const posix = std.posix; |
| 8 | const fs = std.fs; | 7 | const fs = std.fs; |
| ... | @@ -1238,7 +1237,7 @@ test printLineFromFileAnyOs { | ... | @@ -1238,7 +1237,7 @@ test printLineFromFileAnyOs { |
| 1238 | 1237 | ||
| 1239 | const overlap = 10; | 1238 | const overlap = 10; |
| 1240 | var writer = file.writer(); | 1239 | var writer = file.writer(); |
| 1241 | try writer.writeByteNTimes('a', heap.min_page_size - overlap); | 1240 | try writer.writeByteNTimes('a', std.heap.page_size_min - overlap); |
| 1242 | try writer.writeByte('\n'); | 1241 | try writer.writeByte('\n'); |
| 1243 | try writer.writeByteNTimes('a', overlap); | 1242 | try writer.writeByteNTimes('a', overlap); |
| 1244 | 1243 | ||
| ... | @@ -1253,10 +1252,10 @@ test printLineFromFileAnyOs { | ... | @@ -1253,10 +1252,10 @@ test printLineFromFileAnyOs { |
| 1253 | defer allocator.free(path); | 1252 | defer allocator.free(path); |
| 1254 | 1253 | ||
| 1255 | var writer = file.writer(); | 1254 | var writer = file.writer(); |
| 1256 | try writer.writeByteNTimes('a', heap.max_page_size); | 1255 | try writer.writeByteNTimes('a', std.heap.page_size_max); |
| 1257 | 1256 | ||
| 1258 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); | 1257 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); |
| 1259 | try expectEqualStrings(("a" ** heap.max_page_size) ++ "\n", output.items); | 1258 | try expectEqualStrings(("a" ** std.heap.page_size_max) ++ "\n", output.items); |
| 1260 | output.clearRetainingCapacity(); | 1259 | output.clearRetainingCapacity(); |
| 1261 | } | 1260 | } |
| 1262 | { | 1261 | { |
| ... | @@ -1266,18 +1265,18 @@ test printLineFromFileAnyOs { | ... | @@ -1266,18 +1265,18 @@ test printLineFromFileAnyOs { |
| 1266 | defer allocator.free(path); | 1265 | defer allocator.free(path); |
| 1267 | 1266 | ||
| 1268 | var writer = file.writer(); | 1267 | var writer = file.writer(); |
| 1269 | try writer.writeByteNTimes('a', 3 * heap.max_page_size); | 1268 | try writer.writeByteNTimes('a', 3 * std.heap.page_size_max); |
| 1270 | 1269 | ||
| 1271 | try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 })); | 1270 | try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 })); |
| 1272 | 1271 | ||
| 1273 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); | 1272 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); |
| 1274 | try expectEqualStrings(("a" ** (3 * heap.max_page_size)) ++ "\n", output.items); | 1273 | try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "\n", output.items); |
| 1275 | output.clearRetainingCapacity(); | 1274 | output.clearRetainingCapacity(); |
| 1276 | 1275 | ||
| 1277 | try writer.writeAll("a\na"); | 1276 | try writer.writeAll("a\na"); |
| 1278 | 1277 | ||
| 1279 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); | 1278 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); |
| 1280 | try expectEqualStrings(("a" ** (3 * heap.max_page_size)) ++ "a\n", output.items); | 1279 | try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "a\n", output.items); |
| 1281 | output.clearRetainingCapacity(); | 1280 | output.clearRetainingCapacity(); |
| 1282 | 1281 | ||
| 1283 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }); | 1282 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }); |
| ... | @@ -1291,7 +1290,7 @@ test printLineFromFileAnyOs { | ... | @@ -1291,7 +1290,7 @@ test printLineFromFileAnyOs { |
| 1291 | defer allocator.free(path); | 1290 | defer allocator.free(path); |
| 1292 | 1291 | ||
| 1293 | var writer = file.writer(); | 1292 | var writer = file.writer(); |
| 1294 | const real_file_start = 3 * heap.min_page_size; | 1293 | const real_file_start = 3 * std.heap.page_size_min; |
| 1295 | try writer.writeByteNTimes('\n', real_file_start); | 1294 | try writer.writeByteNTimes('\n', real_file_start); |
| 1296 | try writer.writeAll("abc\ndef"); | 1295 | try writer.writeAll("abc\ndef"); |
| 1297 | 1296 |
lib/std/debug/Dwarf.zig+5-5| ... | @@ -2120,8 +2120,8 @@ fn pcRelBase(field_ptr: usize, pc_rel_offset: i64) !usize { | ... | @@ -2120,8 +2120,8 @@ fn pcRelBase(field_ptr: usize, pc_rel_offset: i64) !usize { |
| 2120 | pub const ElfModule = struct { | 2120 | pub const ElfModule = struct { |
| 2121 | base_address: usize, | 2121 | base_address: usize, |
| 2122 | dwarf: Dwarf, | 2122 | dwarf: Dwarf, |
| 2123 | mapped_memory: []align(std.heap.min_page_size) const u8, | 2123 | mapped_memory: []align(std.heap.page_size_min) const u8, |
| 2124 | external_mapped_memory: ?[]align(std.heap.min_page_size) const u8, | 2124 | external_mapped_memory: ?[]align(std.heap.page_size_min) const u8, |
| 2125 | 2125 | ||
| 2126 | pub fn deinit(self: *@This(), allocator: Allocator) void { | 2126 | pub fn deinit(self: *@This(), allocator: Allocator) void { |
| 2127 | self.dwarf.deinit(allocator); | 2127 | self.dwarf.deinit(allocator); |
| ... | @@ -2167,11 +2167,11 @@ pub const ElfModule = struct { | ... | @@ -2167,11 +2167,11 @@ pub const ElfModule = struct { |
| 2167 | /// sections from an external file. | 2167 | /// sections from an external file. |
| 2168 | pub fn load( | 2168 | pub fn load( |
| 2169 | gpa: Allocator, | 2169 | gpa: Allocator, |
| 2170 | mapped_mem: []align(std.heap.min_page_size) const u8, | 2170 | mapped_mem: []align(std.heap.page_size_min) const u8, |
| 2171 | build_id: ?[]const u8, | 2171 | build_id: ?[]const u8, |
| 2172 | expected_crc: ?u32, | 2172 | expected_crc: ?u32, |
| 2173 | parent_sections: *Dwarf.SectionArray, | 2173 | parent_sections: *Dwarf.SectionArray, |
| 2174 | parent_mapped_mem: ?[]align(std.heap.min_page_size) const u8, | 2174 | parent_mapped_mem: ?[]align(std.heap.page_size_min) const u8, |
| 2175 | elf_filename: ?[]const u8, | 2175 | elf_filename: ?[]const u8, |
| 2176 | ) LoadError!Dwarf.ElfModule { | 2176 | ) LoadError!Dwarf.ElfModule { |
| 2177 | if (expected_crc) |crc| if (crc != std.hash.crc.Crc32.hash(mapped_mem)) return error.InvalidDebugInfo; | 2177 | if (expected_crc) |crc| if (crc != std.hash.crc.Crc32.hash(mapped_mem)) return error.InvalidDebugInfo; |
| ... | @@ -2423,7 +2423,7 @@ pub const ElfModule = struct { | ... | @@ -2423,7 +2423,7 @@ pub const ElfModule = struct { |
| 2423 | build_id: ?[]const u8, | 2423 | build_id: ?[]const u8, |
| 2424 | expected_crc: ?u32, | 2424 | expected_crc: ?u32, |
| 2425 | parent_sections: *Dwarf.SectionArray, | 2425 | parent_sections: *Dwarf.SectionArray, |
| 2426 | parent_mapped_mem: ?[]align(std.heap.min_page_size) const u8, | 2426 | parent_mapped_mem: ?[]align(std.heap.page_size_min) const u8, |
| 2427 | ) LoadError!Dwarf.ElfModule { | 2427 | ) LoadError!Dwarf.ElfModule { |
| 2428 | const elf_file = elf_file_path.root_dir.handle.openFile(elf_file_path.sub_path, .{}) catch |err| switch (err) { | 2428 | const elf_file = elf_file_path.root_dir.handle.openFile(elf_file_path.sub_path, .{}) catch |err| switch (err) { |
| 2429 | error.FileNotFound => return missing(), | 2429 | error.FileNotFound => return missing(), |
lib/std/debug/MemoryAccessor.zig+2-2| ... | @@ -7,7 +7,7 @@ const native_os = builtin.os.tag; | ... | @@ -7,7 +7,7 @@ const native_os = builtin.os.tag; |
| 7 | const std = @import("../std.zig"); | 7 | const std = @import("../std.zig"); |
| 8 | const posix = std.posix; | 8 | const posix = std.posix; |
| 9 | const File = std.fs.File; | 9 | const File = std.fs.File; |
| 10 | const min_page_size = std.heap.min_page_size; | 10 | const page_size_min = std.heap.page_size_min; |
| 11 | 11 | ||
| 12 | const MemoryAccessor = @This(); | 12 | const MemoryAccessor = @This(); |
| 13 | 13 | ||
| ... | @@ -96,7 +96,7 @@ pub fn isValidMemory(address: usize) bool { | ... | @@ -96,7 +96,7 @@ pub fn isValidMemory(address: usize) bool { |
| 96 | const page_size = std.heap.pageSize(); | 96 | const page_size = std.heap.pageSize(); |
| 97 | const aligned_address = address & ~(page_size - 1); | 97 | const aligned_address = address & ~(page_size - 1); |
| 98 | if (aligned_address == 0) return false; | 98 | if (aligned_address == 0) return false; |
| 99 | const aligned_memory = @as([*]align(min_page_size) u8, @ptrFromInt(aligned_address))[0..page_size]; | 99 | const aligned_memory = @as([*]align(page_size_min) u8, @ptrFromInt(aligned_address))[0..page_size]; |
| 100 | 100 | ||
| 101 | if (native_os == .windows) { | 101 | if (native_os == .windows) { |
| 102 | const windows = std.os.windows; | 102 | const windows = std.os.windows; |
lib/std/debug/SelfInfo.zig+3-3| ... | @@ -504,7 +504,7 @@ pub const Module = switch (native_os) { | ... | @@ -504,7 +504,7 @@ pub const Module = switch (native_os) { |
| 504 | .macos, .ios, .watchos, .tvos, .visionos => struct { | 504 | .macos, .ios, .watchos, .tvos, .visionos => struct { |
| 505 | base_address: usize, | 505 | base_address: usize, |
| 506 | vmaddr_slide: usize, | 506 | vmaddr_slide: usize, |
| 507 | mapped_memory: []align(std.heap.min_page_size) const u8, | 507 | mapped_memory: []align(std.heap.page_size_min) const u8, |
| 508 | symbols: []const MachoSymbol, | 508 | symbols: []const MachoSymbol, |
| 509 | strings: [:0]const u8, | 509 | strings: [:0]const u8, |
| 510 | ofiles: OFileTable, | 510 | ofiles: OFileTable, |
| ... | @@ -1046,7 +1046,7 @@ pub fn readElfDebugInfo( | ... | @@ -1046,7 +1046,7 @@ pub fn readElfDebugInfo( |
| 1046 | build_id: ?[]const u8, | 1046 | build_id: ?[]const u8, |
| 1047 | expected_crc: ?u32, | 1047 | expected_crc: ?u32, |
| 1048 | parent_sections: *Dwarf.SectionArray, | 1048 | parent_sections: *Dwarf.SectionArray, |
| 1049 | parent_mapped_mem: ?[]align(std.heap.min_page_size) const u8, | 1049 | parent_mapped_mem: ?[]align(std.heap.page_size_min) const u8, |
| 1050 | ) !Dwarf.ElfModule { | 1050 | ) !Dwarf.ElfModule { |
| 1051 | nosuspend { | 1051 | nosuspend { |
| 1052 | const elf_file = (if (elf_filename) |filename| blk: { | 1052 | const elf_file = (if (elf_filename) |filename| blk: { |
| ... | @@ -1088,7 +1088,7 @@ const MachoSymbol = struct { | ... | @@ -1088,7 +1088,7 @@ const MachoSymbol = struct { |
| 1088 | 1088 | ||
| 1089 | /// Takes ownership of file, even on error. | 1089 | /// Takes ownership of file, even on error. |
| 1090 | /// TODO it's weird to take ownership even on error, rework this code. | 1090 | /// TODO it's weird to take ownership even on error, rework this code. |
| 1091 | fn mapWholeFile(file: File) ![]align(std.heap.min_page_size) const u8 { | 1091 | fn mapWholeFile(file: File) ![]align(std.heap.page_size_min) const u8 { |
| 1092 | nosuspend { | 1092 | nosuspend { |
| 1093 | defer file.close(); | 1093 | defer file.close(); |
| 1094 | 1094 |
lib/std/dynamic_library.zig+7-6| ... | @@ -1,7 +1,6 @@ | ... | @@ -1,7 +1,6 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const mem = std.mem; | 3 | const mem = std.mem; |
| 4 | const heap = std.heap; | ||
| 5 | const testing = std.testing; | 4 | const testing = std.testing; |
| 6 | const elf = std.elf; | 5 | const elf = std.elf; |
| 7 | const windows = std.os.windows; | 6 | const windows = std.os.windows; |
| ... | @@ -144,7 +143,7 @@ pub const ElfDynLib = struct { | ... | @@ -144,7 +143,7 @@ pub const ElfDynLib = struct { |
| 144 | hashtab: [*]posix.Elf_Symndx, | 143 | hashtab: [*]posix.Elf_Symndx, |
| 145 | versym: ?[*]elf.Versym, | 144 | versym: ?[*]elf.Versym, |
| 146 | verdef: ?*elf.Verdef, | 145 | verdef: ?*elf.Verdef, |
| 147 | memory: []align(heap.min_page_size) u8, | 146 | memory: []align(std.heap.page_size_min) u8, |
| 148 | 147 | ||
| 149 | pub const Error = ElfDynLibError; | 148 | pub const Error = ElfDynLibError; |
| 150 | 149 | ||
| ... | @@ -220,11 +219,13 @@ pub const ElfDynLib = struct { | ... | @@ -220,11 +219,13 @@ pub const ElfDynLib = struct { |
| 220 | const stat = try file.stat(); | 219 | const stat = try file.stat(); |
| 221 | const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig; | 220 | const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig; |
| 222 | 221 | ||
| 222 | const page_size = std.heap.pageSize(); | ||
| 223 | |||
| 223 | // This one is to read the ELF info. We do more mmapping later | 224 | // This one is to read the ELF info. We do more mmapping later |
| 224 | // corresponding to the actual LOAD sections. | 225 | // corresponding to the actual LOAD sections. |
| 225 | const file_bytes = try posix.mmap( | 226 | const file_bytes = try posix.mmap( |
| 226 | null, | 227 | null, |
| 227 | mem.alignForward(usize, size, heap.pageSize()), | 228 | mem.alignForward(usize, size, page_size), |
| 228 | posix.PROT.READ, | 229 | posix.PROT.READ, |
| 229 | .{ .TYPE = .PRIVATE }, | 230 | .{ .TYPE = .PRIVATE }, |
| 230 | fd, | 231 | fd, |
| ... | @@ -285,10 +286,10 @@ pub const ElfDynLib = struct { | ... | @@ -285,10 +286,10 @@ pub const ElfDynLib = struct { |
| 285 | elf.PT_LOAD => { | 286 | elf.PT_LOAD => { |
| 286 | // The VirtAddr may not be page-aligned; in such case there will be | 287 | // The VirtAddr may not be page-aligned; in such case there will be |
| 287 | // extra nonsense mapped before/after the VirtAddr,MemSiz | 288 | // extra nonsense mapped before/after the VirtAddr,MemSiz |
| 288 | const aligned_addr = (base + ph.p_vaddr) & ~(@as(usize, heap.pageSize()) - 1); | 289 | const aligned_addr = (base + ph.p_vaddr) & ~(@as(usize, page_size) - 1); |
| 289 | const extra_bytes = (base + ph.p_vaddr) - aligned_addr; | 290 | const extra_bytes = (base + ph.p_vaddr) - aligned_addr; |
| 290 | const extended_memsz = mem.alignForward(usize, ph.p_memsz + extra_bytes, heap.pageSize()); | 291 | const extended_memsz = mem.alignForward(usize, ph.p_memsz + extra_bytes, page_size); |
| 291 | const ptr = @as([*]align(heap.min_page_size) u8, @ptrFromInt(aligned_addr)); | 292 | const ptr = @as([*]align(std.heap.page_size_min) u8, @ptrFromInt(aligned_addr)); |
| 292 | const prot = elfToMmapProt(ph.p_flags); | 293 | const prot = elfToMmapProt(ph.p_flags); |
| 293 | if ((ph.p_flags & elf.PF_W) == 0) { | 294 | if ((ph.p_flags & elf.PF_W) == 0) { |
| 294 | // If it does not need write access, it can be mapped from the fd. | 295 | // If it does not need write access, it can be mapped from the fd. |
lib/std/heap.zig+367-586| ... | @@ -8,337 +8,79 @@ const c = std.c; | ... | @@ -8,337 +8,79 @@ const c = std.c; |
| 8 | const Allocator = std.mem.Allocator; | 8 | const Allocator = std.mem.Allocator; |
| 9 | const windows = std.os.windows; | 9 | const windows = std.os.windows; |
| 10 | 10 | ||
| 11 | const default_min_page_size: ?usize = switch (builtin.os.tag) { | 11 | pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator; |
| 12 | .bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => switch (builtin.cpu.arch) { | 12 | pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator; |
| 13 | .x86_64 => 4 << 10, | 13 | pub const ScopedLoggingAllocator = @import("heap/logging_allocator.zig").ScopedLoggingAllocator; |
| 14 | .aarch64 => 16 << 10, | 14 | pub const LogToWriterAllocator = @import("heap/log_to_writer_allocator.zig").LogToWriterAllocator; |
| 15 | else => null, | 15 | pub const logToWriterAllocator = @import("heap/log_to_writer_allocator.zig").logToWriterAllocator; |
| 16 | }, | 16 | pub const ArenaAllocator = @import("heap/arena_allocator.zig").ArenaAllocator; |
| 17 | .windows => switch (builtin.cpu.arch) { | 17 | pub const GeneralPurposeAllocatorConfig = @import("heap/general_purpose_allocator.zig").Config; |
| 18 | // -- <https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200> | 18 | pub const GeneralPurposeAllocator = @import("heap/general_purpose_allocator.zig").GeneralPurposeAllocator; |
| 19 | .x86, .x86_64 => 4 << 10, | 19 | pub const Check = @import("heap/general_purpose_allocator.zig").Check; |
| 20 | // SuperH => 4 << 10, | 20 | pub const WasmAllocator = @import("heap/WasmAllocator.zig"); |
| 21 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | 21 | pub const PageAllocator = @import("heap/PageAllocator.zig"); |
| 22 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10, | 22 | pub const ThreadSafeAllocator = @import("heap/ThreadSafeAllocator.zig"); |
| 23 | // DEC Alpha => 8 << 10, | 23 | pub const SbrkAllocator = @import("heap/sbrk_allocator.zig").SbrkAllocator; |
| 24 | // Itanium => 8 << 10, | 24 | pub const FixedBufferAllocator = @import("heap/FixedBufferAllocator.zig"); |
| 25 | .thumb, .thumbeb, .arm, .armeb, .aarch64, .aarch64_be => 4 << 10, | ||
| 26 | else => null, | ||
| 27 | }, | ||
| 28 | .wasi => switch (builtin.cpu.arch) { | ||
| 29 | .wasm32, .wasm64 => 64 << 10, | ||
| 30 | else => null, | ||
| 31 | }, | ||
| 32 | // https://github.com/tianocore/edk2/blob/b158dad150bf02879668f72ce306445250838201/MdePkg/Include/Uefi/UefiBaseType.h#L180-L187 | ||
| 33 | .uefi => 4 << 10, | ||
| 34 | .freebsd => switch (builtin.cpu.arch) { | ||
| 35 | // FreeBSD/sys/* | ||
| 36 | .x86, .x86_64 => 4 << 10, | ||
| 37 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 38 | .aarch64, .aarch64_be => 4 << 10, | ||
| 39 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 40 | .riscv32, .riscv64 => 4 << 10, | ||
| 41 | else => null, | ||
| 42 | }, | ||
| 43 | .netbsd => switch (builtin.cpu.arch) { | ||
| 44 | // NetBSD/sys/arch/* | ||
| 45 | .x86, .x86_64 => 4 << 10, | ||
| 46 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 47 | .aarch64, .aarch64_be => 4 << 10, | ||
| 48 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 49 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 50 | .sparc => 4 << 10, | ||
| 51 | .sparc64 => 8 << 10, | ||
| 52 | .riscv32, .riscv64 => 4 << 10, | ||
| 53 | // Sun-2 | ||
| 54 | .m68k => 2 << 10, | ||
| 55 | else => null, | ||
| 56 | }, | ||
| 57 | .dragonfly => switch (builtin.cpu.arch) { | ||
| 58 | .x86, .x86_64 => 4 << 10, | ||
| 59 | else => null, | ||
| 60 | }, | ||
| 61 | .openbsd => switch (builtin.cpu.arch) { | ||
| 62 | // OpenBSD/sys/arch/* | ||
| 63 | .x86, .x86_64 => 4 << 10, | ||
| 64 | .thumb, .thumbeb, .arm, .armeb, .aarch64, .aarch64_be => 4 << 10, | ||
| 65 | .mips64, .mips64el => 4 << 10, | ||
| 66 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 67 | .riscv64 => 4 << 10, | ||
| 68 | .sparc64 => 8 << 10, | ||
| 69 | else => null, | ||
| 70 | }, | ||
| 71 | .solaris, .illumos => switch (builtin.cpu.arch) { | ||
| 72 | // src/uts/*/sys/machparam.h | ||
| 73 | .x86, .x86_64 => 4 << 10, | ||
| 74 | .sparc, .sparc64 => 8 << 10, | ||
| 75 | else => null, | ||
| 76 | }, | ||
| 77 | .fuchsia => switch (builtin.cpu.arch) { | ||
| 78 | // fuchsia/kernel/arch/*/include/arch/defines.h | ||
| 79 | .x86_64 => 4 << 10, | ||
| 80 | .aarch64, .aarch64_be => 4 << 10, | ||
| 81 | .riscv64 => 4 << 10, | ||
| 82 | else => null, | ||
| 83 | }, | ||
| 84 | // https://github.com/SerenityOS/serenity/blob/62b938b798dc009605b5df8a71145942fc53808b/Kernel/API/POSIX/sys/limits.h#L11-L13 | ||
| 85 | .serenity => 4 << 10, | ||
| 86 | .haiku => switch (builtin.cpu.arch) { | ||
| 87 | // haiku/headers/posix/arch/*/limits.h | ||
| 88 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 89 | .aarch64, .aarch64_be => 4 << 10, | ||
| 90 | .m68k => 4 << 10, | ||
| 91 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 92 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 93 | .riscv64 => 4 << 10, | ||
| 94 | .sparc64 => 8 << 10, | ||
| 95 | .x86, .x86_64 => 4 << 10, | ||
| 96 | else => null, | ||
| 97 | }, | ||
| 98 | .hurd => switch (builtin.cpu.arch) { | ||
| 99 | // gnumach/*/include/mach/*/vm_param.h | ||
| 100 | .x86, .x86_64 => 4 << 10, | ||
| 101 | .aarch64 => null, | ||
| 102 | else => null, | ||
| 103 | }, | ||
| 104 | .plan9 => switch (builtin.cpu.arch) { | ||
| 105 | // 9front/sys/src/9/*/mem.h | ||
| 106 | .x86, .x86_64 => 4 << 10, | ||
| 107 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 108 | .aarch64, .aarch64_be => 4 << 10, | ||
| 109 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 110 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10, | ||
| 111 | .sparc => 4 << 10, | ||
| 112 | else => null, | ||
| 113 | }, | ||
| 114 | .ps3 => switch (builtin.cpu.arch) { | ||
| 115 | // cell/SDK_doc/en/html/C_and_C++_standard_libraries/stdlib.html | ||
| 116 | .powerpc64 => 1 << 20, // 1 MiB | ||
| 117 | else => null, | ||
| 118 | }, | ||
| 119 | .ps4 => switch (builtin.cpu.arch) { | ||
| 120 | // https://github.com/ps4dev/ps4sdk/blob/4df9d001b66ae4ec07d9a51b62d1e4c5e270eecc/include/machine/param.h#L95 | ||
| 121 | .x86, .x86_64 => 4 << 10, | ||
| 122 | else => null, | ||
| 123 | }, | ||
| 124 | .ps5 => switch (builtin.cpu.arch) { | ||
| 125 | // https://github.com/PS5Dev/PS5SDK/blob/a2e03a2a0231a3a3397fa6cd087a01ca6d04f273/include/machine/param.h#L95 | ||
| 126 | .x86, .x86_64 => 16 << 10, | ||
| 127 | else => null, | ||
| 128 | }, | ||
| 129 | // system/lib/libc/musl/arch/emscripten/bits/limits.h | ||
| 130 | .emscripten => 64 << 10, | ||
| 131 | .linux => switch (builtin.cpu.arch) { | ||
| 132 | // Linux/arch/*/Kconfig | ||
| 133 | .arc => 4 << 10, | ||
| 134 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 135 | .aarch64, .aarch64_be => 4 << 10, | ||
| 136 | .csky => 4 << 10, | ||
| 137 | .hexagon => 4 << 10, | ||
| 138 | .loongarch32, .loongarch64 => 4 << 10, | ||
| 139 | .m68k => 4 << 10, | ||
| 140 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 141 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 142 | .riscv32, .riscv64 => 4 << 10, | ||
| 143 | .s390x => 4 << 10, | ||
| 144 | .sparc => 4 << 10, | ||
| 145 | .sparc64 => 8 << 10, | ||
| 146 | .x86, .x86_64 => 4 << 10, | ||
| 147 | .xtensa => 4 << 10, | ||
| 148 | else => null, | ||
| 149 | }, | ||
| 150 | .freestanding => switch (builtin.cpu.arch) { | ||
| 151 | .wasm32, .wasm64 => 64 << 10, | ||
| 152 | else => null, | ||
| 153 | }, | ||
| 154 | else => null, | ||
| 155 | }; | ||
| 156 | 25 | ||
| 157 | const default_max_page_size: ?usize = switch (builtin.os.tag) { | 26 | const memory_pool = @import("heap/memory_pool.zig"); |
| 158 | .bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => switch (builtin.cpu.arch) { | 27 | pub const MemoryPool = memory_pool.MemoryPool; |
| 159 | .x86_64 => 4 << 10, | 28 | pub const MemoryPoolAligned = memory_pool.MemoryPoolAligned; |
| 160 | .aarch64 => 16 << 10, | 29 | pub const MemoryPoolExtra = memory_pool.MemoryPoolExtra; |
| 161 | else => null, | 30 | pub const MemoryPoolOptions = memory_pool.Options; |
| 162 | }, | 31 | |
| 163 | .windows => switch (builtin.cpu.arch) { | 32 | /// TODO Utilize this on Windows. |
| 164 | // -- <https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200> | 33 | pub var next_mmap_addr_hint: ?[*]align(page_size_min) u8 = null; |
| 165 | .x86, .x86_64 => 4 << 10, | ||
| 166 | // SuperH => 4 << 10, | ||
| 167 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 168 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10, | ||
| 169 | // DEC Alpha => 8 << 10, | ||
| 170 | // Itanium => 8 << 10, | ||
| 171 | .thumb, .thumbeb, .arm, .armeb, .aarch64, .aarch64_be => 4 << 10, | ||
| 172 | else => null, | ||
| 173 | }, | ||
| 174 | .wasi => switch (builtin.cpu.arch) { | ||
| 175 | .wasm32, .wasm64 => 64 << 10, | ||
| 176 | else => null, | ||
| 177 | }, | ||
| 178 | // https://github.com/tianocore/edk2/blob/b158dad150bf02879668f72ce306445250838201/MdePkg/Include/Uefi/UefiBaseType.h#L180-L187 | ||
| 179 | .uefi => 4 << 10, | ||
| 180 | .freebsd => switch (builtin.cpu.arch) { | ||
| 181 | // FreeBSD/sys/* | ||
| 182 | .x86, .x86_64 => 4 << 10, | ||
| 183 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 184 | .aarch64, .aarch64_be => 4 << 10, | ||
| 185 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 186 | .riscv32, .riscv64 => 4 << 10, | ||
| 187 | else => null, | ||
| 188 | }, | ||
| 189 | .netbsd => switch (builtin.cpu.arch) { | ||
| 190 | // NetBSD/sys/arch/* | ||
| 191 | .x86, .x86_64 => 4 << 10, | ||
| 192 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 193 | .aarch64, .aarch64_be => 64 << 10, | ||
| 194 | .mips, .mipsel, .mips64, .mips64el => 16 << 10, | ||
| 195 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 16 << 10, | ||
| 196 | .sparc => 8 << 10, | ||
| 197 | .sparc64 => 8 << 10, | ||
| 198 | .riscv32, .riscv64 => 4 << 10, | ||
| 199 | .m68k => 8 << 10, | ||
| 200 | else => null, | ||
| 201 | }, | ||
| 202 | .dragonfly => switch (builtin.cpu.arch) { | ||
| 203 | .x86, .x86_64 => 4 << 10, | ||
| 204 | else => null, | ||
| 205 | }, | ||
| 206 | .openbsd => switch (builtin.cpu.arch) { | ||
| 207 | // OpenBSD/sys/arch/* | ||
| 208 | .x86, .x86_64 => 4 << 10, | ||
| 209 | .thumb, .thumbeb, .arm, .armeb, .aarch64, .aarch64_be => 4 << 10, | ||
| 210 | .mips64, .mips64el => 16 << 10, | ||
| 211 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 212 | .riscv64 => 4 << 10, | ||
| 213 | .sparc64 => 8 << 10, | ||
| 214 | else => null, | ||
| 215 | }, | ||
| 216 | .solaris, .illumos => switch (builtin.cpu.arch) { | ||
| 217 | // src/uts/*/sys/machparam.h | ||
| 218 | .x86, .x86_64 => 4 << 10, | ||
| 219 | .sparc, .sparc64 => 8 << 10, | ||
| 220 | else => null, | ||
| 221 | }, | ||
| 222 | .fuchsia => switch (builtin.cpu.arch) { | ||
| 223 | // fuchsia/kernel/arch/*/include/arch/defines.h | ||
| 224 | .x86_64 => 4 << 10, | ||
| 225 | .aarch64, .aarch64_be => 4 << 10, | ||
| 226 | .riscv64 => 4 << 10, | ||
| 227 | else => null, | ||
| 228 | }, | ||
| 229 | // https://github.com/SerenityOS/serenity/blob/62b938b798dc009605b5df8a71145942fc53808b/Kernel/API/POSIX/sys/limits.h#L11-L13 | ||
| 230 | .serenity => 4 << 10, | ||
| 231 | .haiku => switch (builtin.cpu.arch) { | ||
| 232 | // haiku/headers/posix/arch/*/limits.h | ||
| 233 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 234 | .aarch64, .aarch64_be => 4 << 10, | ||
| 235 | .m68k => 4 << 10, | ||
| 236 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 237 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 238 | .riscv64 => 4 << 10, | ||
| 239 | .sparc64 => 8 << 10, | ||
| 240 | .x86, .x86_64 => 4 << 10, | ||
| 241 | else => null, | ||
| 242 | }, | ||
| 243 | .hurd => switch (builtin.cpu.arch) { | ||
| 244 | // gnumach/*/include/mach/*/vm_param.h | ||
| 245 | .x86, .x86_64 => 4 << 10, | ||
| 246 | .aarch64 => null, | ||
| 247 | else => null, | ||
| 248 | }, | ||
| 249 | .plan9 => switch (builtin.cpu.arch) { | ||
| 250 | // 9front/sys/src/9/*/mem.h | ||
| 251 | .x86, .x86_64 => 4 << 10, | ||
| 252 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 253 | .aarch64, .aarch64_be => 64 << 10, | ||
| 254 | .mips, .mipsel, .mips64, .mips64el => 16 << 10, | ||
| 255 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10, | ||
| 256 | .sparc => 4 << 10, | ||
| 257 | else => null, | ||
| 258 | }, | ||
| 259 | .ps3 => switch (builtin.cpu.arch) { | ||
| 260 | // cell/SDK_doc/en/html/C_and_C++_standard_libraries/stdlib.html | ||
| 261 | .powerpc64 => 1 << 20, // 1 MiB | ||
| 262 | else => null, | ||
| 263 | }, | ||
| 264 | .ps4 => switch (builtin.cpu.arch) { | ||
| 265 | // https://github.com/ps4dev/ps4sdk/blob/4df9d001b66ae4ec07d9a51b62d1e4c5e270eecc/include/machine/param.h#L95 | ||
| 266 | .x86, .x86_64 => 4 << 10, | ||
| 267 | else => null, | ||
| 268 | }, | ||
| 269 | .ps5 => switch (builtin.cpu.arch) { | ||
| 270 | // https://github.com/PS5Dev/PS5SDK/blob/a2e03a2a0231a3a3397fa6cd087a01ca6d04f273/include/machine/param.h#L95 | ||
| 271 | .x86, .x86_64 => 16 << 10, | ||
| 272 | else => null, | ||
| 273 | }, | ||
| 274 | // system/lib/libc/musl/arch/emscripten/bits/limits.h | ||
| 275 | .emscripten => 64 << 10, | ||
| 276 | .linux => switch (builtin.cpu.arch) { | ||
| 277 | // Linux/arch/*/Kconfig | ||
| 278 | .arc => 16 << 10, | ||
| 279 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 280 | .aarch64, .aarch64_be => 64 << 10, | ||
| 281 | .csky => 4 << 10, | ||
| 282 | .hexagon => 256 << 10, | ||
| 283 | .loongarch32, .loongarch64 => 64 << 10, | ||
| 284 | .m68k => 8 << 10, | ||
| 285 | .mips, .mipsel, .mips64, .mips64el => 64 << 10, | ||
| 286 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 256 << 10, | ||
| 287 | .riscv32, .riscv64 => 4 << 10, | ||
| 288 | .s390x => 4 << 10, | ||
| 289 | .sparc => 4 << 10, | ||
| 290 | .sparc64 => 8 << 10, | ||
| 291 | .x86, .x86_64 => 4 << 10, | ||
| 292 | .xtensa => 4 << 10, | ||
| 293 | else => null, | ||
| 294 | }, | ||
| 295 | .freestanding => switch (builtin.cpu.arch) { | ||
| 296 | .wasm32, .wasm64 => 64 << 10, | ||
| 297 | else => null, | ||
| 298 | }, | ||
| 299 | else => null, | ||
| 300 | }; | ||
| 301 | 34 | ||
| 302 | /// The compile-time minimum page size that the target might have. | 35 | /// comptime-known minimum page size of the target. |
| 303 | /// All pointers from `mmap` or `VirtualAlloc` are aligned to at least `min_page_size`, but their | 36 | /// |
| 304 | /// actual alignment may be much bigger. | 37 | /// All pointers from `mmap` or `VirtualAlloc` are aligned to at least |
| 305 | /// This value can be overridden via `std.options.min_page_size`. | 38 | /// `page_size_min`, but their actual alignment may be bigger. |
| 306 | /// On many systems, the actual page size can only be determined at runtime with `pageSize()`. | 39 | /// |
| 307 | pub const min_page_size: usize = std.options.min_page_size orelse (default_min_page_size orelse if (builtin.os.tag == .freestanding or builtin.os.tag == .other) | 40 | /// This value can be overridden via `std.options.page_size_min`. |
| 308 | @compileError("freestanding/other explicitly has no min_page_size. One can be provided with std.options.min_page_size") | 41 | /// |
| 42 | /// On many systems, the actual page size can only be determined at runtime | ||
| 43 | /// with `pageSize`. | ||
| 44 | pub const page_size_min: usize = std.options.page_size_min orelse (page_size_min_default orelse if (builtin.os.tag == .freestanding or builtin.os.tag == .other) | ||
| 45 | @compileError("freestanding/other page_size_min must provided with std.options.page_size_min") | ||
| 309 | else | 46 | else |
| 310 | @compileError(@tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " has no min_page_size. One can be provided with std.options.min_page_size")); | 47 | @compileError(@tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " has unknown page_size_min; populate std.options.page_size_min")); |
| 311 | 48 | ||
| 312 | /// The compile-time maximum page size that the target might have. | 49 | /// comptime-known maximum page size of the target. |
| 313 | /// Targeting a system with a larger page size may require overriding `std.options.max_page_size`, | 50 | /// |
| 314 | /// as well as using the linker arugment `-z max-page-size=`. | 51 | /// Targeting a system with a larger page size may require overriding |
| 315 | /// The actual page size can only be determined at runtime with `pageSize()`. | 52 | /// `std.options.page_size_max`, as well as providing a corresponding linker |
| 316 | pub const max_page_size: usize = std.options.max_page_size orelse (default_max_page_size orelse if (builtin.os.tag == .freestanding or builtin.os.tag == .other) | 53 | /// option. |
| 317 | @compileError("freestanding/other explicitly has no max_page_size. One can be provided with std.options.max_page_size") | 54 | /// |
| 55 | /// The actual page size can only be determined at runtime with `pageSize`. | ||
| 56 | pub const page_size_max: usize = std.options.page_size_max orelse (page_size_max_default orelse if (builtin.os.tag == .freestanding or builtin.os.tag == .other) | ||
| 57 | @compileError("freestanding/other page_size_max must provided with std.options.page_size_max") | ||
| 318 | else | 58 | else |
| 319 | @compileError(@tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " has no max_page_size. One can be provided with std.options.max_page_size")); | 59 | @compileError(@tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " has unknown page_size_max; populate std.options.page_size_max")); |
| 320 | 60 | ||
| 321 | /// Returns the system page size. | 61 | /// If the page size is comptime-known, return value is comptime. |
| 322 | /// If the page size is comptime-known, `pageSize()` returns it directly. | 62 | /// Otherwise, calls `std.options.queryPageSize` which by default queries the |
| 323 | /// Otherwise, `pageSize()` defers to `std.options.queryPageSizeFn()`. | 63 | /// host operating system at runtime. |
| 324 | pub fn pageSize() usize { | 64 | pub inline fn pageSize() usize { |
| 325 | if (min_page_size == max_page_size) { | 65 | if (page_size_min == page_size_max) return page_size_min; |
| 326 | return min_page_size; | 66 | return std.options.queryPageSize(); |
| 327 | } | ||
| 328 | return std.options.queryPageSizeFn(); | ||
| 329 | } | 67 | } |
| 330 | 68 | ||
| 331 | // A cache used by `defaultQueryPageSize()` to avoid repeating syscalls. | 69 | test pageSize { |
| 332 | var page_size_cache = std.atomic.Value(usize).init(0); | 70 | assert(std.math.isPowerOfTwo(pageSize())); |
| 71 | } | ||
| 333 | 72 | ||
| 334 | // The default implementation in `std.options.queryPageSizeFn`. | 73 | /// The default implementation of `std.options.queryPageSize`. |
| 335 | // The first time it is called, it asserts that the page size is within the comptime bounds. | 74 | /// Asserts that the page size is within `page_size_min` and `page_size_max` |
| 336 | pub fn defaultQueryPageSize() usize { | 75 | pub fn defaultQueryPageSize() usize { |
| 337 | var size = page_size_cache.load(.unordered); | 76 | const global = struct { |
| 77 | var cached_result: std.atomic.Value(usize) = .init(0); | ||
| 78 | }; | ||
| 79 | var size = global.cached_result.load(.unordered); | ||
| 338 | if (size > 0) return size; | 80 | if (size > 0) return size; |
| 339 | size = switch (builtin.os.tag) { | 81 | size = switch (builtin.os.tag) { |
| 340 | .linux => if (builtin.link_libc) @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) else std.os.linux.getauxval(std.elf.AT_PAGESZ), | 82 | .linux => if (builtin.link_libc) @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) else std.os.linux.getauxval(std.elf.AT_PAGESZ), |
| 341 | .bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => blk: { | 83 | .driverkit, .ios, .macos, .tvos, .visionos, .watchos => blk: { |
| 342 | const task_port = std.c.mach_task_self(); | 84 | const task_port = std.c.mach_task_self(); |
| 343 | // mach_task_self may fail "if there are any resource failures or other errors". | 85 | // mach_task_self may fail "if there are any resource failures or other errors". |
| 344 | if (task_port == std.c.TASK_NULL) | 86 | if (task_port == std.c.TASK_NULL) |
| ... | @@ -353,7 +95,7 @@ pub fn defaultQueryPageSize() usize { | ... | @@ -353,7 +95,7 @@ pub fn defaultQueryPageSize() usize { |
| 353 | &info_count, | 95 | &info_count, |
| 354 | ); | 96 | ); |
| 355 | assert(vm_info.page_size != 0); | 97 | assert(vm_info.page_size != 0); |
| 356 | break :blk @as(usize, @intCast(vm_info.page_size)); | 98 | break :blk @intCast(vm_info.page_size); |
| 357 | }, | 99 | }, |
| 358 | .windows => blk: { | 100 | .windows => blk: { |
| 359 | var info: std.os.windows.SYSTEM_INFO = undefined; | 101 | var info: std.os.windows.SYSTEM_INFO = undefined; |
| ... | @@ -361,45 +103,24 @@ pub fn defaultQueryPageSize() usize { | ... | @@ -361,45 +103,24 @@ pub fn defaultQueryPageSize() usize { |
| 361 | break :blk info.dwPageSize; | 103 | break :blk info.dwPageSize; |
| 362 | }, | 104 | }, |
| 363 | else => if (builtin.link_libc) | 105 | else => if (builtin.link_libc) |
| 364 | if (std.c._SC != void and @hasDecl(std.c._SC, "PAGESIZE")) | 106 | @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) |
| 365 | @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) | ||
| 366 | else | ||
| 367 | @compileError("missing _SC.PAGESIZE declaration for " ++ @tagName(builtin.os.tag) ++ "-" ++ @tagName(builtin.os.tag)) | ||
| 368 | else if (builtin.os.tag == .freestanding or builtin.os.tag == .other) | 107 | else if (builtin.os.tag == .freestanding or builtin.os.tag == .other) |
| 369 | @compileError("pageSize on freestanding/other is not supported with the default std.options.queryPageSizeFn") | 108 | @compileError("unsupported target: freestanding/other") |
| 370 | else | 109 | else |
| 371 | @compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"), | 110 | @compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"), |
| 372 | }; | 111 | }; |
| 373 | 112 | ||
| 374 | assert(size >= min_page_size); | 113 | assert(size >= page_size_min); |
| 375 | assert(size <= max_page_size); | 114 | assert(size <= page_size_max); |
| 376 | page_size_cache.store(size, .unordered); | 115 | global.cached_result.store(size, .unordered); |
| 377 | 116 | ||
| 378 | return size; | 117 | return size; |
| 379 | } | 118 | } |
| 380 | 119 | ||
| 381 | pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator; | 120 | test defaultQueryPageSize { |
| 382 | pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator; | 121 | if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; |
| 383 | pub const ScopedLoggingAllocator = @import("heap/logging_allocator.zig").ScopedLoggingAllocator; | 122 | assert(std.math.isPowerOfTwo(defaultQueryPageSize())); |
| 384 | pub const LogToWriterAllocator = @import("heap/log_to_writer_allocator.zig").LogToWriterAllocator; | 123 | } |
| 385 | pub const logToWriterAllocator = @import("heap/log_to_writer_allocator.zig").logToWriterAllocator; | ||
| 386 | pub const ArenaAllocator = @import("heap/arena_allocator.zig").ArenaAllocator; | ||
| 387 | pub const GeneralPurposeAllocatorConfig = @import("heap/general_purpose_allocator.zig").Config; | ||
| 388 | pub const GeneralPurposeAllocator = @import("heap/general_purpose_allocator.zig").GeneralPurposeAllocator; | ||
| 389 | pub const Check = @import("heap/general_purpose_allocator.zig").Check; | ||
| 390 | pub const WasmAllocator = @import("heap/WasmAllocator.zig"); | ||
| 391 | pub const PageAllocator = @import("heap/PageAllocator.zig"); | ||
| 392 | pub const ThreadSafeAllocator = @import("heap/ThreadSafeAllocator.zig"); | ||
| 393 | pub const SbrkAllocator = @import("heap/sbrk_allocator.zig").SbrkAllocator; | ||
| 394 | |||
| 395 | const memory_pool = @import("heap/memory_pool.zig"); | ||
| 396 | pub const MemoryPool = memory_pool.MemoryPool; | ||
| 397 | pub const MemoryPoolAligned = memory_pool.MemoryPoolAligned; | ||
| 398 | pub const MemoryPoolExtra = memory_pool.MemoryPoolExtra; | ||
| 399 | pub const MemoryPoolOptions = memory_pool.Options; | ||
| 400 | |||
| 401 | /// TODO Utilize this on Windows. | ||
| 402 | pub var next_mmap_addr_hint: ?[*]align(min_page_size) u8 = null; | ||
| 403 | 124 | ||
| 404 | const CAllocator = struct { | 125 | const CAllocator = struct { |
| 405 | comptime { | 126 | comptime { |
| ... | @@ -623,13 +344,6 @@ pub const wasm_allocator: Allocator = .{ | ... | @@ -623,13 +344,6 @@ pub const wasm_allocator: Allocator = .{ |
| 623 | .vtable = &WasmAllocator.vtable, | 344 | .vtable = &WasmAllocator.vtable, |
| 624 | }; | 345 | }; |
| 625 | 346 | ||
| 626 | /// Verifies that the adjusted length will still map to the full length | ||
| 627 | pub fn alignPageAllocLen(full_len: usize, len: usize) usize { | ||
| 628 | const aligned_len = mem.alignAllocLen(full_len, len); | ||
| 629 | assert(mem.alignForward(usize, aligned_len, pageSize()) == full_len); | ||
| 630 | return aligned_len; | ||
| 631 | } | ||
| 632 | |||
| 633 | pub const HeapAllocator = switch (builtin.os.tag) { | 347 | pub const HeapAllocator = switch (builtin.os.tag) { |
| 634 | .windows => struct { | 348 | .windows => struct { |
| 635 | heap_handle: ?HeapHandle, | 349 | heap_handle: ?HeapHandle, |
| ... | @@ -730,145 +444,6 @@ pub const HeapAllocator = switch (builtin.os.tag) { | ... | @@ -730,145 +444,6 @@ pub const HeapAllocator = switch (builtin.os.tag) { |
| 730 | else => @compileError("Unsupported OS"), | 444 | else => @compileError("Unsupported OS"), |
| 731 | }; | 445 | }; |
| 732 | 446 | ||
| 733 | fn sliceContainsPtr(container: []u8, ptr: [*]u8) bool { | ||
| 734 | return @intFromPtr(ptr) >= @intFromPtr(container.ptr) and | ||
| 735 | @intFromPtr(ptr) < (@intFromPtr(container.ptr) + container.len); | ||
| 736 | } | ||
| 737 | |||
| 738 | fn sliceContainsSlice(container: []u8, slice: []u8) bool { | ||
| 739 | return @intFromPtr(slice.ptr) >= @intFromPtr(container.ptr) and | ||
| 740 | (@intFromPtr(slice.ptr) + slice.len) <= (@intFromPtr(container.ptr) + container.len); | ||
| 741 | } | ||
| 742 | |||
| 743 | pub const FixedBufferAllocator = struct { | ||
| 744 | end_index: usize, | ||
| 745 | buffer: []u8, | ||
| 746 | |||
| 747 | pub fn init(buffer: []u8) FixedBufferAllocator { | ||
| 748 | return FixedBufferAllocator{ | ||
| 749 | .buffer = buffer, | ||
| 750 | .end_index = 0, | ||
| 751 | }; | ||
| 752 | } | ||
| 753 | |||
| 754 | /// *WARNING* using this at the same time as the interface returned by `threadSafeAllocator` is not thread safe | ||
| 755 | pub fn allocator(self: *FixedBufferAllocator) Allocator { | ||
| 756 | return .{ | ||
| 757 | .ptr = self, | ||
| 758 | .vtable = &.{ | ||
| 759 | .alloc = alloc, | ||
| 760 | .resize = resize, | ||
| 761 | .free = free, | ||
| 762 | }, | ||
| 763 | }; | ||
| 764 | } | ||
| 765 | |||
| 766 | /// Provides a lock free thread safe `Allocator` interface to the underlying `FixedBufferAllocator` | ||
| 767 | /// *WARNING* using this at the same time as the interface returned by `allocator` is not thread safe | ||
| 768 | pub fn threadSafeAllocator(self: *FixedBufferAllocator) Allocator { | ||
| 769 | return .{ | ||
| 770 | .ptr = self, | ||
| 771 | .vtable = &.{ | ||
| 772 | .alloc = threadSafeAlloc, | ||
| 773 | .resize = Allocator.noResize, | ||
| 774 | .free = Allocator.noFree, | ||
| 775 | }, | ||
| 776 | }; | ||
| 777 | } | ||
| 778 | |||
| 779 | pub fn ownsPtr(self: *FixedBufferAllocator, ptr: [*]u8) bool { | ||
| 780 | return sliceContainsPtr(self.buffer, ptr); | ||
| 781 | } | ||
| 782 | |||
| 783 | pub fn ownsSlice(self: *FixedBufferAllocator, slice: []u8) bool { | ||
| 784 | return sliceContainsSlice(self.buffer, slice); | ||
| 785 | } | ||
| 786 | |||
| 787 | /// NOTE: this will not work in all cases, if the last allocation had an adjusted_index | ||
| 788 | /// then we won't be able to determine what the last allocation was. This is because | ||
| 789 | /// the alignForward operation done in alloc is not reversible. | ||
| 790 | pub fn isLastAllocation(self: *FixedBufferAllocator, buf: []u8) bool { | ||
| 791 | return buf.ptr + buf.len == self.buffer.ptr + self.end_index; | ||
| 792 | } | ||
| 793 | |||
| 794 | fn alloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 { | ||
| 795 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | ||
| 796 | _ = ra; | ||
| 797 | const ptr_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align)); | ||
| 798 | const adjust_off = mem.alignPointerOffset(self.buffer.ptr + self.end_index, ptr_align) orelse return null; | ||
| 799 | const adjusted_index = self.end_index + adjust_off; | ||
| 800 | const new_end_index = adjusted_index + n; | ||
| 801 | if (new_end_index > self.buffer.len) return null; | ||
| 802 | self.end_index = new_end_index; | ||
| 803 | return self.buffer.ptr + adjusted_index; | ||
| 804 | } | ||
| 805 | |||
| 806 | fn resize( | ||
| 807 | ctx: *anyopaque, | ||
| 808 | buf: []u8, | ||
| 809 | log2_buf_align: u8, | ||
| 810 | new_size: usize, | ||
| 811 | return_address: usize, | ||
| 812 | ) bool { | ||
| 813 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | ||
| 814 | _ = log2_buf_align; | ||
| 815 | _ = return_address; | ||
| 816 | assert(@inComptime() or self.ownsSlice(buf)); | ||
| 817 | |||
| 818 | if (!self.isLastAllocation(buf)) { | ||
| 819 | if (new_size > buf.len) return false; | ||
| 820 | return true; | ||
| 821 | } | ||
| 822 | |||
| 823 | if (new_size <= buf.len) { | ||
| 824 | const sub = buf.len - new_size; | ||
| 825 | self.end_index -= sub; | ||
| 826 | return true; | ||
| 827 | } | ||
| 828 | |||
| 829 | const add = new_size - buf.len; | ||
| 830 | if (add + self.end_index > self.buffer.len) return false; | ||
| 831 | |||
| 832 | self.end_index += add; | ||
| 833 | return true; | ||
| 834 | } | ||
| 835 | |||
| 836 | fn free( | ||
| 837 | ctx: *anyopaque, | ||
| 838 | buf: []u8, | ||
| 839 | log2_buf_align: u8, | ||
| 840 | return_address: usize, | ||
| 841 | ) void { | ||
| 842 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | ||
| 843 | _ = log2_buf_align; | ||
| 844 | _ = return_address; | ||
| 845 | assert(@inComptime() or self.ownsSlice(buf)); | ||
| 846 | |||
| 847 | if (self.isLastAllocation(buf)) { | ||
| 848 | self.end_index -= buf.len; | ||
| 849 | } | ||
| 850 | } | ||
| 851 | |||
| 852 | fn threadSafeAlloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 { | ||
| 853 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | ||
| 854 | _ = ra; | ||
| 855 | const ptr_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align)); | ||
| 856 | var end_index = @atomicLoad(usize, &self.end_index, .seq_cst); | ||
| 857 | while (true) { | ||
| 858 | const adjust_off = mem.alignPointerOffset(self.buffer.ptr + end_index, ptr_align) orelse return null; | ||
| 859 | const adjusted_index = end_index + adjust_off; | ||
| 860 | const new_end_index = adjusted_index + n; | ||
| 861 | if (new_end_index > self.buffer.len) return null; | ||
| 862 | end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, .seq_cst, .seq_cst) orelse | ||
| 863 | return self.buffer[adjusted_index..new_end_index].ptr; | ||
| 864 | } | ||
| 865 | } | ||
| 866 | |||
| 867 | pub fn reset(self: *FixedBufferAllocator) void { | ||
| 868 | self.end_index = 0; | ||
| 869 | } | ||
| 870 | }; | ||
| 871 | |||
| 872 | /// Returns a `StackFallbackAllocator` allocating using either a | 447 | /// Returns a `StackFallbackAllocator` allocating using either a |
| 873 | /// `FixedBufferAllocator` on an array of size `size` and falling back to | 448 | /// `FixedBufferAllocator` on an array of size `size` and falling back to |
| 874 | /// `fallback_allocator` if that fails. | 449 | /// `fallback_allocator` if that fails. |
| ... | @@ -975,7 +550,7 @@ test "raw_c_allocator" { | ... | @@ -975,7 +550,7 @@ test "raw_c_allocator" { |
| 975 | } | 550 | } |
| 976 | } | 551 | } |
| 977 | 552 | ||
| 978 | test "PageAllocator" { | 553 | test PageAllocator { |
| 979 | const allocator = page_allocator; | 554 | const allocator = page_allocator; |
| 980 | try testAllocator(allocator); | 555 | try testAllocator(allocator); |
| 981 | try testAllocatorAligned(allocator); | 556 | try testAllocatorAligned(allocator); |
| ... | @@ -985,7 +560,7 @@ test "PageAllocator" { | ... | @@ -985,7 +560,7 @@ test "PageAllocator" { |
| 985 | } | 560 | } |
| 986 | 561 | ||
| 987 | if (builtin.os.tag == .windows) { | 562 | if (builtin.os.tag == .windows) { |
| 988 | const slice = try allocator.alignedAlloc(u8, min_page_size, 128); | 563 | const slice = try allocator.alignedAlloc(u8, page_size_min, 128); |
| 989 | slice[0] = 0x12; | 564 | slice[0] = 0x12; |
| 990 | slice[127] = 0x34; | 565 | slice[127] = 0x34; |
| 991 | allocator.free(slice); | 566 | allocator.free(slice); |
| ... | @@ -997,7 +572,7 @@ test "PageAllocator" { | ... | @@ -997,7 +572,7 @@ test "PageAllocator" { |
| 997 | } | 572 | } |
| 998 | } | 573 | } |
| 999 | 574 | ||
| 1000 | test "HeapAllocator" { | 575 | test HeapAllocator { |
| 1001 | if (builtin.os.tag == .windows) { | 576 | if (builtin.os.tag == .windows) { |
| 1002 | // https://github.com/ziglang/zig/issues/13702 | 577 | // https://github.com/ziglang/zig/issues/13702 |
| 1003 | if (builtin.cpu.arch == .aarch64) return error.SkipZigTest; | 578 | if (builtin.cpu.arch == .aarch64) return error.SkipZigTest; |
| ... | @@ -1013,7 +588,7 @@ test "HeapAllocator" { | ... | @@ -1013,7 +588,7 @@ test "HeapAllocator" { |
| 1013 | } | 588 | } |
| 1014 | } | 589 | } |
| 1015 | 590 | ||
| 1016 | test "ArenaAllocator" { | 591 | test ArenaAllocator { |
| 1017 | var arena_allocator = ArenaAllocator.init(page_allocator); | 592 | var arena_allocator = ArenaAllocator.init(page_allocator); |
| 1018 | defer arena_allocator.deinit(); | 593 | defer arena_allocator.deinit(); |
| 1019 | const allocator = arena_allocator.allocator(); | 594 | const allocator = arena_allocator.allocator(); |
| ... | @@ -1024,38 +599,6 @@ test "ArenaAllocator" { | ... | @@ -1024,38 +599,6 @@ test "ArenaAllocator" { |
| 1024 | try testAllocatorAlignedShrink(allocator); | 599 | try testAllocatorAlignedShrink(allocator); |
| 1025 | } | 600 | } |
| 1026 | 601 | ||
| 1027 | var test_fixed_buffer_allocator_memory: [800000 * @sizeOf(u64)]u8 = undefined; | ||
| 1028 | test "FixedBufferAllocator" { | ||
| 1029 | var fixed_buffer_allocator = mem.validationWrap(FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..])); | ||
| 1030 | const allocator = fixed_buffer_allocator.allocator(); | ||
| 1031 | |||
| 1032 | try testAllocator(allocator); | ||
| 1033 | try testAllocatorAligned(allocator); | ||
| 1034 | try testAllocatorLargeAlignment(allocator); | ||
| 1035 | try testAllocatorAlignedShrink(allocator); | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | test "FixedBufferAllocator.reset" { | ||
| 1039 | var buf: [8]u8 align(@alignOf(u64)) = undefined; | ||
| 1040 | var fba = FixedBufferAllocator.init(buf[0..]); | ||
| 1041 | const allocator = fba.allocator(); | ||
| 1042 | |||
| 1043 | const X = 0xeeeeeeeeeeeeeeee; | ||
| 1044 | const Y = 0xffffffffffffffff; | ||
| 1045 | |||
| 1046 | const x = try allocator.create(u64); | ||
| 1047 | x.* = X; | ||
| 1048 | try testing.expectError(error.OutOfMemory, allocator.create(u64)); | ||
| 1049 | |||
| 1050 | fba.reset(); | ||
| 1051 | const y = try allocator.create(u64); | ||
| 1052 | y.* = Y; | ||
| 1053 | |||
| 1054 | // we expect Y to have overwritten X. | ||
| 1055 | try testing.expect(x.* == y.*); | ||
| 1056 | try testing.expect(y.* == Y); | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | test "StackFallbackAllocator" { | 602 | test "StackFallbackAllocator" { |
| 1060 | { | 603 | { |
| 1061 | var stack_allocator = stackFallback(4096, std.testing.allocator); | 604 | var stack_allocator = stackFallback(4096, std.testing.allocator); |
| ... | @@ -1075,46 +618,6 @@ test "StackFallbackAllocator" { | ... | @@ -1075,46 +618,6 @@ test "StackFallbackAllocator" { |
| 1075 | } | 618 | } |
| 1076 | } | 619 | } |
| 1077 | 620 | ||
| 1078 | test "FixedBufferAllocator Reuse memory on realloc" { | ||
| 1079 | var small_fixed_buffer: [10]u8 = undefined; | ||
| 1080 | // check if we re-use the memory | ||
| 1081 | { | ||
| 1082 | var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]); | ||
| 1083 | const allocator = fixed_buffer_allocator.allocator(); | ||
| 1084 | |||
| 1085 | const slice0 = try allocator.alloc(u8, 5); | ||
| 1086 | try testing.expect(slice0.len == 5); | ||
| 1087 | const slice1 = try allocator.realloc(slice0, 10); | ||
| 1088 | try testing.expect(slice1.ptr == slice0.ptr); | ||
| 1089 | try testing.expect(slice1.len == 10); | ||
| 1090 | try testing.expectError(error.OutOfMemory, allocator.realloc(slice1, 11)); | ||
| 1091 | } | ||
| 1092 | // check that we don't re-use the memory if it's not the most recent block | ||
| 1093 | { | ||
| 1094 | var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]); | ||
| 1095 | const allocator = fixed_buffer_allocator.allocator(); | ||
| 1096 | |||
| 1097 | var slice0 = try allocator.alloc(u8, 2); | ||
| 1098 | slice0[0] = 1; | ||
| 1099 | slice0[1] = 2; | ||
| 1100 | const slice1 = try allocator.alloc(u8, 2); | ||
| 1101 | const slice2 = try allocator.realloc(slice0, 4); | ||
| 1102 | try testing.expect(slice0.ptr != slice2.ptr); | ||
| 1103 | try testing.expect(slice1.ptr != slice2.ptr); | ||
| 1104 | try testing.expect(slice2[0] == 1); | ||
| 1105 | try testing.expect(slice2[1] == 2); | ||
| 1106 | } | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | test "Thread safe FixedBufferAllocator" { | ||
| 1110 | var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]); | ||
| 1111 | |||
| 1112 | try testAllocator(fixed_buffer_allocator.threadSafeAllocator()); | ||
| 1113 | try testAllocatorAligned(fixed_buffer_allocator.threadSafeAllocator()); | ||
| 1114 | try testAllocatorLargeAlignment(fixed_buffer_allocator.threadSafeAllocator()); | ||
| 1115 | try testAllocatorAlignedShrink(fixed_buffer_allocator.threadSafeAllocator()); | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | /// This one should not try alignments that exceed what C malloc can handle. | 621 | /// This one should not try alignments that exceed what C malloc can handle. |
| 1119 | pub fn testAllocator(base_allocator: mem.Allocator) !void { | 622 | pub fn testAllocator(base_allocator: mem.Allocator) !void { |
| 1120 | var validationAllocator = mem.validationWrap(base_allocator); | 623 | var validationAllocator = mem.validationWrap(base_allocator); |
| ... | @@ -1194,7 +697,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void { | ... | @@ -1194,7 +697,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void { |
| 1194 | var validationAllocator = mem.validationWrap(base_allocator); | 697 | var validationAllocator = mem.validationWrap(base_allocator); |
| 1195 | const allocator = validationAllocator.allocator(); | 698 | const allocator = validationAllocator.allocator(); |
| 1196 | 699 | ||
| 1197 | const large_align: usize = min_page_size / 2; | 700 | const large_align: usize = page_size_min / 2; |
| 1198 | 701 | ||
| 1199 | var align_mask: usize = undefined; | 702 | var align_mask: usize = undefined; |
| 1200 | align_mask = @shlWithOverflow(~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)))[0]; | 703 | align_mask = @shlWithOverflow(~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)))[0]; |
| ... | @@ -1251,19 +754,296 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void { | ... | @@ -1251,19 +754,296 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void { |
| 1251 | try testing.expect(slice[60] == 0x34); | 754 | try testing.expect(slice[60] == 0x34); |
| 1252 | } | 755 | } |
| 1253 | 756 | ||
| 1254 | test "pageSize() smoke test" { | 757 | const page_size_min_default: ?usize = switch (builtin.os.tag) { |
| 1255 | const size = std.heap.pageSize(); | 758 | .driverkit, .ios, .macos, .tvos, .visionos, .watchos => switch (builtin.cpu.arch) { |
| 1256 | // Check that pageSize is a power of 2. | 759 | .x86_64 => 4 << 10, |
| 1257 | std.debug.assert(size & (size - 1) == 0); | 760 | .aarch64 => 16 << 10, |
| 1258 | } | 761 | else => null, |
| 762 | }, | ||
| 763 | .windows => switch (builtin.cpu.arch) { | ||
| 764 | // -- <https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200> | ||
| 765 | .x86, .x86_64 => 4 << 10, | ||
| 766 | // SuperH => 4 << 10, | ||
| 767 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 768 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10, | ||
| 769 | // DEC Alpha => 8 << 10, | ||
| 770 | // Itanium => 8 << 10, | ||
| 771 | .thumb, .thumbeb, .arm, .armeb, .aarch64, .aarch64_be => 4 << 10, | ||
| 772 | else => null, | ||
| 773 | }, | ||
| 774 | .wasi => switch (builtin.cpu.arch) { | ||
| 775 | .wasm32, .wasm64 => 64 << 10, | ||
| 776 | else => null, | ||
| 777 | }, | ||
| 778 | // https://github.com/tianocore/edk2/blob/b158dad150bf02879668f72ce306445250838201/MdePkg/Include/Uefi/UefiBaseType.h#L180-L187 | ||
| 779 | .uefi => 4 << 10, | ||
| 780 | .freebsd => switch (builtin.cpu.arch) { | ||
| 781 | // FreeBSD/sys/* | ||
| 782 | .x86, .x86_64 => 4 << 10, | ||
| 783 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 784 | .aarch64, .aarch64_be => 4 << 10, | ||
| 785 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 786 | .riscv32, .riscv64 => 4 << 10, | ||
| 787 | else => null, | ||
| 788 | }, | ||
| 789 | .netbsd => switch (builtin.cpu.arch) { | ||
| 790 | // NetBSD/sys/arch/* | ||
| 791 | .x86, .x86_64 => 4 << 10, | ||
| 792 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 793 | .aarch64, .aarch64_be => 4 << 10, | ||
| 794 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 795 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 796 | .sparc => 4 << 10, | ||
| 797 | .sparc64 => 8 << 10, | ||
| 798 | .riscv32, .riscv64 => 4 << 10, | ||
| 799 | // Sun-2 | ||
| 800 | .m68k => 2 << 10, | ||
| 801 | else => null, | ||
| 802 | }, | ||
| 803 | .dragonfly => switch (builtin.cpu.arch) { | ||
| 804 | .x86, .x86_64 => 4 << 10, | ||
| 805 | else => null, | ||
| 806 | }, | ||
| 807 | .openbsd => switch (builtin.cpu.arch) { | ||
| 808 | // OpenBSD/sys/arch/* | ||
| 809 | .x86, .x86_64 => 4 << 10, | ||
| 810 | .thumb, .thumbeb, .arm, .armeb, .aarch64, .aarch64_be => 4 << 10, | ||
| 811 | .mips64, .mips64el => 4 << 10, | ||
| 812 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 813 | .riscv64 => 4 << 10, | ||
| 814 | .sparc64 => 8 << 10, | ||
| 815 | else => null, | ||
| 816 | }, | ||
| 817 | .solaris, .illumos => switch (builtin.cpu.arch) { | ||
| 818 | // src/uts/*/sys/machparam.h | ||
| 819 | .x86, .x86_64 => 4 << 10, | ||
| 820 | .sparc, .sparc64 => 8 << 10, | ||
| 821 | else => null, | ||
| 822 | }, | ||
| 823 | .fuchsia => switch (builtin.cpu.arch) { | ||
| 824 | // fuchsia/kernel/arch/*/include/arch/defines.h | ||
| 825 | .x86_64 => 4 << 10, | ||
| 826 | .aarch64, .aarch64_be => 4 << 10, | ||
| 827 | .riscv64 => 4 << 10, | ||
| 828 | else => null, | ||
| 829 | }, | ||
| 830 | // https://github.com/SerenityOS/serenity/blob/62b938b798dc009605b5df8a71145942fc53808b/Kernel/API/POSIX/sys/limits.h#L11-L13 | ||
| 831 | .serenity => 4 << 10, | ||
| 832 | .haiku => switch (builtin.cpu.arch) { | ||
| 833 | // haiku/headers/posix/arch/*/limits.h | ||
| 834 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 835 | .aarch64, .aarch64_be => 4 << 10, | ||
| 836 | .m68k => 4 << 10, | ||
| 837 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 838 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 839 | .riscv64 => 4 << 10, | ||
| 840 | .sparc64 => 8 << 10, | ||
| 841 | .x86, .x86_64 => 4 << 10, | ||
| 842 | else => null, | ||
| 843 | }, | ||
| 844 | .hurd => switch (builtin.cpu.arch) { | ||
| 845 | // gnumach/*/include/mach/*/vm_param.h | ||
| 846 | .x86, .x86_64 => 4 << 10, | ||
| 847 | .aarch64 => null, | ||
| 848 | else => null, | ||
| 849 | }, | ||
| 850 | .plan9 => switch (builtin.cpu.arch) { | ||
| 851 | // 9front/sys/src/9/*/mem.h | ||
| 852 | .x86, .x86_64 => 4 << 10, | ||
| 853 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 854 | .aarch64, .aarch64_be => 4 << 10, | ||
| 855 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 856 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10, | ||
| 857 | .sparc => 4 << 10, | ||
| 858 | else => null, | ||
| 859 | }, | ||
| 860 | .ps3 => switch (builtin.cpu.arch) { | ||
| 861 | // cell/SDK_doc/en/html/C_and_C++_standard_libraries/stdlib.html | ||
| 862 | .powerpc64 => 1 << 20, // 1 MiB | ||
| 863 | else => null, | ||
| 864 | }, | ||
| 865 | .ps4 => switch (builtin.cpu.arch) { | ||
| 866 | // https://github.com/ps4dev/ps4sdk/blob/4df9d001b66ae4ec07d9a51b62d1e4c5e270eecc/include/machine/param.h#L95 | ||
| 867 | .x86, .x86_64 => 4 << 10, | ||
| 868 | else => null, | ||
| 869 | }, | ||
| 870 | .ps5 => switch (builtin.cpu.arch) { | ||
| 871 | // https://github.com/PS5Dev/PS5SDK/blob/a2e03a2a0231a3a3397fa6cd087a01ca6d04f273/include/machine/param.h#L95 | ||
| 872 | .x86, .x86_64 => 16 << 10, | ||
| 873 | else => null, | ||
| 874 | }, | ||
| 875 | // system/lib/libc/musl/arch/emscripten/bits/limits.h | ||
| 876 | .emscripten => 64 << 10, | ||
| 877 | .linux => switch (builtin.cpu.arch) { | ||
| 878 | // Linux/arch/*/Kconfig | ||
| 879 | .arc => 4 << 10, | ||
| 880 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 881 | .aarch64, .aarch64_be => 4 << 10, | ||
| 882 | .csky => 4 << 10, | ||
| 883 | .hexagon => 4 << 10, | ||
| 884 | .loongarch32, .loongarch64 => 4 << 10, | ||
| 885 | .m68k => 4 << 10, | ||
| 886 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 887 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 888 | .riscv32, .riscv64 => 4 << 10, | ||
| 889 | .s390x => 4 << 10, | ||
| 890 | .sparc => 4 << 10, | ||
| 891 | .sparc64 => 8 << 10, | ||
| 892 | .x86, .x86_64 => 4 << 10, | ||
| 893 | .xtensa => 4 << 10, | ||
| 894 | else => null, | ||
| 895 | }, | ||
| 896 | .freestanding => switch (builtin.cpu.arch) { | ||
| 897 | .wasm32, .wasm64 => 64 << 10, | ||
| 898 | else => null, | ||
| 899 | }, | ||
| 900 | else => null, | ||
| 901 | }; | ||
| 1259 | 902 | ||
| 1260 | test "defaultQueryPageSize() smoke test" { | 903 | const page_size_max_default: ?usize = switch (builtin.os.tag) { |
| 1261 | // queryPageSize() does not always get called by pageSize() | 904 | .driverkit, .ios, .macos, .tvos, .visionos, .watchos => switch (builtin.cpu.arch) { |
| 1262 | if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; | 905 | .x86_64 => 4 << 10, |
| 1263 | const size = defaultQueryPageSize(); | 906 | .aarch64 => 16 << 10, |
| 1264 | // Check that pageSize is a power of 2. | 907 | else => null, |
| 1265 | std.debug.assert(size & (size - 1) == 0); | 908 | }, |
| 1266 | } | 909 | .windows => switch (builtin.cpu.arch) { |
| 910 | // -- <https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200> | ||
| 911 | .x86, .x86_64 => 4 << 10, | ||
| 912 | // SuperH => 4 << 10, | ||
| 913 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 914 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10, | ||
| 915 | // DEC Alpha => 8 << 10, | ||
| 916 | // Itanium => 8 << 10, | ||
| 917 | .thumb, .thumbeb, .arm, .armeb, .aarch64, .aarch64_be => 4 << 10, | ||
| 918 | else => null, | ||
| 919 | }, | ||
| 920 | .wasi => switch (builtin.cpu.arch) { | ||
| 921 | .wasm32, .wasm64 => 64 << 10, | ||
| 922 | else => null, | ||
| 923 | }, | ||
| 924 | // https://github.com/tianocore/edk2/blob/b158dad150bf02879668f72ce306445250838201/MdePkg/Include/Uefi/UefiBaseType.h#L180-L187 | ||
| 925 | .uefi => 4 << 10, | ||
| 926 | .freebsd => switch (builtin.cpu.arch) { | ||
| 927 | // FreeBSD/sys/* | ||
| 928 | .x86, .x86_64 => 4 << 10, | ||
| 929 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 930 | .aarch64, .aarch64_be => 4 << 10, | ||
| 931 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 932 | .riscv32, .riscv64 => 4 << 10, | ||
| 933 | else => null, | ||
| 934 | }, | ||
| 935 | .netbsd => switch (builtin.cpu.arch) { | ||
| 936 | // NetBSD/sys/arch/* | ||
| 937 | .x86, .x86_64 => 4 << 10, | ||
| 938 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 939 | .aarch64, .aarch64_be => 64 << 10, | ||
| 940 | .mips, .mipsel, .mips64, .mips64el => 16 << 10, | ||
| 941 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 16 << 10, | ||
| 942 | .sparc => 8 << 10, | ||
| 943 | .sparc64 => 8 << 10, | ||
| 944 | .riscv32, .riscv64 => 4 << 10, | ||
| 945 | .m68k => 8 << 10, | ||
| 946 | else => null, | ||
| 947 | }, | ||
| 948 | .dragonfly => switch (builtin.cpu.arch) { | ||
| 949 | .x86, .x86_64 => 4 << 10, | ||
| 950 | else => null, | ||
| 951 | }, | ||
| 952 | .openbsd => switch (builtin.cpu.arch) { | ||
| 953 | // OpenBSD/sys/arch/* | ||
| 954 | .x86, .x86_64 => 4 << 10, | ||
| 955 | .thumb, .thumbeb, .arm, .armeb, .aarch64, .aarch64_be => 4 << 10, | ||
| 956 | .mips64, .mips64el => 16 << 10, | ||
| 957 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 958 | .riscv64 => 4 << 10, | ||
| 959 | .sparc64 => 8 << 10, | ||
| 960 | else => null, | ||
| 961 | }, | ||
| 962 | .solaris, .illumos => switch (builtin.cpu.arch) { | ||
| 963 | // src/uts/*/sys/machparam.h | ||
| 964 | .x86, .x86_64 => 4 << 10, | ||
| 965 | .sparc, .sparc64 => 8 << 10, | ||
| 966 | else => null, | ||
| 967 | }, | ||
| 968 | .fuchsia => switch (builtin.cpu.arch) { | ||
| 969 | // fuchsia/kernel/arch/*/include/arch/defines.h | ||
| 970 | .x86_64 => 4 << 10, | ||
| 971 | .aarch64, .aarch64_be => 4 << 10, | ||
| 972 | .riscv64 => 4 << 10, | ||
| 973 | else => null, | ||
| 974 | }, | ||
| 975 | // https://github.com/SerenityOS/serenity/blob/62b938b798dc009605b5df8a71145942fc53808b/Kernel/API/POSIX/sys/limits.h#L11-L13 | ||
| 976 | .serenity => 4 << 10, | ||
| 977 | .haiku => switch (builtin.cpu.arch) { | ||
| 978 | // haiku/headers/posix/arch/*/limits.h | ||
| 979 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 980 | .aarch64, .aarch64_be => 4 << 10, | ||
| 981 | .m68k => 4 << 10, | ||
| 982 | .mips, .mipsel, .mips64, .mips64el => 4 << 10, | ||
| 983 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 4 << 10, | ||
| 984 | .riscv64 => 4 << 10, | ||
| 985 | .sparc64 => 8 << 10, | ||
| 986 | .x86, .x86_64 => 4 << 10, | ||
| 987 | else => null, | ||
| 988 | }, | ||
| 989 | .hurd => switch (builtin.cpu.arch) { | ||
| 990 | // gnumach/*/include/mach/*/vm_param.h | ||
| 991 | .x86, .x86_64 => 4 << 10, | ||
| 992 | .aarch64 => null, | ||
| 993 | else => null, | ||
| 994 | }, | ||
| 995 | .plan9 => switch (builtin.cpu.arch) { | ||
| 996 | // 9front/sys/src/9/*/mem.h | ||
| 997 | .x86, .x86_64 => 4 << 10, | ||
| 998 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 999 | .aarch64, .aarch64_be => 64 << 10, | ||
| 1000 | .mips, .mipsel, .mips64, .mips64el => 16 << 10, | ||
| 1001 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10, | ||
| 1002 | .sparc => 4 << 10, | ||
| 1003 | else => null, | ||
| 1004 | }, | ||
| 1005 | .ps3 => switch (builtin.cpu.arch) { | ||
| 1006 | // cell/SDK_doc/en/html/C_and_C++_standard_libraries/stdlib.html | ||
| 1007 | .powerpc64 => 1 << 20, // 1 MiB | ||
| 1008 | else => null, | ||
| 1009 | }, | ||
| 1010 | .ps4 => switch (builtin.cpu.arch) { | ||
| 1011 | // https://github.com/ps4dev/ps4sdk/blob/4df9d001b66ae4ec07d9a51b62d1e4c5e270eecc/include/machine/param.h#L95 | ||
| 1012 | .x86, .x86_64 => 4 << 10, | ||
| 1013 | else => null, | ||
| 1014 | }, | ||
| 1015 | .ps5 => switch (builtin.cpu.arch) { | ||
| 1016 | // https://github.com/PS5Dev/PS5SDK/blob/a2e03a2a0231a3a3397fa6cd087a01ca6d04f273/include/machine/param.h#L95 | ||
| 1017 | .x86, .x86_64 => 16 << 10, | ||
| 1018 | else => null, | ||
| 1019 | }, | ||
| 1020 | // system/lib/libc/musl/arch/emscripten/bits/limits.h | ||
| 1021 | .emscripten => 64 << 10, | ||
| 1022 | .linux => switch (builtin.cpu.arch) { | ||
| 1023 | // Linux/arch/*/Kconfig | ||
| 1024 | .arc => 16 << 10, | ||
| 1025 | .thumb, .thumbeb, .arm, .armeb => 4 << 10, | ||
| 1026 | .aarch64, .aarch64_be => 64 << 10, | ||
| 1027 | .csky => 4 << 10, | ||
| 1028 | .hexagon => 256 << 10, | ||
| 1029 | .loongarch32, .loongarch64 => 64 << 10, | ||
| 1030 | .m68k => 8 << 10, | ||
| 1031 | .mips, .mipsel, .mips64, .mips64el => 64 << 10, | ||
| 1032 | .powerpc, .powerpc64, .powerpc64le, .powerpcle => 256 << 10, | ||
| 1033 | .riscv32, .riscv64 => 4 << 10, | ||
| 1034 | .s390x => 4 << 10, | ||
| 1035 | .sparc => 4 << 10, | ||
| 1036 | .sparc64 => 8 << 10, | ||
| 1037 | .x86, .x86_64 => 4 << 10, | ||
| 1038 | .xtensa => 4 << 10, | ||
| 1039 | else => null, | ||
| 1040 | }, | ||
| 1041 | .freestanding => switch (builtin.cpu.arch) { | ||
| 1042 | .wasm32, .wasm64 => 64 << 10, | ||
| 1043 | else => null, | ||
| 1044 | }, | ||
| 1045 | else => null, | ||
| 1046 | }; | ||
| 1267 | 1047 | ||
| 1268 | test { | 1048 | test { |
| 1269 | _ = LoggingAllocator; | 1049 | _ = LoggingAllocator; |
| ... | @@ -1272,6 +1052,7 @@ test { | ... | @@ -1272,6 +1052,7 @@ test { |
| 1272 | _ = @import("heap/memory_pool.zig"); | 1052 | _ = @import("heap/memory_pool.zig"); |
| 1273 | _ = ArenaAllocator; | 1053 | _ = ArenaAllocator; |
| 1274 | _ = GeneralPurposeAllocator; | 1054 | _ = GeneralPurposeAllocator; |
| 1055 | _ = FixedBufferAllocator; | ||
| 1275 | if (builtin.target.isWasm()) { | 1056 | if (builtin.target.isWasm()) { |
| 1276 | _ = WasmAllocator; | 1057 | _ = WasmAllocator; |
| 1277 | } | 1058 | } |
lib/std/heap/FixedBufferAllocator.zig created+218| ... | @@ -0,0 +1,218 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const Allocator = std.mem.Allocator; | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const mem = std.mem; | ||
| 5 | |||
| 6 | const FixedBufferAllocator = @This(); | ||
| 7 | |||
| 8 | end_index: usize, | ||
| 9 | buffer: []u8, | ||
| 10 | |||
| 11 | pub fn init(buffer: []u8) FixedBufferAllocator { | ||
| 12 | return FixedBufferAllocator{ | ||
| 13 | .buffer = buffer, | ||
| 14 | .end_index = 0, | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | /// Using this at the same time as the interface returned by `threadSafeAllocator` is not thread safe. | ||
| 19 | pub fn allocator(self: *FixedBufferAllocator) Allocator { | ||
| 20 | return .{ | ||
| 21 | .ptr = self, | ||
| 22 | .vtable = &.{ | ||
| 23 | .alloc = alloc, | ||
| 24 | .resize = resize, | ||
| 25 | .free = free, | ||
| 26 | }, | ||
| 27 | }; | ||
| 28 | } | ||
| 29 | |||
| 30 | /// Provides a lock free thread safe `Allocator` interface to the underlying `FixedBufferAllocator` | ||
| 31 | /// | ||
| 32 | /// Using this at the same time as the interface returned by `allocator` is not thread safe. | ||
| 33 | pub fn threadSafeAllocator(self: *FixedBufferAllocator) Allocator { | ||
| 34 | return .{ | ||
| 35 | .ptr = self, | ||
| 36 | .vtable = &.{ | ||
| 37 | .alloc = threadSafeAlloc, | ||
| 38 | .resize = Allocator.noResize, | ||
| 39 | .free = Allocator.noFree, | ||
| 40 | }, | ||
| 41 | }; | ||
| 42 | } | ||
| 43 | |||
| 44 | pub fn ownsPtr(self: *FixedBufferAllocator, ptr: [*]u8) bool { | ||
| 45 | return sliceContainsPtr(self.buffer, ptr); | ||
| 46 | } | ||
| 47 | |||
| 48 | pub fn ownsSlice(self: *FixedBufferAllocator, slice: []u8) bool { | ||
| 49 | return sliceContainsSlice(self.buffer, slice); | ||
| 50 | } | ||
| 51 | |||
| 52 | /// This has false negatives when the last allocation had an | ||
| 53 | /// adjusted_index. In such case we won't be able to determine what the | ||
| 54 | /// last allocation was because the alignForward operation done in alloc is | ||
| 55 | /// not reversible. | ||
| 56 | pub fn isLastAllocation(self: *FixedBufferAllocator, buf: []u8) bool { | ||
| 57 | return buf.ptr + buf.len == self.buffer.ptr + self.end_index; | ||
| 58 | } | ||
| 59 | |||
| 60 | pub fn alloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 { | ||
| 61 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | ||
| 62 | _ = ra; | ||
| 63 | const ptr_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align)); | ||
| 64 | const adjust_off = mem.alignPointerOffset(self.buffer.ptr + self.end_index, ptr_align) orelse return null; | ||
| 65 | const adjusted_index = self.end_index + adjust_off; | ||
| 66 | const new_end_index = adjusted_index + n; | ||
| 67 | if (new_end_index > self.buffer.len) return null; | ||
| 68 | self.end_index = new_end_index; | ||
| 69 | return self.buffer.ptr + adjusted_index; | ||
| 70 | } | ||
| 71 | |||
| 72 | pub fn resize( | ||
| 73 | ctx: *anyopaque, | ||
| 74 | buf: []u8, | ||
| 75 | log2_buf_align: u8, | ||
| 76 | new_size: usize, | ||
| 77 | return_address: usize, | ||
| 78 | ) bool { | ||
| 79 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | ||
| 80 | _ = log2_buf_align; | ||
| 81 | _ = return_address; | ||
| 82 | assert(@inComptime() or self.ownsSlice(buf)); | ||
| 83 | |||
| 84 | if (!self.isLastAllocation(buf)) { | ||
| 85 | if (new_size > buf.len) return false; | ||
| 86 | return true; | ||
| 87 | } | ||
| 88 | |||
| 89 | if (new_size <= buf.len) { | ||
| 90 | const sub = buf.len - new_size; | ||
| 91 | self.end_index -= sub; | ||
| 92 | return true; | ||
| 93 | } | ||
| 94 | |||
| 95 | const add = new_size - buf.len; | ||
| 96 | if (add + self.end_index > self.buffer.len) return false; | ||
| 97 | |||
| 98 | self.end_index += add; | ||
| 99 | return true; | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn free( | ||
| 103 | ctx: *anyopaque, | ||
| 104 | buf: []u8, | ||
| 105 | log2_buf_align: u8, | ||
| 106 | return_address: usize, | ||
| 107 | ) void { | ||
| 108 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | ||
| 109 | _ = log2_buf_align; | ||
| 110 | _ = return_address; | ||
| 111 | assert(@inComptime() or self.ownsSlice(buf)); | ||
| 112 | |||
| 113 | if (self.isLastAllocation(buf)) { | ||
| 114 | self.end_index -= buf.len; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | fn threadSafeAlloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 { | ||
| 119 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | ||
| 120 | _ = ra; | ||
| 121 | const ptr_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align)); | ||
| 122 | var end_index = @atomicLoad(usize, &self.end_index, .seq_cst); | ||
| 123 | while (true) { | ||
| 124 | const adjust_off = mem.alignPointerOffset(self.buffer.ptr + end_index, ptr_align) orelse return null; | ||
| 125 | const adjusted_index = end_index + adjust_off; | ||
| 126 | const new_end_index = adjusted_index + n; | ||
| 127 | if (new_end_index > self.buffer.len) return null; | ||
| 128 | end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, .seq_cst, .seq_cst) orelse | ||
| 129 | return self.buffer[adjusted_index..new_end_index].ptr; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | pub fn reset(self: *FixedBufferAllocator) void { | ||
| 134 | self.end_index = 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | fn sliceContainsPtr(container: []u8, ptr: [*]u8) bool { | ||
| 138 | return @intFromPtr(ptr) >= @intFromPtr(container.ptr) and | ||
| 139 | @intFromPtr(ptr) < (@intFromPtr(container.ptr) + container.len); | ||
| 140 | } | ||
| 141 | |||
| 142 | fn sliceContainsSlice(container: []u8, slice: []u8) bool { | ||
| 143 | return @intFromPtr(slice.ptr) >= @intFromPtr(container.ptr) and | ||
| 144 | (@intFromPtr(slice.ptr) + slice.len) <= (@intFromPtr(container.ptr) + container.len); | ||
| 145 | } | ||
| 146 | |||
| 147 | var test_fixed_buffer_allocator_memory: [800000 * @sizeOf(u64)]u8 = undefined; | ||
| 148 | |||
| 149 | test FixedBufferAllocator { | ||
| 150 | var fixed_buffer_allocator = mem.validationWrap(FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..])); | ||
| 151 | const a = fixed_buffer_allocator.allocator(); | ||
| 152 | |||
| 153 | try std.heap.testAllocator(a); | ||
| 154 | try std.heap.testAllocatorAligned(a); | ||
| 155 | try std.heap.testAllocatorLargeAlignment(a); | ||
| 156 | try std.heap.testAllocatorAlignedShrink(a); | ||
| 157 | } | ||
| 158 | |||
| 159 | test reset { | ||
| 160 | var buf: [8]u8 align(@alignOf(u64)) = undefined; | ||
| 161 | var fba = FixedBufferAllocator.init(buf[0..]); | ||
| 162 | const a = fba.allocator(); | ||
| 163 | |||
| 164 | const X = 0xeeeeeeeeeeeeeeee; | ||
| 165 | const Y = 0xffffffffffffffff; | ||
| 166 | |||
| 167 | const x = try a.create(u64); | ||
| 168 | x.* = X; | ||
| 169 | try std.testing.expectError(error.OutOfMemory, a.create(u64)); | ||
| 170 | |||
| 171 | fba.reset(); | ||
| 172 | const y = try a.create(u64); | ||
| 173 | y.* = Y; | ||
| 174 | |||
| 175 | // we expect Y to have overwritten X. | ||
| 176 | try std.testing.expect(x.* == y.*); | ||
| 177 | try std.testing.expect(y.* == Y); | ||
| 178 | } | ||
| 179 | |||
| 180 | test "reuse memory on realloc" { | ||
| 181 | var small_fixed_buffer: [10]u8 = undefined; | ||
| 182 | // check if we re-use the memory | ||
| 183 | { | ||
| 184 | var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]); | ||
| 185 | const a = fixed_buffer_allocator.allocator(); | ||
| 186 | |||
| 187 | const slice0 = try a.alloc(u8, 5); | ||
| 188 | try std.testing.expect(slice0.len == 5); | ||
| 189 | const slice1 = try a.realloc(slice0, 10); | ||
| 190 | try std.testing.expect(slice1.ptr == slice0.ptr); | ||
| 191 | try std.testing.expect(slice1.len == 10); | ||
| 192 | try std.testing.expectError(error.OutOfMemory, a.realloc(slice1, 11)); | ||
| 193 | } | ||
| 194 | // check that we don't re-use the memory if it's not the most recent block | ||
| 195 | { | ||
| 196 | var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]); | ||
| 197 | const a = fixed_buffer_allocator.allocator(); | ||
| 198 | |||
| 199 | var slice0 = try a.alloc(u8, 2); | ||
| 200 | slice0[0] = 1; | ||
| 201 | slice0[1] = 2; | ||
| 202 | const slice1 = try a.alloc(u8, 2); | ||
| 203 | const slice2 = try a.realloc(slice0, 4); | ||
| 204 | try std.testing.expect(slice0.ptr != slice2.ptr); | ||
| 205 | try std.testing.expect(slice1.ptr != slice2.ptr); | ||
| 206 | try std.testing.expect(slice2[0] == 1); | ||
| 207 | try std.testing.expect(slice2[1] == 2); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | test "thread safe version" { | ||
| 212 | var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]); | ||
| 213 | |||
| 214 | try std.heap.testAllocator(fixed_buffer_allocator.threadSafeAllocator()); | ||
| 215 | try std.heap.testAllocatorAligned(fixed_buffer_allocator.threadSafeAllocator()); | ||
| 216 | try std.heap.testAllocatorLargeAlignment(fixed_buffer_allocator.threadSafeAllocator()); | ||
| 217 | try std.heap.testAllocatorAlignedShrink(fixed_buffer_allocator.threadSafeAllocator()); | ||
| 218 | } | ||
lib/std/heap/PageAllocator.zig+14-11| ... | @@ -2,14 +2,14 @@ const std = @import("../std.zig"); | ... | @@ -2,14 +2,14 @@ const std = @import("../std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const Allocator = std.mem.Allocator; | 3 | const Allocator = std.mem.Allocator; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const heap = std.heap; | ||
| 6 | const maxInt = std.math.maxInt; | 5 | const maxInt = std.math.maxInt; |
| 7 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 8 | const native_os = builtin.os.tag; | 7 | const native_os = builtin.os.tag; |
| 9 | const windows = std.os.windows; | 8 | const windows = std.os.windows; |
| 10 | const posix = std.posix; | 9 | const posix = std.posix; |
| 10 | const page_size_min = std.heap.page_size_min; | ||
| 11 | 11 | ||
| 12 | pub const vtable = Allocator.VTable{ | 12 | pub const vtable: Allocator.VTable = .{ |
| 13 | .alloc = alloc, | 13 | .alloc = alloc, |
| 14 | .resize = resize, | 14 | .resize = resize, |
| 15 | .free = free, | 15 | .free = free, |
| ... | @@ -19,7 +19,6 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 { | ... | @@ -19,7 +19,6 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 { |
| 19 | _ = ra; | 19 | _ = ra; |
| 20 | _ = log2_align; | 20 | _ = log2_align; |
| 21 | assert(n > 0); | 21 | assert(n > 0); |
| 22 | if (n > maxInt(usize) - (heap.pageSize() - 1)) return null; | ||
| 23 | 22 | ||
| 24 | if (native_os == .windows) { | 23 | if (native_os == .windows) { |
| 25 | const addr = windows.VirtualAlloc( | 24 | const addr = windows.VirtualAlloc( |
| ... | @@ -35,7 +34,10 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 { | ... | @@ -35,7 +34,10 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 { |
| 35 | return @ptrCast(addr); | 34 | return @ptrCast(addr); |
| 36 | } | 35 | } |
| 37 | 36 | ||
| 38 | const aligned_len = mem.alignForward(usize, n, heap.pageSize()); | 37 | const page_size = std.heap.pageSize(); |
| 38 | if (n >= maxInt(usize) - page_size) return null; | ||
| 39 | |||
| 40 | const aligned_len = mem.alignForward(usize, n, page_size); | ||
| 39 | const hint = @atomicLoad(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, .unordered); | 41 | const hint = @atomicLoad(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, .unordered); |
| 40 | const slice = posix.mmap( | 42 | const slice = posix.mmap( |
| 41 | hint, | 43 | hint, |
| ... | @@ -45,8 +47,8 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 { | ... | @@ -45,8 +47,8 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 { |
| 45 | -1, | 47 | -1, |
| 46 | 0, | 48 | 0, |
| 47 | ) catch return null; | 49 | ) catch return null; |
| 48 | assert(mem.isAligned(@intFromPtr(slice.ptr), heap.pageSize())); | 50 | assert(mem.isAligned(@intFromPtr(slice.ptr), page_size_min)); |
| 49 | const new_hint: [*]align(heap.min_page_size) u8 = @alignCast(slice.ptr + aligned_len); | 51 | const new_hint: [*]align(std.heap.page_size_min) u8 = @alignCast(slice.ptr + aligned_len); |
| 50 | _ = @cmpxchgStrong(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, hint, new_hint, .monotonic, .monotonic); | 52 | _ = @cmpxchgStrong(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, hint, new_hint, .monotonic, .monotonic); |
| 51 | return slice.ptr; | 53 | return slice.ptr; |
| 52 | } | 54 | } |
| ... | @@ -60,13 +62,14 @@ fn resize( | ... | @@ -60,13 +62,14 @@ fn resize( |
| 60 | ) bool { | 62 | ) bool { |
| 61 | _ = log2_buf_align; | 63 | _ = log2_buf_align; |
| 62 | _ = return_address; | 64 | _ = return_address; |
| 63 | const new_size_aligned = mem.alignForward(usize, new_size, heap.pageSize()); | 65 | const page_size = std.heap.pageSize(); |
| 66 | const new_size_aligned = mem.alignForward(usize, new_size, page_size); | ||
| 64 | 67 | ||
| 65 | if (native_os == .windows) { | 68 | if (native_os == .windows) { |
| 66 | if (new_size <= buf_unaligned.len) { | 69 | if (new_size <= buf_unaligned.len) { |
| 67 | const base_addr = @intFromPtr(buf_unaligned.ptr); | 70 | const base_addr = @intFromPtr(buf_unaligned.ptr); |
| 68 | const old_addr_end = base_addr + buf_unaligned.len; | 71 | const old_addr_end = base_addr + buf_unaligned.len; |
| 69 | const new_addr_end = mem.alignForward(usize, base_addr + new_size, heap.pageSize()); | 72 | const new_addr_end = mem.alignForward(usize, base_addr + new_size, page_size); |
| 70 | if (old_addr_end > new_addr_end) { | 73 | if (old_addr_end > new_addr_end) { |
| 71 | // For shrinking that is not releasing, we will only | 74 | // For shrinking that is not releasing, we will only |
| 72 | // decommit the pages not needed anymore. | 75 | // decommit the pages not needed anymore. |
| ... | @@ -78,14 +81,14 @@ fn resize( | ... | @@ -78,14 +81,14 @@ fn resize( |
| 78 | } | 81 | } |
| 79 | return true; | 82 | return true; |
| 80 | } | 83 | } |
| 81 | const old_size_aligned = mem.alignForward(usize, buf_unaligned.len, heap.pageSize()); | 84 | const old_size_aligned = mem.alignForward(usize, buf_unaligned.len, page_size); |
| 82 | if (new_size_aligned <= old_size_aligned) { | 85 | if (new_size_aligned <= old_size_aligned) { |
| 83 | return true; | 86 | return true; |
| 84 | } | 87 | } |
| 85 | return false; | 88 | return false; |
| 86 | } | 89 | } |
| 87 | 90 | ||
| 88 | const buf_aligned_len = mem.alignForward(usize, buf_unaligned.len, heap.pageSize()); | 91 | const buf_aligned_len = mem.alignForward(usize, buf_unaligned.len, page_size); |
| 89 | if (new_size_aligned == buf_aligned_len) | 92 | if (new_size_aligned == buf_aligned_len) |
| 90 | return true; | 93 | return true; |
| 91 | 94 | ||
| ... | @@ -108,7 +111,7 @@ fn free(_: *anyopaque, slice: []u8, log2_buf_align: u8, return_address: usize) v | ... | @@ -108,7 +111,7 @@ fn free(_: *anyopaque, slice: []u8, log2_buf_align: u8, return_address: usize) v |
| 108 | if (native_os == .windows) { | 111 | if (native_os == .windows) { |
| 109 | windows.VirtualFree(slice.ptr, 0, windows.MEM_RELEASE); | 112 | windows.VirtualFree(slice.ptr, 0, windows.MEM_RELEASE); |
| 110 | } else { | 113 | } else { |
| 111 | const buf_aligned_len = mem.alignForward(usize, slice.len, heap.pageSize()); | 114 | const buf_aligned_len = mem.alignForward(usize, slice.len, std.heap.pageSize()); |
| 112 | posix.munmap(@alignCast(slice.ptr[0..buf_aligned_len])); | 115 | posix.munmap(@alignCast(slice.ptr[0..buf_aligned_len])); |
| 113 | } | 116 | } |
| 114 | } | 117 | } |
lib/std/heap/general_purpose_allocator.zig+8-8| ... | @@ -75,7 +75,7 @@ | ... | @@ -75,7 +75,7 @@ |
| 75 | //! BucketHeader, followed by "used bits", and two stack traces for each slot | 75 | //! BucketHeader, followed by "used bits", and two stack traces for each slot |
| 76 | //! (allocation trace and free trace). | 76 | //! (allocation trace and free trace). |
| 77 | //! | 77 | //! |
| 78 | //! The buckets array contains buckets for every size class below `max_page_size`. | 78 | //! The buckets array contains buckets for every size class below `page_size_max`. |
| 79 | //! At runtime, only size classes below `pageSize()` will actually be used for allocations. | 79 | //! At runtime, only size classes below `pageSize()` will actually be used for allocations. |
| 80 | //! | 80 | //! |
| 81 | //! The "used bits" are 1 bit per slot representing whether the slot is used. | 81 | //! The "used bits" are 1 bit per slot representing whether the slot is used. |
| ... | @@ -102,13 +102,13 @@ const math = std.math; | ... | @@ -102,13 +102,13 @@ const math = std.math; |
| 102 | const assert = std.debug.assert; | 102 | const assert = std.debug.assert; |
| 103 | const mem = std.mem; | 103 | const mem = std.mem; |
| 104 | const Allocator = std.mem.Allocator; | 104 | const Allocator = std.mem.Allocator; |
| 105 | const min_page_size = std.heap.min_page_size; | 105 | const page_size_min = std.heap.page_size_min; |
| 106 | const max_page_size = std.heap.max_page_size; | 106 | const page_size_max = std.heap.page_size_max; |
| 107 | const pageSize = std.heap.pageSize; | 107 | const pageSize = std.heap.pageSize; |
| 108 | const StackTrace = std.builtin.StackTrace; | 108 | const StackTrace = std.builtin.StackTrace; |
| 109 | 109 | ||
| 110 | /// Integer type for pointing to slots in a small allocation | 110 | /// Integer type for pointing to slots in a small allocation |
| 111 | const SlotIndex = std.meta.Int(.unsigned, math.log2(max_page_size) + 1); | 111 | const SlotIndex = std.meta.Int(.unsigned, math.log2(page_size_max) + 1); |
| 112 | 112 | ||
| 113 | const default_test_stack_trace_frames: usize = if (builtin.is_test) 10 else 6; | 113 | const default_test_stack_trace_frames: usize = if (builtin.is_test) 10 else 6; |
| 114 | const default_sys_stack_trace_frames: usize = if (std.debug.sys_can_stack_trace) default_test_stack_trace_frames else 0; | 114 | const default_sys_stack_trace_frames: usize = if (std.debug.sys_can_stack_trace) default_test_stack_trace_frames else 0; |
| ... | @@ -214,7 +214,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -214,7 +214,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 214 | 214 | ||
| 215 | pub const Error = mem.Allocator.Error; | 215 | pub const Error = mem.Allocator.Error; |
| 216 | 216 | ||
| 217 | const small_bucket_count = math.log2(max_page_size); | 217 | const small_bucket_count = math.log2(page_size_max); |
| 218 | const largest_bucket_object_size = 1 << (small_bucket_count - 1); | 218 | const largest_bucket_object_size = 1 << (small_bucket_count - 1); |
| 219 | const LargestSizeClassInt = std.math.IntFittingRange(0, largest_bucket_object_size); | 219 | const LargestSizeClassInt = std.math.IntFittingRange(0, largest_bucket_object_size); |
| 220 | fn used_small_bucket_count() usize { | 220 | fn used_small_bucket_count() usize { |
| ... | @@ -287,7 +287,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -287,7 +287,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 287 | // * stack_trace_addresses: [N]usize, // traces_per_slot for every allocation | 287 | // * stack_trace_addresses: [N]usize, // traces_per_slot for every allocation |
| 288 | 288 | ||
| 289 | const BucketHeader = struct { | 289 | const BucketHeader = struct { |
| 290 | page: [*]align(min_page_size) u8, | 290 | page: [*]align(page_size_min) u8, |
| 291 | alloc_cursor: SlotIndex, | 291 | alloc_cursor: SlotIndex, |
| 292 | used_count: SlotIndex, | 292 | used_count: SlotIndex, |
| 293 | 293 | ||
| ... | @@ -591,7 +591,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -591,7 +591,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 591 | addr: usize, | 591 | addr: usize, |
| 592 | current_bucket: ?*BucketHeader, | 592 | current_bucket: ?*BucketHeader, |
| 593 | ) ?*BucketHeader { | 593 | ) ?*BucketHeader { |
| 594 | const search_page: [*]align(min_page_size) u8 = @ptrFromInt(mem.alignBackward(usize, addr, pageSize())); | 594 | const search_page: [*]align(page_size_min) u8 = @ptrFromInt(mem.alignBackward(usize, addr, pageSize())); |
| 595 | if (current_bucket != null and current_bucket.?.page == search_page) { | 595 | if (current_bucket != null and current_bucket.?.page == search_page) { |
| 596 | return current_bucket; | 596 | return current_bucket; |
| 597 | } | 597 | } |
| ... | @@ -1062,7 +1062,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -1062,7 +1062,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 1062 | } | 1062 | } |
| 1063 | 1063 | ||
| 1064 | fn createBucket(self: *Self, size_class: usize) Error!*BucketHeader { | 1064 | fn createBucket(self: *Self, size_class: usize) Error!*BucketHeader { |
| 1065 | const page = try self.backing_allocator.alignedAlloc(u8, min_page_size, pageSize()); | 1065 | const page = try self.backing_allocator.alignedAlloc(u8, page_size_min, pageSize()); |
| 1066 | errdefer self.backing_allocator.free(page); | 1066 | errdefer self.backing_allocator.free(page); |
| 1067 | 1067 | ||
| 1068 | const bucket_size = bucketSize(size_class); | 1068 | const bucket_size = bucketSize(size_class); |
lib/std/mem.zig+12-10| ... | @@ -1048,17 +1048,18 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co | ... | @@ -1048,17 +1048,18 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co |
| 1048 | // as we don't read into a new page. This should be the case for most architectures | 1048 | // as we don't read into a new page. This should be the case for most architectures |
| 1049 | // which use paged memory, however should be confirmed before adding a new arch below. | 1049 | // which use paged memory, however should be confirmed before adding a new arch below. |
| 1050 | .aarch64, .x86, .x86_64 => if (std.simd.suggestVectorLength(T)) |block_len| { | 1050 | .aarch64, .x86, .x86_64 => if (std.simd.suggestVectorLength(T)) |block_len| { |
| 1051 | const page_size = std.heap.pageSize(); | ||
| 1051 | const block_size = @sizeOf(T) * block_len; | 1052 | const block_size = @sizeOf(T) * block_len; |
| 1052 | const Block = @Vector(block_len, T); | 1053 | const Block = @Vector(block_len, T); |
| 1053 | const mask: Block = @splat(sentinel); | 1054 | const mask: Block = @splat(sentinel); |
| 1054 | 1055 | ||
| 1055 | comptime std.debug.assert(std.heap.max_page_size % @sizeOf(Block) == 0); | 1056 | comptime assert(std.heap.page_size_max % @sizeOf(Block) == 0); |
| 1056 | std.debug.assert(std.heap.pageSize() % @sizeOf(Block) == 0); | 1057 | assert(page_size % @sizeOf(Block) == 0); |
| 1057 | 1058 | ||
| 1058 | // First block may be unaligned | 1059 | // First block may be unaligned |
| 1059 | const start_addr = @intFromPtr(&p[i]); | 1060 | const start_addr = @intFromPtr(&p[i]); |
| 1060 | const offset_in_page = start_addr & (std.heap.pageSize() - 1); | 1061 | const offset_in_page = start_addr & (page_size - 1); |
| 1061 | if (offset_in_page <= std.heap.pageSize() - @sizeOf(Block)) { | 1062 | if (offset_in_page <= page_size - @sizeOf(Block)) { |
| 1062 | // Will not read past the end of a page, full block. | 1063 | // Will not read past the end of a page, full block. |
| 1063 | const block: Block = p[i..][0..block_len].*; | 1064 | const block: Block = p[i..][0..block_len].*; |
| 1064 | const matches = block == mask; | 1065 | const matches = block == mask; |
| ... | @@ -1078,7 +1079,7 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co | ... | @@ -1078,7 +1079,7 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co |
| 1078 | } | 1079 | } |
| 1079 | } | 1080 | } |
| 1080 | 1081 | ||
| 1081 | std.debug.assert(std.mem.isAligned(@intFromPtr(&p[i]), block_size)); | 1082 | assert(std.mem.isAligned(@intFromPtr(&p[i]), block_size)); |
| 1082 | while (true) { | 1083 | while (true) { |
| 1083 | const block: *const Block = @ptrCast(@alignCast(p[i..][0..block_len])); | 1084 | const block: *const Block = @ptrCast(@alignCast(p[i..][0..block_len])); |
| 1084 | const matches = block.* == mask; | 1085 | const matches = block.* == mask; |
| ... | @@ -1101,23 +1102,24 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co | ... | @@ -1101,23 +1102,24 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co |
| 1101 | test "indexOfSentinel vector paths" { | 1102 | test "indexOfSentinel vector paths" { |
| 1102 | const Types = [_]type{ u8, u16, u32, u64 }; | 1103 | const Types = [_]type{ u8, u16, u32, u64 }; |
| 1103 | const allocator = std.testing.allocator; | 1104 | const allocator = std.testing.allocator; |
| 1105 | const page_size = std.heap.pageSize(); | ||
| 1104 | 1106 | ||
| 1105 | inline for (Types) |T| { | 1107 | inline for (Types) |T| { |
| 1106 | const block_len = std.simd.suggestVectorLength(T) orelse continue; | 1108 | const block_len = std.simd.suggestVectorLength(T) orelse continue; |
| 1107 | 1109 | ||
| 1108 | // Allocate three pages so we guarantee a page-crossing address with a full page after | 1110 | // Allocate three pages so we guarantee a page-crossing address with a full page after |
| 1109 | const memory = try allocator.alloc(T, 3 * std.heap.pageSize() / @sizeOf(T)); | 1111 | const memory = try allocator.alloc(T, 3 * page_size / @sizeOf(T)); |
| 1110 | defer allocator.free(memory); | 1112 | defer allocator.free(memory); |
| 1111 | @memset(memory, 0xaa); | 1113 | @memset(memory, 0xaa); |
| 1112 | 1114 | ||
| 1113 | // Find starting page-alignment = 0 | 1115 | // Find starting page-alignment = 0 |
| 1114 | var start: usize = 0; | 1116 | var start: usize = 0; |
| 1115 | const start_addr = @intFromPtr(&memory); | 1117 | const start_addr = @intFromPtr(&memory); |
| 1116 | start += (std.mem.alignForward(usize, start_addr, std.heap.pageSize()) - start_addr) / @sizeOf(T); | 1118 | start += (std.mem.alignForward(usize, start_addr, page_size) - start_addr) / @sizeOf(T); |
| 1117 | try testing.expect(start < std.heap.pageSize() / @sizeOf(T)); | 1119 | try testing.expect(start < page_size / @sizeOf(T)); |
| 1118 | 1120 | ||
| 1119 | // Validate all sub-block alignments | 1121 | // Validate all sub-block alignments |
| 1120 | const search_len = std.heap.pageSize() / @sizeOf(T); | 1122 | const search_len = page_size / @sizeOf(T); |
| 1121 | memory[start + search_len] = 0; | 1123 | memory[start + search_len] = 0; |
| 1122 | for (0..block_len) |offset| { | 1124 | for (0..block_len) |offset| { |
| 1123 | try testing.expectEqual(search_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start + offset]))); | 1125 | try testing.expectEqual(search_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start + offset]))); |
| ... | @@ -1125,7 +1127,7 @@ test "indexOfSentinel vector paths" { | ... | @@ -1125,7 +1127,7 @@ test "indexOfSentinel vector paths" { |
| 1125 | memory[start + search_len] = 0xaa; | 1127 | memory[start + search_len] = 0xaa; |
| 1126 | 1128 | ||
| 1127 | // Validate page boundary crossing | 1129 | // Validate page boundary crossing |
| 1128 | const start_page_boundary = start + (std.heap.pageSize() / @sizeOf(T)); | 1130 | const start_page_boundary = start + (page_size / @sizeOf(T)); |
| 1129 | memory[start_page_boundary + block_len] = 0; | 1131 | memory[start_page_boundary + block_len] = 0; |
| 1130 | for (0..block_len) |offset| { | 1132 | for (0..block_len) |offset| { |
| 1131 | try testing.expectEqual(2 * block_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start_page_boundary - block_len + offset]))); | 1133 | try testing.expectEqual(2 * block_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start_page_boundary - block_len + offset]))); |
lib/std/mem/Allocator.zig+5-6| ... | @@ -18,11 +18,15 @@ ptr: *anyopaque, | ... | @@ -18,11 +18,15 @@ ptr: *anyopaque, |
| 18 | vtable: *const VTable, | 18 | vtable: *const VTable, |
| 19 | 19 | ||
| 20 | pub const VTable = struct { | 20 | pub const VTable = struct { |
| 21 | /// Attempt to allocate exactly `len` bytes aligned to `1 << ptr_align`. | 21 | /// Allocate exactly `len` bytes aligned to `1 << ptr_align`, or return `null` |
| 22 | /// indicating the allocation failed. | ||
| 22 | /// | 23 | /// |
| 23 | /// `ret_addr` is optionally provided as the first return address of the | 24 | /// `ret_addr` is optionally provided as the first return address of the |
| 24 | /// allocation call stack. If the value is `0` it means no return address | 25 | /// allocation call stack. If the value is `0` it means no return address |
| 25 | /// has been provided. | 26 | /// has been provided. |
| 27 | /// | ||
| 28 | /// The returned slice of memory must have been `@memset` to `undefined` | ||
| 29 | /// by the allocator implementation. | ||
| 26 | alloc: *const fn (ctx: *anyopaque, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8, | 30 | alloc: *const fn (ctx: *anyopaque, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8, |
| 27 | 31 | ||
| 28 | /// Attempt to expand or shrink memory in place. `buf.len` must equal the | 32 | /// Attempt to expand or shrink memory in place. `buf.len` must equal the |
| ... | @@ -215,11 +219,6 @@ fn allocWithSizeAndAlignment(self: Allocator, comptime size: usize, comptime ali | ... | @@ -215,11 +219,6 @@ fn allocWithSizeAndAlignment(self: Allocator, comptime size: usize, comptime ali |
| 215 | } | 219 | } |
| 216 | 220 | ||
| 217 | fn allocBytesWithAlignment(self: Allocator, comptime alignment: u29, byte_count: usize, return_address: usize) Error![*]align(alignment) u8 { | 221 | fn allocBytesWithAlignment(self: Allocator, comptime alignment: u29, byte_count: usize, return_address: usize) Error![*]align(alignment) u8 { |
| 218 | // The Zig Allocator interface is not intended to solve alignments beyond | ||
| 219 | // the minimum OS page size. For these use cases, the caller must use OS | ||
| 220 | // APIs directly. | ||
| 221 | if (!@inComptime() and alignment > std.heap.pageSize()) @panic("Alignment must be smaller than page size."); | ||
| 222 | |||
| 223 | if (byte_count == 0) { | 222 | if (byte_count == 0) { |
| 224 | const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), alignment); | 223 | const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), alignment); |
| 225 | return @as([*]align(alignment) u8, @ptrFromInt(ptr)); | 224 | return @as([*]align(alignment) u8, @ptrFromInt(ptr)); |
lib/std/os/linux/IoUring.zig+8-8| ... | @@ -3,12 +3,12 @@ const std = @import("std"); | ... | @@ -3,12 +3,12 @@ const std = @import("std"); |
| 3 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const heap = std.heap; | ||
| 7 | const net = std.net; | 6 | const net = std.net; |
| 8 | const posix = std.posix; | 7 | const posix = std.posix; |
| 9 | const linux = std.os.linux; | 8 | const linux = std.os.linux; |
| 10 | const testing = std.testing; | 9 | const testing = std.testing; |
| 11 | const is_linux = builtin.os.tag == .linux; | 10 | const is_linux = builtin.os.tag == .linux; |
| 11 | const page_size_min = std.heap.page_size_min; | ||
| 12 | 12 | ||
| 13 | fd: posix.fd_t = -1, | 13 | fd: posix.fd_t = -1, |
| 14 | sq: SubmissionQueue, | 14 | sq: SubmissionQueue, |
| ... | @@ -1342,8 +1342,8 @@ pub const SubmissionQueue = struct { | ... | @@ -1342,8 +1342,8 @@ pub const SubmissionQueue = struct { |
| 1342 | dropped: *u32, | 1342 | dropped: *u32, |
| 1343 | array: []u32, | 1343 | array: []u32, |
| 1344 | sqes: []linux.io_uring_sqe, | 1344 | sqes: []linux.io_uring_sqe, |
| 1345 | mmap: []align(heap.min_page_size) u8, | 1345 | mmap: []align(page_size_min) u8, |
| 1346 | mmap_sqes: []align(heap.min_page_size) u8, | 1346 | mmap_sqes: []align(page_size_min) u8, |
| 1347 | 1347 | ||
| 1348 | // We use `sqe_head` and `sqe_tail` in the same way as liburing: | 1348 | // We use `sqe_head` and `sqe_tail` in the same way as liburing: |
| 1349 | // We increment `sqe_tail` (but not `tail`) for each call to `get_sqe()`. | 1349 | // We increment `sqe_tail` (but not `tail`) for each call to `get_sqe()`. |
| ... | @@ -1461,7 +1461,7 @@ pub const BufferGroup = struct { | ... | @@ -1461,7 +1461,7 @@ pub const BufferGroup = struct { |
| 1461 | /// Pointer to the memory shared by the kernel. | 1461 | /// Pointer to the memory shared by the kernel. |
| 1462 | /// `buffers_count` of `io_uring_buf` structures are shared by the kernel. | 1462 | /// `buffers_count` of `io_uring_buf` structures are shared by the kernel. |
| 1463 | /// First `io_uring_buf` is overlaid by `io_uring_buf_ring` struct. | 1463 | /// First `io_uring_buf` is overlaid by `io_uring_buf_ring` struct. |
| 1464 | br: *align(heap.min_page_size) linux.io_uring_buf_ring, | 1464 | br: *align(page_size_min) linux.io_uring_buf_ring, |
| 1465 | /// Contiguous block of memory of size (buffers_count * buffer_size). | 1465 | /// Contiguous block of memory of size (buffers_count * buffer_size). |
| 1466 | buffers: []u8, | 1466 | buffers: []u8, |
| 1467 | /// Size of each buffer in buffers. | 1467 | /// Size of each buffer in buffers. |
| ... | @@ -1556,7 +1556,7 @@ pub const BufferGroup = struct { | ... | @@ -1556,7 +1556,7 @@ pub const BufferGroup = struct { |
| 1556 | /// `fd` is IO_Uring.fd for which the provided buffer ring is being registered. | 1556 | /// `fd` is IO_Uring.fd for which the provided buffer ring is being registered. |
| 1557 | /// `entries` is the number of entries requested in the buffer ring, must be power of 2. | 1557 | /// `entries` is the number of entries requested in the buffer ring, must be power of 2. |
| 1558 | /// `group_id` is the chosen buffer group ID, unique in IO_Uring. | 1558 | /// `group_id` is the chosen buffer group ID, unique in IO_Uring. |
| 1559 | pub fn setup_buf_ring(fd: posix.fd_t, entries: u16, group_id: u16) !*align(heap.min_page_size) linux.io_uring_buf_ring { | 1559 | pub fn setup_buf_ring(fd: posix.fd_t, entries: u16, group_id: u16) !*align(page_size_min) linux.io_uring_buf_ring { |
| 1560 | if (entries == 0 or entries > 1 << 15) return error.EntriesNotInRange; | 1560 | if (entries == 0 or entries > 1 << 15) return error.EntriesNotInRange; |
| 1561 | if (!std.math.isPowerOfTwo(entries)) return error.EntriesNotPowerOfTwo; | 1561 | if (!std.math.isPowerOfTwo(entries)) return error.EntriesNotPowerOfTwo; |
| 1562 | 1562 | ||
| ... | @@ -1572,7 +1572,7 @@ pub fn setup_buf_ring(fd: posix.fd_t, entries: u16, group_id: u16) !*align(heap. | ... | @@ -1572,7 +1572,7 @@ pub fn setup_buf_ring(fd: posix.fd_t, entries: u16, group_id: u16) !*align(heap. |
| 1572 | errdefer posix.munmap(mmap); | 1572 | errdefer posix.munmap(mmap); |
| 1573 | assert(mmap.len == mmap_size); | 1573 | assert(mmap.len == mmap_size); |
| 1574 | 1574 | ||
| 1575 | const br: *align(heap.min_page_size) linux.io_uring_buf_ring = @ptrCast(mmap.ptr); | 1575 | const br: *align(page_size_min) linux.io_uring_buf_ring = @ptrCast(mmap.ptr); |
| 1576 | try register_buf_ring(fd, @intFromPtr(br), entries, group_id); | 1576 | try register_buf_ring(fd, @intFromPtr(br), entries, group_id); |
| 1577 | return br; | 1577 | return br; |
| 1578 | } | 1578 | } |
| ... | @@ -1614,9 +1614,9 @@ fn handle_register_buf_ring_result(res: usize) !void { | ... | @@ -1614,9 +1614,9 @@ fn handle_register_buf_ring_result(res: usize) !void { |
| 1614 | } | 1614 | } |
| 1615 | 1615 | ||
| 1616 | // Unregisters a previously registered shared buffer ring, returned from io_uring_setup_buf_ring. | 1616 | // Unregisters a previously registered shared buffer ring, returned from io_uring_setup_buf_ring. |
| 1617 | pub fn free_buf_ring(fd: posix.fd_t, br: *align(heap.min_page_size) linux.io_uring_buf_ring, entries: u32, group_id: u16) void { | 1617 | pub fn free_buf_ring(fd: posix.fd_t, br: *align(page_size_min) linux.io_uring_buf_ring, entries: u32, group_id: u16) void { |
| 1618 | unregister_buf_ring(fd, group_id) catch {}; | 1618 | unregister_buf_ring(fd, group_id) catch {}; |
| 1619 | var mmap: []align(heap.min_page_size) u8 = undefined; | 1619 | var mmap: []align(page_size_min) u8 = undefined; |
| 1620 | mmap.ptr = @ptrCast(br); | 1620 | mmap.ptr = @ptrCast(br); |
| 1621 | mmap.len = entries * @sizeOf(linux.io_uring_buf); | 1621 | mmap.len = entries * @sizeOf(linux.io_uring_buf); |
| 1622 | posix.munmap(mmap); | 1622 | posix.munmap(mmap); |
lib/std/os/linux/tls.zig+10-10| ... | @@ -11,13 +11,13 @@ | ... | @@ -11,13 +11,13 @@ |
| 11 | 11 | ||
| 12 | const std = @import("std"); | 12 | const std = @import("std"); |
| 13 | const mem = std.mem; | 13 | const mem = std.mem; |
| 14 | const heap = std.heap; | ||
| 15 | const elf = std.elf; | 14 | const elf = std.elf; |
| 16 | const math = std.math; | 15 | const math = std.math; |
| 17 | const assert = std.debug.assert; | 16 | const assert = std.debug.assert; |
| 18 | const native_arch = @import("builtin").cpu.arch; | 17 | const native_arch = @import("builtin").cpu.arch; |
| 19 | const linux = std.os.linux; | 18 | const linux = std.os.linux; |
| 20 | const posix = std.posix; | 19 | const posix = std.posix; |
| 20 | const page_size_min = std.heap.page_size_min; | ||
| 21 | 21 | ||
| 22 | /// Represents an ELF TLS variant. | 22 | /// Represents an ELF TLS variant. |
| 23 | /// | 23 | /// |
| ... | @@ -485,13 +485,13 @@ pub fn prepareArea(area: []u8) usize { | ... | @@ -485,13 +485,13 @@ pub fn prepareArea(area: []u8) usize { |
| 485 | }; | 485 | }; |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | // The main motivation for the size chosen here is that this is how much ends up being requested for | 488 | /// The main motivation for the size chosen here is that this is how much ends up being requested for |
| 489 | // the thread-local variables of the `std.crypto.random` implementation. I'm not sure why it ends up | 489 | /// the thread-local variables of the `std.crypto.random` implementation. I'm not sure why it ends up |
| 490 | // being so much; the struct itself is only 64 bytes. I think it has to do with being page-aligned | 490 | /// being so much; the struct itself is only 64 bytes. I think it has to do with being page-aligned |
| 491 | // and LLVM or LLD is not smart enough to lay out the TLS data in a space-conserving way. Anyway, I | 491 | /// and LLVM or LLD is not smart enough to lay out the TLS data in a space-conserving way. Anyway, I |
| 492 | // think it's fine because it's less than 3 pages of memory, and putting it in the ELF like this is | 492 | /// think it's fine because it's less than 3 pages of memory, and putting it in the ELF like this is |
| 493 | // equivalent to moving the `mmap` call below into the kernel, avoiding syscall overhead. | 493 | /// equivalent to moving the `mmap` call below into the kernel, avoiding syscall overhead. |
| 494 | var main_thread_area_buffer: [0x2100]u8 align(heap.min_page_size) = undefined; | 494 | var main_thread_area_buffer: [0x2100]u8 align(page_size_min) = undefined; |
| 495 | 495 | ||
| 496 | /// Computes the layout of the static TLS area, allocates the area, initializes all of its fields, | 496 | /// Computes the layout of the static TLS area, allocates the area, initializes all of its fields, |
| 497 | /// and assigns the architecture-specific value to the TP register. | 497 | /// and assigns the architecture-specific value to the TP register. |
| ... | @@ -504,7 +504,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void { | ... | @@ -504,7 +504,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void { |
| 504 | const area = blk: { | 504 | const area = blk: { |
| 505 | // Fast path for the common case where the TLS data is really small, avoid an allocation and | 505 | // Fast path for the common case where the TLS data is really small, avoid an allocation and |
| 506 | // use our local buffer. | 506 | // use our local buffer. |
| 507 | if (area_desc.alignment <= heap.min_page_size and area_desc.size <= main_thread_area_buffer.len) { | 507 | if (area_desc.alignment <= page_size_min and area_desc.size <= main_thread_area_buffer.len) { |
| 508 | break :blk main_thread_area_buffer[0..area_desc.size]; | 508 | break :blk main_thread_area_buffer[0..area_desc.size]; |
| 509 | } | 509 | } |
| 510 | 510 | ||
| ... | @@ -518,7 +518,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void { | ... | @@ -518,7 +518,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void { |
| 518 | ); | 518 | ); |
| 519 | if (@as(isize, @bitCast(begin_addr)) < 0) @trap(); | 519 | if (@as(isize, @bitCast(begin_addr)) < 0) @trap(); |
| 520 | 520 | ||
| 521 | const area_ptr: [*]align(heap.min_page_size) u8 = @ptrFromInt(begin_addr); | 521 | const area_ptr: [*]align(page_size_min) u8 = @ptrFromInt(begin_addr); |
| 522 | 522 | ||
| 523 | // Make sure the slice is correctly aligned. | 523 | // Make sure the slice is correctly aligned. |
| 524 | const begin_aligned_addr = alignForward(begin_addr, area_desc.alignment); | 524 | const begin_aligned_addr = alignForward(begin_addr, area_desc.alignment); |
lib/std/posix.zig+10-10| ... | @@ -18,13 +18,13 @@ const builtin = @import("builtin"); | ... | @@ -18,13 +18,13 @@ const builtin = @import("builtin"); |
| 18 | const root = @import("root"); | 18 | const root = @import("root"); |
| 19 | const std = @import("std.zig"); | 19 | const std = @import("std.zig"); |
| 20 | const mem = std.mem; | 20 | const mem = std.mem; |
| 21 | const heap = std.heap; | ||
| 22 | const fs = std.fs; | 21 | const fs = std.fs; |
| 23 | const max_path_bytes = fs.max_path_bytes; | 22 | const max_path_bytes = fs.max_path_bytes; |
| 24 | const maxInt = std.math.maxInt; | 23 | const maxInt = std.math.maxInt; |
| 25 | const cast = std.math.cast; | 24 | const cast = std.math.cast; |
| 26 | const assert = std.debug.assert; | 25 | const assert = std.debug.assert; |
| 27 | const native_os = builtin.os.tag; | 26 | const native_os = builtin.os.tag; |
| 27 | const page_size_min = std.heap.page_size_min; | ||
| 28 | 28 | ||
| 29 | test { | 29 | test { |
| 30 | _ = @import("posix/test.zig"); | 30 | _ = @import("posix/test.zig"); |
| ... | @@ -4695,7 +4695,7 @@ pub const MProtectError = error{ | ... | @@ -4695,7 +4695,7 @@ pub const MProtectError = error{ |
| 4695 | OutOfMemory, | 4695 | OutOfMemory, |
| 4696 | } || UnexpectedError; | 4696 | } || UnexpectedError; |
| 4697 | 4697 | ||
| 4698 | pub fn mprotect(memory: []align(heap.min_page_size) u8, protection: u32) MProtectError!void { | 4698 | pub fn mprotect(memory: []align(page_size_min) u8, protection: u32) MProtectError!void { |
| 4699 | if (native_os == .windows) { | 4699 | if (native_os == .windows) { |
| 4700 | const win_prot: windows.DWORD = switch (@as(u3, @truncate(protection))) { | 4700 | const win_prot: windows.DWORD = switch (@as(u3, @truncate(protection))) { |
| 4701 | 0b000 => windows.PAGE_NOACCESS, | 4701 | 0b000 => windows.PAGE_NOACCESS, |
| ... | @@ -4760,21 +4760,21 @@ pub const MMapError = error{ | ... | @@ -4760,21 +4760,21 @@ pub const MMapError = error{ |
| 4760 | /// * SIGSEGV - Attempted write into a region mapped as read-only. | 4760 | /// * SIGSEGV - Attempted write into a region mapped as read-only. |
| 4761 | /// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file | 4761 | /// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file |
| 4762 | pub fn mmap( | 4762 | pub fn mmap( |
| 4763 | ptr: ?[*]align(heap.min_page_size) u8, | 4763 | ptr: ?[*]align(page_size_min) u8, |
| 4764 | length: usize, | 4764 | length: usize, |
| 4765 | prot: u32, | 4765 | prot: u32, |
| 4766 | flags: system.MAP, | 4766 | flags: system.MAP, |
| 4767 | fd: fd_t, | 4767 | fd: fd_t, |
| 4768 | offset: u64, | 4768 | offset: u64, |
| 4769 | ) MMapError![]align(heap.min_page_size) u8 { | 4769 | ) MMapError![]align(page_size_min) u8 { |
| 4770 | const mmap_sym = if (lfs64_abi) system.mmap64 else system.mmap; | 4770 | const mmap_sym = if (lfs64_abi) system.mmap64 else system.mmap; |
| 4771 | const rc = mmap_sym(ptr, length, prot, @bitCast(flags), fd, @bitCast(offset)); | 4771 | const rc = mmap_sym(ptr, length, prot, @bitCast(flags), fd, @bitCast(offset)); |
| 4772 | const err: E = if (builtin.link_libc) blk: { | 4772 | const err: E = if (builtin.link_libc) blk: { |
| 4773 | if (rc != std.c.MAP_FAILED) return @as([*]align(heap.min_page_size) u8, @ptrCast(@alignCast(rc)))[0..length]; | 4773 | if (rc != std.c.MAP_FAILED) return @as([*]align(page_size_min) u8, @ptrCast(@alignCast(rc)))[0..length]; |
| 4774 | break :blk @enumFromInt(system._errno().*); | 4774 | break :blk @enumFromInt(system._errno().*); |
| 4775 | } else blk: { | 4775 | } else blk: { |
| 4776 | const err = errno(rc); | 4776 | const err = errno(rc); |
| 4777 | if (err == .SUCCESS) return @as([*]align(heap.min_page_size) u8, @ptrFromInt(rc))[0..length]; | 4777 | if (err == .SUCCESS) return @as([*]align(page_size_min) u8, @ptrFromInt(rc))[0..length]; |
| 4778 | break :blk err; | 4778 | break :blk err; |
| 4779 | }; | 4779 | }; |
| 4780 | switch (err) { | 4780 | switch (err) { |
| ... | @@ -4800,7 +4800,7 @@ pub fn mmap( | ... | @@ -4800,7 +4800,7 @@ pub fn mmap( |
| 4800 | /// Zig's munmap function does not, for two reasons: | 4800 | /// Zig's munmap function does not, for two reasons: |
| 4801 | /// * It violates the Zig principle that resource deallocation must succeed. | 4801 | /// * It violates the Zig principle that resource deallocation must succeed. |
| 4802 | /// * The Windows function, VirtualFree, has this restriction. | 4802 | /// * The Windows function, VirtualFree, has this restriction. |
| 4803 | pub fn munmap(memory: []align(heap.min_page_size) const u8) void { | 4803 | pub fn munmap(memory: []align(page_size_min) const u8) void { |
| 4804 | switch (errno(system.munmap(memory.ptr, memory.len))) { | 4804 | switch (errno(system.munmap(memory.ptr, memory.len))) { |
| 4805 | .SUCCESS => return, | 4805 | .SUCCESS => return, |
| 4806 | .INVAL => unreachable, // Invalid parameters. | 4806 | .INVAL => unreachable, // Invalid parameters. |
| ... | @@ -4814,7 +4814,7 @@ pub const MSyncError = error{ | ... | @@ -4814,7 +4814,7 @@ pub const MSyncError = error{ |
| 4814 | PermissionDenied, | 4814 | PermissionDenied, |
| 4815 | } || UnexpectedError; | 4815 | } || UnexpectedError; |
| 4816 | 4816 | ||
| 4817 | pub fn msync(memory: []align(heap.min_page_size) u8, flags: i32) MSyncError!void { | 4817 | pub fn msync(memory: []align(page_size_min) u8, flags: i32) MSyncError!void { |
| 4818 | switch (errno(system.msync(memory.ptr, memory.len, flags))) { | 4818 | switch (errno(system.msync(memory.ptr, memory.len, flags))) { |
| 4819 | .SUCCESS => return, | 4819 | .SUCCESS => return, |
| 4820 | .PERM => return error.PermissionDenied, | 4820 | .PERM => return error.PermissionDenied, |
| ... | @@ -7136,7 +7136,7 @@ pub const MincoreError = error{ | ... | @@ -7136,7 +7136,7 @@ pub const MincoreError = error{ |
| 7136 | } || UnexpectedError; | 7136 | } || UnexpectedError; |
| 7137 | 7137 | ||
| 7138 | /// Determine whether pages are resident in memory. | 7138 | /// Determine whether pages are resident in memory. |
| 7139 | pub fn mincore(ptr: [*]align(heap.min_page_size) u8, length: usize, vec: [*]u8) MincoreError!void { | 7139 | pub fn mincore(ptr: [*]align(page_size_min) u8, length: usize, vec: [*]u8) MincoreError!void { |
| 7140 | return switch (errno(system.mincore(ptr, length, vec))) { | 7140 | return switch (errno(system.mincore(ptr, length, vec))) { |
| 7141 | .SUCCESS => {}, | 7141 | .SUCCESS => {}, |
| 7142 | .AGAIN => error.SystemResources, | 7142 | .AGAIN => error.SystemResources, |
| ... | @@ -7182,7 +7182,7 @@ pub const MadviseError = error{ | ... | @@ -7182,7 +7182,7 @@ pub const MadviseError = error{ |
| 7182 | 7182 | ||
| 7183 | /// Give advice about use of memory. | 7183 | /// Give advice about use of memory. |
| 7184 | /// This syscall is optional and is sometimes configured to be disabled. | 7184 | /// This syscall is optional and is sometimes configured to be disabled. |
| 7185 | pub fn madvise(ptr: [*]align(heap.min_page_size) u8, length: usize, advice: u32) MadviseError!void { | 7185 | pub fn madvise(ptr: [*]align(page_size_min) u8, length: usize, advice: u32) MadviseError!void { |
| 7186 | switch (errno(system.madvise(ptr, length, advice))) { | 7186 | switch (errno(system.madvise(ptr, length, advice))) { |
| 7187 | .SUCCESS => return, | 7187 | .SUCCESS => return, |
| 7188 | .PERM => return error.PermissionDenied, | 7188 | .PERM => return error.PermissionDenied, |
lib/std/process.zig+1-1| ... | @@ -1560,7 +1560,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo { | ... | @@ -1560,7 +1560,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo { |
| 1560 | ReadGroupId, | 1560 | ReadGroupId, |
| 1561 | }; | 1561 | }; |
| 1562 | 1562 | ||
| 1563 | var buf: [std.heap.min_page_size]u8 = undefined; | 1563 | var buf: [std.heap.page_size_min]u8 = undefined; |
| 1564 | var name_index: usize = 0; | 1564 | var name_index: usize = 0; |
| 1565 | var state = State.Start; | 1565 | var state = State.Start; |
| 1566 | var uid: posix.uid_t = 0; | 1566 | var uid: posix.uid_t = 0; |
lib/std/start.zig+1-1| ... | @@ -576,7 +576,7 @@ fn expandStackSize(phdrs: []elf.Phdr) void { | ... | @@ -576,7 +576,7 @@ fn expandStackSize(phdrs: []elf.Phdr) void { |
| 576 | switch (phdr.p_type) { | 576 | switch (phdr.p_type) { |
| 577 | elf.PT_GNU_STACK => { | 577 | elf.PT_GNU_STACK => { |
| 578 | if (phdr.p_memsz == 0) break; | 578 | if (phdr.p_memsz == 0) break; |
| 579 | assert(phdr.p_memsz % std.heap.pageSize() == 0); | 579 | assert(phdr.p_memsz % std.heap.page_size_min == 0); |
| 580 | 580 | ||
| 581 | // Silently fail if we are unable to get limits. | 581 | // Silently fail if we are unable to get limits. |
| 582 | const limits = std.posix.getrlimit(.STACK) catch break; | 582 | const limits = std.posix.getrlimit(.STACK) catch break; |
lib/std/std.zig+6-3| ... | @@ -119,9 +119,12 @@ pub const Options = struct { | ... | @@ -119,9 +119,12 @@ pub const Options = struct { |
| 119 | args: anytype, | 119 | args: anytype, |
| 120 | ) void = log.defaultLog, | 120 | ) void = log.defaultLog, |
| 121 | 121 | ||
| 122 | min_page_size: ?usize = null, | 122 | /// Overrides `std.heap.page_size_min`. |
| 123 | max_page_size: ?usize = null, | 123 | page_size_min: ?usize = null, |
| 124 | queryPageSizeFn: fn () usize = heap.defaultQueryPageSize, | 124 | /// Overrides `std.heap.page_size_max`. |
| 125 | page_size_max: ?usize = null, | ||
| 126 | /// Overrides default implementation for determining OS page size at runtime. | ||
| 127 | queryPageSize: fn () usize = heap.defaultQueryPageSize, | ||
| 125 | 128 | ||
| 126 | fmt_max_depth: usize = fmt.default_max_depth, | 129 | fmt_max_depth: usize = fmt.default_max_depth, |
| 127 | 130 |
src/Package/Fetch.zig+1-1| ... | @@ -1249,7 +1249,7 @@ fn unzip(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult { | ... | @@ -1249,7 +1249,7 @@ fn unzip(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult { |
| 1249 | .{@errorName(err)}, | 1249 | .{@errorName(err)}, |
| 1250 | )); | 1250 | )); |
| 1251 | defer zip_file.close(); | 1251 | defer zip_file.close(); |
| 1252 | var buf: [std.heap.min_page_size]u8 = undefined; | 1252 | var buf: [4096]u8 = undefined; |
| 1253 | while (true) { | 1253 | while (true) { |
| 1254 | const len = reader.readAll(&buf) catch |err| return f.fail(f.location_tok, try eb.printString( | 1254 | const len = reader.readAll(&buf) catch |err| return f.fail(f.location_tok, try eb.printString( |
| 1255 | "read zip stream failed: {s}", | 1255 | "read zip stream failed: {s}", |