authorgravatar for archbirdplus@gmail.comArchbirdplus <archbirdplus@gmail.com> 2024-10-20 14:55:57-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-06 14:23:23-08:00
log439667be0476f5bf60f3efbb82a3c4d5aae96ee4
tree982fdb5d9260c1c30dee76f89319848e0371b4e2
parentb0ed602d5d9358128471588f00a073f2545809fa

runtime page size detection

heap.zig: define new default page sizes heap.zig: add min/max_page_size and their options lib/std/c: add miscellaneous declarations heap.zig: add pageSize() and its options switch to new page sizes, especially in GPA/stdlib mem.zig: remove page_size

29 files changed, 614 insertions(+), 176 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. In480 /// of this ArrayList in accordance with the respective documentation. In
481 /// all cases, "invalidated" means that the memory has been passed to this481 /// 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.mem.page_size) volatile u8,483 items: []align(std.heap.min_page_size) 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,
486486
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";
41const fuzzer_cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext";41const fuzzer_cpu_features = "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext";
4242
43const CoverageMap = struct {43const CoverageMap = struct {
44 mapped_memory: []align(std.mem.page_size) const u8,44 mapped_memory: []align(std.heap.min_page_size) 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+3-3
...@@ -769,7 +769,7 @@ const PosixThreadImpl = struct {...@@ -769,7 +769,7 @@ const PosixThreadImpl = struct {
769 // Use the same set of parameters used by the libc-less impl.769 // Use the same set of parameters used by the libc-less impl.
770 const stack_size = @max(config.stack_size, 16 * 1024);770 const stack_size = @max(config.stack_size, 16 * 1024);
771 assert(c.pthread_attr_setstacksize(&attr, stack_size) == .SUCCESS);771 assert(c.pthread_attr_setstacksize(&attr, stack_size) == .SUCCESS);
772 assert(c.pthread_attr_setguardsize(&attr, std.mem.page_size) == .SUCCESS);772 assert(c.pthread_attr_setguardsize(&attr, std.heap.pageSize()) == .SUCCESS);
773773
774 var handle: c.pthread_t = undefined;774 var handle: c.pthread_t = undefined;
775 switch (c.pthread_create(775 switch (c.pthread_create(
...@@ -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.mem.page_size) u8,1158 mapped: []align(std.heap.min_page_size) u8,
11591159
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:
...@@ -1362,7 +1362,7 @@ const LinuxThreadImpl = struct {...@@ -1362,7 +1362,7 @@ const LinuxThreadImpl = struct {
1362 };1362 };
13631363
1364 fn spawn(config: SpawnConfig, comptime f: anytype, args: anytype) !Impl {1364 fn spawn(config: SpawnConfig, comptime f: anytype, args: anytype) !Impl {
1365 const page_size = std.mem.page_size;1365 const page_size = std.heap.pageSize();
1366 const Args = @TypeOf(args);1366 const Args = @TypeOf(args);
1367 const Instance = struct {1367 const Instance = struct {
1368 fn_args: Args,1368 fn_args: Args,
lib/std/c.zig+48-11
...@@ -3,7 +3,7 @@ const builtin = @import("builtin");...@@ -3,7 +3,7 @@ const builtin = @import("builtin");
3const c = @This();3const c = @This();
4const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const page_size = std.mem.page_size;6const min_page_size = std.heap.min_page_size;
7const native_abi = builtin.abi;7const native_abi = builtin.abi;
8const native_arch = builtin.cpu.arch;8const native_arch = builtin.cpu.arch;
9const native_os = builtin.os.tag;9const native_os = builtin.os.tag;
...@@ -2227,6 +2227,39 @@ pub const SC = switch (native_os) {...@@ -2227,6 +2227,39 @@ pub const SC = switch (native_os) {
2227 .linux => linux.SC,2227 .linux => linux.SC,
2228 else => void,2228 else => void,
2229};2229};
2230
2231pub const _SC = switch (native_os) {
2232 .bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => enum(c_int) {
2233 PAGESIZE = 29,
2234 },
2235 .dragonfly => enum(c_int) {
2236 PAGESIZE = 47,
2237 },
2238 .freebsd => enum(c_int) {
2239 PAGESIZE = 47,
2240 },
2241 .fuchsia => enum(c_int) {
2242 PAGESIZE = 30,
2243 },
2244 .haiku => enum(c_int) {
2245 PAGESIZE = 27,
2246 },
2247 .linux => enum(c_int) {
2248 PAGESIZE = 30,
2249 },
2250 .netbsd => enum(c_int) {
2251 PAGESIZE = 28,
2252 },
2253 .openbsd => enum(c_int) {
2254 PAGESIZE = 28,
2255 },
2256 .solaris, .illumos => enum(c_int) {
2257 PAGESIZE = 11,
2258 NPROCESSORS_ONLN = 15,
2259 },
2260 else => void,
2261};
2262
2230pub const SEEK = switch (native_os) {2263pub const SEEK = switch (native_os) {
2231 .linux => linux.SEEK,2264 .linux => linux.SEEK,
2232 .emscripten => emscripten.SEEK,2265 .emscripten => emscripten.SEEK,
...@@ -9232,7 +9265,7 @@ pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd;...@@ -9232,7 +9265,7 @@ pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd;
9232pub extern "c" fn getpwuid(uid: uid_t) ?*passwd;9265pub extern "c" fn getpwuid(uid: uid_t) ?*passwd;
9233pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;9266pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
9234pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;9267pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
9235pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;9268pub extern "c" fn mmap64(addr: ?*align(min_page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;
9236pub extern "c" fn open64(path: [*:0]const u8, oflag: O, ...) c_int;9269pub extern "c" fn open64(path: [*:0]const u8, oflag: O, ...) c_int;
9237pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int;9270pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int;
9238pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;9271pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;
...@@ -9324,13 +9357,13 @@ pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int;...@@ -9324,13 +9357,13 @@ pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int;
93249357
9325pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int;9358pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int;
9326pub extern "c" fn mincore(9359pub extern "c" fn mincore(
9327 addr: *align(std.mem.page_size) anyopaque,9360 addr: *align(min_page_size) anyopaque,
9328 length: usize,9361 length: usize,
9329 vec: [*]u8,9362 vec: [*]u8,
9330) c_int;9363) c_int;
93319364
9332pub extern "c" fn madvise(9365pub extern "c" fn madvise(
9333 addr: *align(std.mem.page_size) anyopaque,9366 addr: *align(min_page_size) anyopaque,
9334 length: usize,9367 length: usize,
9335 advice: u32,9368 advice: u32,
9336) c_int;9369) c_int;
...@@ -9428,6 +9461,10 @@ pub const posix_memalign = switch (native_os) {...@@ -9428,6 +9461,10 @@ pub const posix_memalign = switch (native_os) {
9428 .dragonfly, .netbsd, .freebsd, .solaris, .openbsd, .linux, .macos, .ios, .tvos, .watchos, .visionos => private.posix_memalign,9461 .dragonfly, .netbsd, .freebsd, .solaris, .openbsd, .linux, .macos, .ios, .tvos, .watchos, .visionos => private.posix_memalign,
9429 else => {},9462 else => {},
9430};9463};
9464pub const sysconf = switch (native_os) {
9465 .solaris => solaris.sysconf,
9466 else => private.sysconf,
9467};
94319468
9432pub const sf_hdtr = switch (native_os) {9469pub const sf_hdtr = switch (native_os) {
9433 .freebsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {9470 .freebsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {
...@@ -9469,9 +9506,9 @@ pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) i...@@ -9469,9 +9506,9 @@ pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) i
9469pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize;9506pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize;
9470pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;9507pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;
9471pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize;9508pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize;
9472pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: fd_t, offset: off_t) *anyopaque;9509pub extern "c" fn mmap(addr: ?*align(min_page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: fd_t, offset: off_t) *anyopaque;
9473pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;9510pub extern "c" fn munmap(addr: *align(min_page_size) const anyopaque, len: usize) c_int;
9474pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;9511pub extern "c" fn mprotect(addr: *align(min_page_size) anyopaque, len: usize, prot: c_uint) c_int;
9475pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8) c_int;9512pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8) c_int;
9476pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int;9513pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int;
9477pub extern "c" fn unlink(path: [*:0]const u8) c_int;9514pub extern "c" fn unlink(path: [*:0]const u8) c_int;
...@@ -9823,7 +9860,6 @@ pub const SCM = solaris.SCM;...@@ -9823,7 +9860,6 @@ pub const SCM = solaris.SCM;
9823pub const SETCONTEXT = solaris.SETCONTEXT;9860pub const SETCONTEXT = solaris.SETCONTEXT;
9824pub const SETUSTACK = solaris.GETUSTACK;9861pub const SETUSTACK = solaris.GETUSTACK;
9825pub const SFD = solaris.SFD;9862pub const SFD = solaris.SFD;
9826pub const _SC = solaris._SC;
9827pub const cmsghdr = solaris.cmsghdr;9863pub const cmsghdr = solaris.cmsghdr;
9828pub const ctid_t = solaris.ctid_t;9864pub const ctid_t = solaris.ctid_t;
9829pub const file_obj = solaris.file_obj;9865pub const file_obj = solaris.file_obj;
...@@ -9840,7 +9876,6 @@ pub const priority = solaris.priority;...@@ -9840,7 +9876,6 @@ pub const priority = solaris.priority;
9840pub const procfs = solaris.procfs;9876pub const procfs = solaris.procfs;
9841pub const projid_t = solaris.projid_t;9877pub const projid_t = solaris.projid_t;
9842pub const signalfd_siginfo = solaris.signalfd_siginfo;9878pub const signalfd_siginfo = solaris.signalfd_siginfo;
9843pub const sysconf = solaris.sysconf;
9844pub const taskid_t = solaris.taskid_t;9879pub const taskid_t = solaris.taskid_t;
9845pub const zoneid_t = solaris.zoneid_t;9880pub const zoneid_t = solaris.zoneid_t;
98469881
...@@ -9997,6 +10032,7 @@ pub const host_t = darwin.host_t;...@@ -9997,6 +10032,7 @@ pub const host_t = darwin.host_t;
9997pub const ipc_space_t = darwin.ipc_space_t;10032pub const ipc_space_t = darwin.ipc_space_t;
9998pub const ipc_space_port_t = darwin.ipc_space_port_t;10033pub const ipc_space_port_t = darwin.ipc_space_port_t;
9999pub const kern_return_t = darwin.kern_return_t;10034pub const kern_return_t = darwin.kern_return_t;
10035pub const vm_size_t = darwin.vm_size_t;
10000pub const kevent64 = darwin.kevent64;10036pub const kevent64 = darwin.kevent64;
10001pub const kevent64_s = darwin.kevent64_s;10037pub const kevent64_s = darwin.kevent64_s;
10002pub const mach_absolute_time = darwin.mach_absolute_time;10038pub const mach_absolute_time = darwin.mach_absolute_time;
...@@ -10155,7 +10191,7 @@ const private = struct {...@@ -10155,7 +10191,7 @@ const private = struct {
10155 };10191 };
10156 extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;10192 extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
10157 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;
10158 extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int;10194 extern "c" fn msync(addr: *align(min_page_size) const anyopaque, len: usize, flags: c_int) c_int;
10159 extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;10195 extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
10160 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;
10161 extern "c" fn readdir(dir: *DIR) ?*dirent;10197 extern "c" fn readdir(dir: *DIR) ?*dirent;
...@@ -10168,6 +10204,7 @@ const private = struct {...@@ -10168,6 +10204,7 @@ const private = struct {
10168 extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;10204 extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
10169 extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;10205 extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
10170 extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;10206 extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
10207 extern "c" fn sysconf(sc: c_int) c_long;
1017110208
10172 extern "c" fn pthread_setname_np(thread: pthread_t, name: [*:0]const u8) c_int;10209 extern "c" fn pthread_setname_np(thread: pthread_t, name: [*:0]const u8) c_int;
10173 extern "c" fn getcontext(ucp: *ucontext_t) c_int;10210 extern "c" fn getcontext(ucp: *ucontext_t) c_int;
...@@ -10202,7 +10239,7 @@ const private = struct {...@@ -10202,7 +10239,7 @@ const private = struct {
10202 extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int;10239 extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int;
10203 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;
10204 extern "c" fn __libc_thr_yield() c_int;10241 extern "c" fn __libc_thr_yield() c_int;
10205 extern "c" fn __msync13(addr: *align(std.mem.page_size) const anyopaque, len: usize, flags: c_int) c_int;10242 extern "c" fn __msync13(addr: *align(min_page_size) const anyopaque, len: usize, flags: c_int) c_int;
10206 extern "c" fn __nanosleep50(rqtp: *const timespec, rmtp: ?*timespec) c_int;10243 extern "c" fn __nanosleep50(rqtp: *const timespec, rmtp: ?*timespec) c_int;
10207 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;
10208 extern "c" fn __sigfillset14(set: ?*sigset_t) void;10245 extern "c" fn __sigfillset14(set: ?*sigset_t) void;
lib/std/c/solaris.zig-4
...@@ -154,10 +154,6 @@ pub const AF_SUN = struct {...@@ -154,10 +154,6 @@ pub const AF_SUN = struct {
154 pub const NOPLM = 0x00000004;154 pub const NOPLM = 0x00000004;
155};155};
156156
157pub const _SC = struct {
158 pub const NPROCESSORS_ONLN = 15;
159};
160
161pub const procfs = struct {157pub const procfs = struct {
162 pub const misc_header = extern struct {158 pub const misc_header = extern struct {
163 size: u32,159 size: u32,
lib/std/crypto/tlcsprng.zig+3-2
...@@ -6,6 +6,7 @@...@@ -6,6 +6,7 @@
6const std = @import("std");6const std = @import("std");
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const mem = std.mem;8const mem = std.mem;
9const heap = std.heap;
9const native_os = builtin.os.tag;10const native_os = builtin.os.tag;
10const posix = std.posix;11const posix = std.posix;
1112
...@@ -42,7 +43,7 @@ var install_atfork_handler = std.once(struct {...@@ -42,7 +43,7 @@ var install_atfork_handler = std.once(struct {
42 }43 }
43}.do);44}.do);
4445
45threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{};46threadlocal var wipe_mem: []align(heap.min_page_size) u8 = &[_]u8{};
4647
47fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {48fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
48 if (os_has_arc4random) {49 if (os_has_arc4random) {
...@@ -77,7 +78,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {...@@ -77,7 +78,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
77 } else {78 } else {
78 // Use a static thread-local buffer.79 // Use a static thread-local buffer.
79 const S = struct {80 const S = struct {
80 threadlocal var buf: Context align(mem.page_size) = .{81 threadlocal var buf: Context align(heap.min_page_size) = .{
81 .init_state = .uninitialized,82 .init_state = .uninitialized,
82 .rng = undefined,83 .rng = undefined,
83 };84 };
lib/std/debug.zig+9-8
...@@ -2,6 +2,7 @@ const builtin = @import("builtin");...@@ -2,6 +2,7 @@ const builtin = @import("builtin");
2const std = @import("std.zig");2const std = @import("std.zig");
3const math = std.math;3const math = std.math;
4const mem = std.mem;4const mem = std.mem;
5const heap = std.heap;
5const io = std.io;6const io = std.io;
6const posix = std.posix;7const posix = std.posix;
7const fs = std.fs;8const fs = std.fs;
...@@ -1134,7 +1135,7 @@ fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation)...@@ -1134,7 +1135,7 @@ fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation)
1134 defer f.close();1135 defer f.close();
1135 // TODO fstat and make sure that the file has the correct size1136 // TODO fstat and make sure that the file has the correct size
11361137
1137 var buf: [mem.page_size]u8 = undefined;1138 var buf: [4096]u8 = undefined;
1138 var amt_read = try f.read(buf[0..]);1139 var amt_read = try f.read(buf[0..]);
1139 const line_start = seek: {1140 const line_start = seek: {
1140 var current_line_start: usize = 0;1141 var current_line_start: usize = 0;
...@@ -1237,7 +1238,7 @@ test printLineFromFileAnyOs {...@@ -1237,7 +1238,7 @@ test printLineFromFileAnyOs {
12371238
1238 const overlap = 10;1239 const overlap = 10;
1239 var writer = file.writer();1240 var writer = file.writer();
1240 try writer.writeByteNTimes('a', mem.page_size - overlap);1241 try writer.writeByteNTimes('a', heap.min_page_size - overlap);
1241 try writer.writeByte('\n');1242 try writer.writeByte('\n');
1242 try writer.writeByteNTimes('a', overlap);1243 try writer.writeByteNTimes('a', overlap);
12431244
...@@ -1252,10 +1253,10 @@ test printLineFromFileAnyOs {...@@ -1252,10 +1253,10 @@ test printLineFromFileAnyOs {
1252 defer allocator.free(path);1253 defer allocator.free(path);
12531254
1254 var writer = file.writer();1255 var writer = file.writer();
1255 try writer.writeByteNTimes('a', mem.page_size);1256 try writer.writeByteNTimes('a', heap.max_page_size);
12561257
1257 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });1258 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
1258 try expectEqualStrings(("a" ** mem.page_size) ++ "\n", output.items);1259 try expectEqualStrings(("a" ** heap.max_page_size) ++ "\n", output.items);
1259 output.clearRetainingCapacity();1260 output.clearRetainingCapacity();
1260 }1261 }
1261 {1262 {
...@@ -1265,18 +1266,18 @@ test printLineFromFileAnyOs {...@@ -1265,18 +1266,18 @@ test printLineFromFileAnyOs {
1265 defer allocator.free(path);1266 defer allocator.free(path);
12661267
1267 var writer = file.writer();1268 var writer = file.writer();
1268 try writer.writeByteNTimes('a', 3 * mem.page_size);1269 try writer.writeByteNTimes('a', 3 * heap.max_page_size);
12691270
1270 try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }));1271 try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }));
12711272
1272 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });1273 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
1273 try expectEqualStrings(("a" ** (3 * mem.page_size)) ++ "\n", output.items);1274 try expectEqualStrings(("a" ** (3 * heap.max_page_size)) ++ "\n", output.items);
1274 output.clearRetainingCapacity();1275 output.clearRetainingCapacity();
12751276
1276 try writer.writeAll("a\na");1277 try writer.writeAll("a\na");
12771278
1278 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });1279 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
1279 try expectEqualStrings(("a" ** (3 * mem.page_size)) ++ "a\n", output.items);1280 try expectEqualStrings(("a" ** (3 * heap.max_page_size)) ++ "a\n", output.items);
1280 output.clearRetainingCapacity();1281 output.clearRetainingCapacity();
12811282
1282 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 });1283 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 });
...@@ -1290,7 +1291,7 @@ test printLineFromFileAnyOs {...@@ -1290,7 +1291,7 @@ test printLineFromFileAnyOs {
1290 defer allocator.free(path);1291 defer allocator.free(path);
12911292
1292 var writer = file.writer();1293 var writer = file.writer();
1293 const real_file_start = 3 * mem.page_size;1294 const real_file_start = 3 * heap.min_page_size;
1294 try writer.writeByteNTimes('\n', real_file_start);1295 try writer.writeByteNTimes('\n', real_file_start);
1295 try writer.writeAll("abc\ndef");1296 try writer.writeAll("abc\ndef");
12961297
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 {
2120pub const ElfModule = struct {2120pub const ElfModule = struct {
2121 base_address: usize,2121 base_address: usize,
2122 dwarf: Dwarf,2122 dwarf: Dwarf,
2123 mapped_memory: []align(std.mem.page_size) const u8,2123 mapped_memory: []align(std.heap.min_page_size) const u8,
2124 external_mapped_memory: ?[]align(std.mem.page_size) const u8,2124 external_mapped_memory: ?[]align(std.heap.min_page_size) const u8,
21252125
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.mem.page_size) const u8,2170 mapped_mem: []align(std.heap.min_page_size) 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.mem.page_size) const u8,2174 parent_mapped_mem: ?[]align(std.heap.min_page_size) 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.mem.page_size) const u8,2426 parent_mapped_mem: ?[]align(std.heap.min_page_size) 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/Info.zig-1
...@@ -10,7 +10,6 @@ const std = @import("../std.zig");...@@ -10,7 +10,6 @@ const std = @import("../std.zig");
10const Allocator = std.mem.Allocator;10const Allocator = std.mem.Allocator;
11const Path = std.Build.Cache.Path;11const Path = std.Build.Cache.Path;
12const Dwarf = std.debug.Dwarf;12const Dwarf = std.debug.Dwarf;
13const page_size = std.mem.page_size;
14const assert = std.debug.assert;13const assert = std.debug.assert;
15const Coverage = std.debug.Coverage;14const Coverage = std.debug.Coverage;
16const SourceLocation = std.debug.Coverage.SourceLocation;15const SourceLocation = std.debug.Coverage.SourceLocation;
lib/std/debug/MemoryAccessor.zig+5-4
...@@ -7,7 +7,7 @@ const native_os = builtin.os.tag;...@@ -7,7 +7,7 @@ const native_os = builtin.os.tag;
7const std = @import("../std.zig");7const std = @import("../std.zig");
8const posix = std.posix;8const posix = std.posix;
9const File = std.fs.File;9const File = std.fs.File;
10const page_size = std.mem.page_size;10const min_page_size = std.heap.min_page_size;
1111
12const MemoryAccessor = @This();12const MemoryAccessor = @This();
1313
...@@ -93,9 +93,10 @@ pub fn isValidMemory(address: usize) bool {...@@ -93,9 +93,10 @@ pub fn isValidMemory(address: usize) bool {
93 // We are unable to determine validity of memory for freestanding targets93 // We are unable to determine validity of memory for freestanding targets
94 if (native_os == .freestanding or native_os == .other or native_os == .uefi) return true;94 if (native_os == .freestanding or native_os == .other or native_os == .uefi) return true;
9595
96 const aligned_address = address & ~@as(usize, @intCast((page_size - 1)));96 const page_size = std.heap.pageSize();
97 const aligned_address = address & ~(page_size - 1);
97 if (aligned_address == 0) return false;98 if (aligned_address == 0) return false;
98 const aligned_memory = @as([*]align(page_size) u8, @ptrFromInt(aligned_address))[0..page_size];99 const aligned_memory = @as([*]align(min_page_size) u8, @ptrFromInt(aligned_address))[0..page_size];
99100
100 if (native_os == .windows) {101 if (native_os == .windows) {
101 const windows = std.os.windows;102 const windows = std.os.windows;
...@@ -104,7 +105,7 @@ pub fn isValidMemory(address: usize) bool {...@@ -104,7 +105,7 @@ pub fn isValidMemory(address: usize) bool {
104105
105 // The only error this function can throw is ERROR_INVALID_PARAMETER.106 // The only error this function can throw is ERROR_INVALID_PARAMETER.
106 // supply an address that invalid i'll be thrown.107 // supply an address that invalid i'll be thrown.
107 const rc = windows.VirtualQuery(aligned_memory, &memory_info, aligned_memory.len) catch {108 const rc = windows.VirtualQuery(@ptrCast(aligned_memory), &memory_info, aligned_memory.len) catch {
108 return false;109 return false;
109 };110 };
110111
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(mem.page_size) const u8,507 mapped_memory: []align(std.heap.min_page_size) 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(mem.page_size) const u8,1049 parent_mapped_mem: ?[]align(std.heap.min_page_size) 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 {
10881088
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.
1091fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 {1091fn mapWholeFile(file: File) ![]align(std.heap.min_page_size) const u8 {
1092 nosuspend {1092 nosuspend {
1093 defer file.close();1093 defer file.close();
10941094
lib/std/dynamic_library.zig+6-5
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const mem = std.mem;3const mem = std.mem;
4const heap = std.heap;
4const testing = std.testing;5const testing = std.testing;
5const elf = std.elf;6const elf = std.elf;
6const windows = std.os.windows;7const windows = std.os.windows;
...@@ -143,7 +144,7 @@ pub const ElfDynLib = struct {...@@ -143,7 +144,7 @@ pub const ElfDynLib = struct {
143 hashtab: [*]posix.Elf_Symndx,144 hashtab: [*]posix.Elf_Symndx,
144 versym: ?[*]elf.Versym,145 versym: ?[*]elf.Versym,
145 verdef: ?*elf.Verdef,146 verdef: ?*elf.Verdef,
146 memory: []align(mem.page_size) u8,147 memory: []align(heap.min_page_size) u8,
147148
148 pub const Error = ElfDynLibError;149 pub const Error = ElfDynLibError;
149150
...@@ -223,7 +224,7 @@ pub const ElfDynLib = struct {...@@ -223,7 +224,7 @@ pub const ElfDynLib = struct {
223 // corresponding to the actual LOAD sections.224 // corresponding to the actual LOAD sections.
224 const file_bytes = try posix.mmap(225 const file_bytes = try posix.mmap(
225 null,226 null,
226 mem.alignForward(usize, size, mem.page_size),227 mem.alignForward(usize, size, heap.pageSize()),
227 posix.PROT.READ,228 posix.PROT.READ,
228 .{ .TYPE = .PRIVATE },229 .{ .TYPE = .PRIVATE },
229 fd,230 fd,
...@@ -284,10 +285,10 @@ pub const ElfDynLib = struct {...@@ -284,10 +285,10 @@ pub const ElfDynLib = struct {
284 elf.PT_LOAD => {285 elf.PT_LOAD => {
285 // The VirtAddr may not be page-aligned; in such case there will be286 // The VirtAddr may not be page-aligned; in such case there will be
286 // extra nonsense mapped before/after the VirtAddr,MemSiz287 // extra nonsense mapped before/after the VirtAddr,MemSiz
287 const aligned_addr = (base + ph.p_vaddr) & ~(@as(usize, mem.page_size) - 1);288 const aligned_addr = (base + ph.p_vaddr) & ~(@as(usize, heap.pageSize()) - 1);
288 const extra_bytes = (base + ph.p_vaddr) - aligned_addr;289 const extra_bytes = (base + ph.p_vaddr) - aligned_addr;
289 const extended_memsz = mem.alignForward(usize, ph.p_memsz + extra_bytes, mem.page_size);290 const extended_memsz = mem.alignForward(usize, ph.p_memsz + extra_bytes, heap.pageSize());
290 const ptr = @as([*]align(mem.page_size) u8, @ptrFromInt(aligned_addr));291 const ptr = @as([*]align(heap.min_page_size) u8, @ptrFromInt(aligned_addr));
291 const prot = elfToMmapProt(ph.p_flags);292 const prot = elfToMmapProt(ph.p_flags);
292 if ((ph.p_flags & elf.PF_W) == 0) {293 if ((ph.p_flags & elf.PF_W) == 0) {
293 // If it does not need write access, it can be mapped from the fd.294 // If it does not need write access, it can be mapped from the fd.
lib/std/fifo.zig+1-1
...@@ -91,7 +91,7 @@ pub fn LinearFifo(...@@ -91,7 +91,7 @@ pub fn LinearFifo(
91 mem.copyForwards(T, self.buf[0..self.count], self.buf[self.head..][0..self.count]);91 mem.copyForwards(T, self.buf[0..self.count], self.buf[self.head..][0..self.count]);
92 self.head = 0;92 self.head = 0;
93 } else {93 } else {
94 var tmp: [mem.page_size / 2 / @sizeOf(T)]T = undefined;94 var tmp: [4096 / 2 / @sizeOf(T)]T = undefined;
9595
96 while (self.head != 0) {96 while (self.head != 0) {
97 const n = @min(self.head, tmp.len);97 const n = @min(self.head, tmp.len);
lib/std/heap.zig+391-7
...@@ -8,6 +8,376 @@ const c = std.c;...@@ -8,6 +8,376 @@ const c = std.c;
8const Allocator = std.mem.Allocator;8const Allocator = std.mem.Allocator;
9const windows = std.os.windows;9const windows = std.os.windows;
1010
11const default_min_page_size: ?usize = switch (builtin.os.tag) {
12 .bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => switch (builtin.cpu.arch) {
13 .x86_64 => 4 << 10,
14 .aarch64 => 16 << 10,
15 else => null,
16 },
17 .windows => switch (builtin.cpu.arch) {
18 // -- <https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200>
19 .x86, .x86_64 => 4 << 10,
20 // SuperH => 4 << 10,
21 .mips, .mipsel, .mips64, .mips64el => 4 << 10,
22 .powerpc, .powerpcle, .powerpc64, .powerpc64le => 4 << 10,
23 // DEC Alpha => 8 << 10,
24 // Itanium => 8 << 10,
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
157const default_max_page_size: ?usize = switch (builtin.os.tag) {
158 .bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => switch (builtin.cpu.arch) {
159 .x86_64 => 4 << 10,
160 .aarch64 => 16 << 10,
161 else => null,
162 },
163 .windows => switch (builtin.cpu.arch) {
164 // -- <https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200>
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
302/// The compile-time minimum page size that the target might have.
303/// All pointers from `mmap` or `VirtualAlloc` are aligned to at least `min_page_size`, but their
304/// actual alignment may be much bigger.
305/// This value can be overridden via `std.options.min_page_size`.
306/// On many systems, the actual page size can only be determined at runtime with `pageSize()`.
307pub 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)
308 @compileError("freestanding/other explicitly has no min_page_size. One can be provided with std.options.min_page_size")
309else
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"));
311
312/// The compile-time maximum page size that the target might have.
313/// Targeting a system with a larger page size may require overriding `std.options.max_page_size`,
314/// as well as using the linker arugment `-z max-page-size=`.
315/// The actual page size can only be determined at runtime with `pageSize()`.
316pub 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)
317 @compileError("freestanding/other explicitly has no max_page_size. One can be provided with std.options.max_page_size")
318else
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"));
320
321/// Returns the system page size.
322/// If the page size is comptime-known, `pageSize()` returns it directly.
323/// Otherwise, `pageSize()` defers to `std.options.queryPageSizeFn()`.
324pub fn pageSize() usize {
325 if (min_page_size == max_page_size) {
326 return min_page_size;
327 }
328 return std.options.queryPageSizeFn();
329}
330
331// A cache used by `defaultQueryPageSize()` to avoid repeating syscalls.
332var page_size_cache = std.atomic.Value(usize).init(0);
333
334// The default implementation in `std.options.queryPageSizeFn`.
335// The first time it is called, it asserts that the page size is within the comptime bounds.
336pub fn defaultQueryPageSize() usize {
337 var size = page_size_cache.load(.unordered);
338 if (size > 0) return size;
339 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),
341 .bridgeos, .driverkit, .ios, .macos, .tvos, .visionos, .watchos => blk: {
342 const task_port = std.c.mach_task_self();
343 // mach_task_self may fail "if there are any resource failures or other errors".
344 if (task_port == std.c.TASK_NULL)
345 break :blk 0;
346 var info_count = std.c.TASK_VM_INFO_COUNT;
347 var vm_info: std.c.task_vm_info_data_t = undefined;
348 vm_info.page_size = 0;
349 _ = std.c.task_info(
350 task_port,
351 std.c.TASK_VM_INFO,
352 @as(std.c.task_info_t, @ptrCast(&vm_info)),
353 &info_count,
354 );
355 assert(vm_info.page_size != 0);
356 break :blk @as(usize, @intCast(vm_info.page_size));
357 },
358 .windows => blk: {
359 var info: std.os.windows.SYSTEM_INFO = undefined;
360 std.os.windows.kernel32.GetSystemInfo(&info);
361 break :blk info.dwPageSize;
362 },
363 else => if (builtin.link_libc)
364 if (std.c._SC != void and @hasDecl(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)
369 @compileError("pageSize on freestanding/other is not supported with the default std.options.queryPageSizeFn")
370 else
371 @compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"),
372 };
373
374 assert(size >= min_page_size);
375 assert(size <= max_page_size);
376 page_size_cache.store(size, .unordered);
377
378 return size;
379}
380
11pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator;381pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator;
12pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator;382pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator;
13pub const ScopedLoggingAllocator = @import("heap/logging_allocator.zig").ScopedLoggingAllocator;383pub const ScopedLoggingAllocator = @import("heap/logging_allocator.zig").ScopedLoggingAllocator;
...@@ -29,7 +399,7 @@ pub const MemoryPoolExtra = memory_pool.MemoryPoolExtra;...@@ -29,7 +399,7 @@ pub const MemoryPoolExtra = memory_pool.MemoryPoolExtra;
29pub const MemoryPoolOptions = memory_pool.Options;399pub const MemoryPoolOptions = memory_pool.Options;
30400
31/// TODO Utilize this on Windows.401/// TODO Utilize this on Windows.
32pub var next_mmap_addr_hint: ?[*]align(mem.page_size) u8 = null;402pub var next_mmap_addr_hint: ?[*]align(min_page_size) u8 = null;
33403
34const CAllocator = struct {404const CAllocator = struct {
35 comptime {405 comptime {
...@@ -256,7 +626,7 @@ pub const wasm_allocator: Allocator = .{...@@ -256,7 +626,7 @@ pub const wasm_allocator: Allocator = .{
256/// Verifies that the adjusted length will still map to the full length626/// Verifies that the adjusted length will still map to the full length
257pub fn alignPageAllocLen(full_len: usize, len: usize) usize {627pub fn alignPageAllocLen(full_len: usize, len: usize) usize {
258 const aligned_len = mem.alignAllocLen(full_len, len);628 const aligned_len = mem.alignAllocLen(full_len, len);
259 assert(mem.alignForward(usize, aligned_len, mem.page_size) == full_len);629 assert(mem.alignForward(usize, aligned_len, pageSize()) == full_len);
260 return aligned_len;630 return aligned_len;
261}631}
262632
...@@ -615,13 +985,13 @@ test "PageAllocator" {...@@ -615,13 +985,13 @@ test "PageAllocator" {
615 }985 }
616986
617 if (builtin.os.tag == .windows) {987 if (builtin.os.tag == .windows) {
618 const slice = try allocator.alignedAlloc(u8, mem.page_size, 128);988 const slice = try allocator.alignedAlloc(u8, min_page_size, 128);
619 slice[0] = 0x12;989 slice[0] = 0x12;
620 slice[127] = 0x34;990 slice[127] = 0x34;
621 allocator.free(slice);991 allocator.free(slice);
622 }992 }
623 {993 {
624 var buf = try allocator.alloc(u8, mem.page_size + 1);994 var buf = try allocator.alloc(u8, pageSize() + 1);
625 defer allocator.free(buf);995 defer allocator.free(buf);
626 buf = try allocator.realloc(buf, 1); // shrink past the page boundary996 buf = try allocator.realloc(buf, 1); // shrink past the page boundary
627 }997 }
...@@ -824,7 +1194,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {...@@ -824,7 +1194,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {
824 var validationAllocator = mem.validationWrap(base_allocator);1194 var validationAllocator = mem.validationWrap(base_allocator);
825 const allocator = validationAllocator.allocator();1195 const allocator = validationAllocator.allocator();
8261196
827 const large_align: usize = mem.page_size / 2;1197 const large_align: usize = min_page_size / 2;
8281198
829 var align_mask: usize = undefined;1199 var align_mask: usize = undefined;
830 align_mask = @shlWithOverflow(~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)))[0];1200 align_mask = @shlWithOverflow(~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)))[0];
...@@ -857,7 +1227,7 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void {...@@ -857,7 +1227,7 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void {
857 var fib = FixedBufferAllocator.init(&debug_buffer);1227 var fib = FixedBufferAllocator.init(&debug_buffer);
858 const debug_allocator = fib.allocator();1228 const debug_allocator = fib.allocator();
8591229
860 const alloc_size = mem.page_size * 2 + 50;1230 const alloc_size = pageSize() * 2 + 50;
861 var slice = try allocator.alignedAlloc(u8, 16, alloc_size);1231 var slice = try allocator.alignedAlloc(u8, 16, alloc_size);
862 defer allocator.free(slice);1232 defer allocator.free(slice);
8631233
...@@ -866,7 +1236,7 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void {...@@ -866,7 +1236,7 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void {
866 // which is 16 pages, hence the 32. This test may require to increase1236 // which is 16 pages, hence the 32. This test may require to increase
867 // the size of the allocations feeding the `allocator` parameter if they1237 // the size of the allocations feeding the `allocator` parameter if they
868 // fail, because of this high over-alignment we want to have.1238 // fail, because of this high over-alignment we want to have.
869 while (@intFromPtr(slice.ptr) == mem.alignForward(usize, @intFromPtr(slice.ptr), mem.page_size * 32)) {1239 while (@intFromPtr(slice.ptr) == mem.alignForward(usize, @intFromPtr(slice.ptr), pageSize() * 32)) {
870 try stuff_to_free.append(slice);1240 try stuff_to_free.append(slice);
871 slice = try allocator.alignedAlloc(u8, 16, alloc_size);1241 slice = try allocator.alignedAlloc(u8, 16, alloc_size);
872 }1242 }
...@@ -881,6 +1251,20 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void {...@@ -881,6 +1251,20 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void {
881 try testing.expect(slice[60] == 0x34);1251 try testing.expect(slice[60] == 0x34);
882}1252}
8831253
1254test "pageSize() smoke test" {
1255 const size = std.heap.pageSize();
1256 // Check that pageSize is a power of 2.
1257 std.debug.assert(size & (size - 1) == 0);
1258}
1259
1260test "defaultQueryPageSize() smoke test" {
1261 // queryPageSize() does not always get called by pageSize()
1262 if (builtin.cpu.arch.isWasm()) return error.SkipZigTest;
1263 const size = defaultQueryPageSize();
1264 // Check that pageSize is a power of 2.
1265 std.debug.assert(size & (size - 1) == 0);
1266}
1267
884test {1268test {
885 _ = LoggingAllocator;1269 _ = LoggingAllocator;
886 _ = LogToWriterAllocator;1270 _ = LogToWriterAllocator;
lib/std/heap/PageAllocator.zig+10-9
...@@ -2,6 +2,7 @@ const std = @import("../std.zig");...@@ -2,6 +2,7 @@ const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const mem = std.mem;4const mem = std.mem;
5const heap = std.heap;
5const maxInt = std.math.maxInt;6const maxInt = std.math.maxInt;
6const assert = std.debug.assert;7const assert = std.debug.assert;
7const native_os = builtin.os.tag;8const native_os = builtin.os.tag;
...@@ -18,7 +19,7 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 {...@@ -18,7 +19,7 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 {
18 _ = ra;19 _ = ra;
19 _ = log2_align;20 _ = log2_align;
20 assert(n > 0);21 assert(n > 0);
21 if (n > maxInt(usize) - (mem.page_size - 1)) return null;22 if (n > maxInt(usize) - (heap.pageSize() - 1)) return null;
2223
23 if (native_os == .windows) {24 if (native_os == .windows) {
24 const addr = windows.VirtualAlloc(25 const addr = windows.VirtualAlloc(
...@@ -34,7 +35,7 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 {...@@ -34,7 +35,7 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 {
34 return @ptrCast(addr);35 return @ptrCast(addr);
35 }36 }
3637
37 const aligned_len = mem.alignForward(usize, n, mem.page_size);38 const aligned_len = mem.alignForward(usize, n, heap.pageSize());
38 const hint = @atomicLoad(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, .unordered);39 const hint = @atomicLoad(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, .unordered);
39 const slice = posix.mmap(40 const slice = posix.mmap(
40 hint,41 hint,
...@@ -44,8 +45,8 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 {...@@ -44,8 +45,8 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 {
44 -1,45 -1,
45 0,46 0,
46 ) catch return null;47 ) catch return null;
47 assert(mem.isAligned(@intFromPtr(slice.ptr), mem.page_size));48 assert(mem.isAligned(@intFromPtr(slice.ptr), heap.pageSize()));
48 const new_hint: [*]align(mem.page_size) u8 = @alignCast(slice.ptr + aligned_len);49 const new_hint: [*]align(heap.min_page_size) u8 = @alignCast(slice.ptr + aligned_len);
49 _ = @cmpxchgStrong(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, hint, new_hint, .monotonic, .monotonic);50 _ = @cmpxchgStrong(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, hint, new_hint, .monotonic, .monotonic);
50 return slice.ptr;51 return slice.ptr;
51}52}
...@@ -59,13 +60,13 @@ fn resize(...@@ -59,13 +60,13 @@ fn resize(
59) bool {60) bool {
60 _ = log2_buf_align;61 _ = log2_buf_align;
61 _ = return_address;62 _ = return_address;
62 const new_size_aligned = mem.alignForward(usize, new_size, mem.page_size);63 const new_size_aligned = mem.alignForward(usize, new_size, heap.pageSize());
6364
64 if (native_os == .windows) {65 if (native_os == .windows) {
65 if (new_size <= buf_unaligned.len) {66 if (new_size <= buf_unaligned.len) {
66 const base_addr = @intFromPtr(buf_unaligned.ptr);67 const base_addr = @intFromPtr(buf_unaligned.ptr);
67 const old_addr_end = base_addr + buf_unaligned.len;68 const old_addr_end = base_addr + buf_unaligned.len;
68 const new_addr_end = mem.alignForward(usize, base_addr + new_size, mem.page_size);69 const new_addr_end = mem.alignForward(usize, base_addr + new_size, heap.pageSize());
69 if (old_addr_end > new_addr_end) {70 if (old_addr_end > new_addr_end) {
70 // For shrinking that is not releasing, we will only71 // For shrinking that is not releasing, we will only
71 // decommit the pages not needed anymore.72 // decommit the pages not needed anymore.
...@@ -77,14 +78,14 @@ fn resize(...@@ -77,14 +78,14 @@ fn resize(
77 }78 }
78 return true;79 return true;
79 }80 }
80 const old_size_aligned = mem.alignForward(usize, buf_unaligned.len, mem.page_size);81 const old_size_aligned = mem.alignForward(usize, buf_unaligned.len, heap.pageSize());
81 if (new_size_aligned <= old_size_aligned) {82 if (new_size_aligned <= old_size_aligned) {
82 return true;83 return true;
83 }84 }
84 return false;85 return false;
85 }86 }
8687
87 const buf_aligned_len = mem.alignForward(usize, buf_unaligned.len, mem.page_size);88 const buf_aligned_len = mem.alignForward(usize, buf_unaligned.len, heap.pageSize());
88 if (new_size_aligned == buf_aligned_len)89 if (new_size_aligned == buf_aligned_len)
89 return true;90 return true;
9091
...@@ -107,7 +108,7 @@ fn free(_: *anyopaque, slice: []u8, log2_buf_align: u8, return_address: usize) v...@@ -107,7 +108,7 @@ fn free(_: *anyopaque, slice: []u8, log2_buf_align: u8, return_address: usize) v
107 if (native_os == .windows) {108 if (native_os == .windows) {
108 windows.VirtualFree(slice.ptr, 0, windows.MEM_RELEASE);109 windows.VirtualFree(slice.ptr, 0, windows.MEM_RELEASE);
109 } else {110 } else {
110 const buf_aligned_len = mem.alignForward(usize, slice.len, mem.page_size);111 const buf_aligned_len = mem.alignForward(usize, slice.len, heap.pageSize());
111 posix.munmap(@alignCast(slice.ptr[0..buf_aligned_len]));112 posix.munmap(@alignCast(slice.ptr[0..buf_aligned_len]));
112 }113 }
113}114}
lib/std/heap/general_purpose_allocator.zig+78-51
...@@ -48,7 +48,7 @@...@@ -48,7 +48,7 @@
48//!48//!
49//! ## Basic Design:49//! ## Basic Design:
50//!50//!
51//! Small allocations are divided into buckets:51//! Small allocations are divided into buckets. For a max page size of 4K:
52//!52//!
53//! ```53//! ```
54//! index obj_size54//! index obj_size
...@@ -75,6 +75,9 @@...@@ -75,6 +75,9 @@
75//! BucketHeader, followed by "used bits", and two stack traces for each slot75//! 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`.
79//! At runtime, only size classes below `pageSize()` will actually be used for allocations.
80//!
78//! 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.
79//! Allocations use the data to iterate to find a free slot. Frees assert that the82//! Allocations use the data to iterate to find a free slot. Frees assert that the
80//! corresponding bit is 1 and set it to 0.83//! corresponding bit is 1 and set it to 0.
...@@ -99,11 +102,13 @@ const math = std.math;...@@ -99,11 +102,13 @@ const math = std.math;
99const assert = std.debug.assert;102const assert = std.debug.assert;
100const mem = std.mem;103const mem = std.mem;
101const Allocator = std.mem.Allocator;104const Allocator = std.mem.Allocator;
102const page_size = std.mem.page_size;105const min_page_size = std.heap.min_page_size;
106const max_page_size = std.heap.max_page_size;
107const pageSize = std.heap.pageSize;
103const StackTrace = std.builtin.StackTrace;108const StackTrace = std.builtin.StackTrace;
104109
105/// Integer type for pointing to slots in a small allocation110/// Integer type for pointing to slots in a small allocation
106const SlotIndex = std.meta.Int(.unsigned, math.log2(page_size) + 1);111const SlotIndex = std.meta.Int(.unsigned, math.log2(max_page_size) + 1);
107112
108const default_test_stack_trace_frames: usize = if (builtin.is_test) 10 else 6;113const default_test_stack_trace_frames: usize = if (builtin.is_test) 10 else 6;
109const default_sys_stack_trace_frames: usize = if (std.debug.sys_can_stack_trace) default_test_stack_trace_frames else 0;114const default_sys_stack_trace_frames: usize = if (std.debug.sys_can_stack_trace) default_test_stack_trace_frames else 0;
...@@ -157,6 +162,9 @@ pub const Config = struct {...@@ -157,6 +162,9 @@ pub const Config = struct {
157162
158pub const Check = enum { ok, leak };163pub const Check = enum { ok, leak };
159164
165var used_small_bucket_count_cache = std.atomic.Value(usize).init(0);
166var largest_used_bucket_object_size_cache = std.atomic.Value(usize).init(0);
167
160/// Default initialization of this struct is deprecated; use `.init` instead.168/// Default initialization of this struct is deprecated; use `.init` instead.
161pub fn GeneralPurposeAllocator(comptime config: Config) type {169pub fn GeneralPurposeAllocator(comptime config: Config) type {
162 return struct {170 return struct {
...@@ -206,9 +214,27 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -206,9 +214,27 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
206214
207 pub const Error = mem.Allocator.Error;215 pub const Error = mem.Allocator.Error;
208216
209 const small_bucket_count = math.log2(page_size);217 const small_bucket_count = math.log2(max_page_size);
210 const largest_bucket_object_size = 1 << (small_bucket_count - 1);218 const largest_bucket_object_size = 1 << (small_bucket_count - 1);
211 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 {
221 const cached = used_small_bucket_count_cache.load(.monotonic);
222 if (cached != 0) {
223 return cached;
224 }
225 const val = math.log2(pageSize());
226 used_small_bucket_count_cache.store(val, .monotonic);
227 return val;
228 }
229 fn largest_used_bucket_object_size() usize {
230 const cached = largest_used_bucket_object_size_cache.load(.monotonic);
231 if (cached != 0) {
232 return cached;
233 }
234 const val = @as(usize, 1) << @truncate(used_small_bucket_count() - 1);
235 largest_used_bucket_object_size_cache.store(val, .monotonic);
236 return val;
237 }
212238
213 const bucketCompare = struct {239 const bucketCompare = struct {
214 fn compare(a: *BucketHeader, b: *BucketHeader) std.math.Order {240 fn compare(a: *BucketHeader, b: *BucketHeader) std.math.Order {
...@@ -261,7 +287,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -261,7 +287,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
261 // * stack_trace_addresses: [N]usize, // traces_per_slot for every allocation287 // * stack_trace_addresses: [N]usize, // traces_per_slot for every allocation
262288
263 const BucketHeader = struct {289 const BucketHeader = struct {
264 page: [*]align(page_size) u8,290 page: [*]align(min_page_size) u8,
265 alloc_cursor: SlotIndex,291 alloc_cursor: SlotIndex,
266 used_count: SlotIndex,292 used_count: SlotIndex,
267293
...@@ -273,14 +299,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -273,14 +299,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
273 if (!config.safety) @compileError("requested size is only stored when safety is enabled");299 if (!config.safety) @compileError("requested size is only stored when safety is enabled");
274 const start_ptr = @as([*]u8, @ptrCast(bucket)) + bucketRequestedSizesStart(size_class);300 const start_ptr = @as([*]u8, @ptrCast(bucket)) + bucketRequestedSizesStart(size_class);
275 const sizes = @as([*]LargestSizeClassInt, @ptrCast(@alignCast(start_ptr)));301 const sizes = @as([*]LargestSizeClassInt, @ptrCast(@alignCast(start_ptr)));
276 const slot_count = @divExact(page_size, size_class);302 const slot_count = @divExact(pageSize(), size_class);
277 return sizes[0..slot_count];303 return sizes[0..slot_count];
278 }304 }
279305
280 fn log2PtrAligns(bucket: *BucketHeader, size_class: usize) []u8 {306 fn log2PtrAligns(bucket: *BucketHeader, size_class: usize) []u8 {
281 if (!config.safety) @compileError("requested size is only stored when safety is enabled");307 if (!config.safety) @compileError("requested size is only stored when safety is enabled");
282 const aligns_ptr = @as([*]u8, @ptrCast(bucket)) + bucketAlignsStart(size_class);308 const aligns_ptr = @as([*]u8, @ptrCast(bucket)) + bucketAlignsStart(size_class);
283 const slot_count = @divExact(page_size, size_class);309 const slot_count = @divExact(pageSize(), size_class);
284 return aligns_ptr[0..slot_count];310 return aligns_ptr[0..slot_count];
285 }311 }
286312
...@@ -312,7 +338,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -312,7 +338,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
312 /// Only valid for buckets within `empty_buckets`, and relies on the `alloc_cursor`338 /// Only valid for buckets within `empty_buckets`, and relies on the `alloc_cursor`
313 /// of empty buckets being set to `slot_count` when they are added to `empty_buckets`339 /// of empty buckets being set to `slot_count` when they are added to `empty_buckets`
314 fn emptyBucketSizeClass(bucket: *BucketHeader) usize {340 fn emptyBucketSizeClass(bucket: *BucketHeader) usize {
315 return @divExact(page_size, bucket.alloc_cursor);341 return @divExact(pageSize(), bucket.alloc_cursor);
316 }342 }
317 };343 };
318344
...@@ -355,13 +381,13 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -355,13 +381,13 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
355381
356 fn bucketAlignsStart(size_class: usize) usize {382 fn bucketAlignsStart(size_class: usize) usize {
357 if (!config.safety) @compileError("requested sizes are not stored unless safety is enabled");383 if (!config.safety) @compileError("requested sizes are not stored unless safety is enabled");
358 const slot_count = @divExact(page_size, size_class);384 const slot_count = @divExact(pageSize(), size_class);
359 return bucketRequestedSizesStart(size_class) + (@sizeOf(LargestSizeClassInt) * slot_count);385 return bucketRequestedSizesStart(size_class) + (@sizeOf(LargestSizeClassInt) * slot_count);
360 }386 }
361387
362 fn bucketStackFramesStart(size_class: usize) usize {388 fn bucketStackFramesStart(size_class: usize) usize {
363 const unaligned_start = if (config.safety) blk: {389 const unaligned_start = if (config.safety) blk: {
364 const slot_count = @divExact(page_size, size_class);390 const slot_count = @divExact(pageSize(), size_class);
365 break :blk bucketAlignsStart(size_class) + slot_count;391 break :blk bucketAlignsStart(size_class) + slot_count;
366 } else @sizeOf(BucketHeader) + usedBitsCount(size_class);392 } else @sizeOf(BucketHeader) + usedBitsCount(size_class);
367 return mem.alignForward(393 return mem.alignForward(
...@@ -372,12 +398,12 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -372,12 +398,12 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
372 }398 }
373399
374 fn bucketSize(size_class: usize) usize {400 fn bucketSize(size_class: usize) usize {
375 const slot_count = @divExact(page_size, size_class);401 const slot_count = @divExact(pageSize(), size_class);
376 return bucketStackFramesStart(size_class) + one_trace_size * traces_per_slot * slot_count;402 return bucketStackFramesStart(size_class) + one_trace_size * traces_per_slot * slot_count;
377 }403 }
378404
379 fn usedBitsCount(size_class: usize) usize {405 fn usedBitsCount(size_class: usize) usize {
380 const slot_count = @divExact(page_size, size_class);406 const slot_count = @divExact(pageSize(), size_class);
381 if (slot_count < 8) return 1;407 if (slot_count < 8) return 1;
382 return @divExact(slot_count, 8);408 return @divExact(slot_count, 8);
383 }409 }
...@@ -416,7 +442,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -416,7 +442,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
416 pub fn detectLeaks(self: *Self) bool {442 pub fn detectLeaks(self: *Self) bool {
417 var leaks = false;443 var leaks = false;
418444
419 for (&self.buckets, 0..) |*buckets, bucket_i| {445 for (0..used_small_bucket_count()) |bucket_i| {
446 const buckets = &self.buckets[bucket_i];
420 if (buckets.root == null) continue;447 if (buckets.root == null) continue;
421 const size_class = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(bucket_i));448 const size_class = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(bucket_i));
422 const used_bits_count = usedBitsCount(size_class);449 const used_bits_count = usedBitsCount(size_class);
...@@ -464,7 +491,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -464,7 +491,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
464 var bucket = node.key;491 var bucket = node.key;
465 if (config.never_unmap) {492 if (config.never_unmap) {
466 // free page that was intentionally leaked by never_unmap493 // free page that was intentionally leaked by never_unmap
467 self.backing_allocator.free(bucket.page[0..page_size]);494 self.backing_allocator.free(bucket.page[0..pageSize()]);
468 }495 }
469 // alloc_cursor was set to slot count when bucket added to empty_buckets496 // alloc_cursor was set to slot count when bucket added to empty_buckets
470 self.freeBucket(bucket, bucket.emptyBucketSizeClass());497 self.freeBucket(bucket, bucket.emptyBucketSizeClass());
...@@ -531,7 +558,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -531,7 +558,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
531 fn allocSlot(self: *Self, size_class: usize, trace_addr: usize) Error!Slot {558 fn allocSlot(self: *Self, size_class: usize, trace_addr: usize) Error!Slot {
532 const bucket_index = math.log2(size_class);559 const bucket_index = math.log2(size_class);
533 var buckets = &self.buckets[bucket_index];560 var buckets = &self.buckets[bucket_index];
534 const slot_count = @divExact(page_size, size_class);561 const slot_count = @divExact(pageSize(), size_class);
535 if (self.cur_buckets[bucket_index] == null or self.cur_buckets[bucket_index].?.alloc_cursor == slot_count) {562 if (self.cur_buckets[bucket_index] == null or self.cur_buckets[bucket_index].?.alloc_cursor == slot_count) {
536 const new_bucket = try self.createBucket(size_class);563 const new_bucket = try self.createBucket(size_class);
537 errdefer self.freeBucket(new_bucket, size_class);564 errdefer self.freeBucket(new_bucket, size_class);
...@@ -564,7 +591,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -564,7 +591,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
564 addr: usize,591 addr: usize,
565 current_bucket: ?*BucketHeader,592 current_bucket: ?*BucketHeader,
566 ) ?*BucketHeader {593 ) ?*BucketHeader {
567 const search_page: [*]align(page_size) u8 = @ptrFromInt(mem.alignBackward(usize, addr, page_size));594 const search_page: [*]align(min_page_size) u8 = @ptrFromInt(mem.alignBackward(usize, addr, pageSize()));
568 if (current_bucket != null and current_bucket.?.page == search_page) {595 if (current_bucket != null and current_bucket.?.page == search_page) {
569 return current_bucket;596 return current_bucket;
570 }597 }
...@@ -729,14 +756,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -729,14 +756,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
729 assert(old_mem.len != 0);756 assert(old_mem.len != 0);
730757
731 const aligned_size = @max(old_mem.len, @as(usize, 1) << log2_old_align);758 const aligned_size = @max(old_mem.len, @as(usize, 1) << log2_old_align);
732 if (aligned_size > largest_bucket_object_size) {759 if (aligned_size > largest_used_bucket_object_size()) {
733 return self.resizeLarge(old_mem, log2_old_align, new_size, ret_addr);760 return self.resizeLarge(old_mem, log2_old_align, new_size, ret_addr);
734 }761 }
735 const size_class_hint = math.ceilPowerOfTwoAssert(usize, aligned_size);762 const size_class_hint = math.ceilPowerOfTwoAssert(usize, aligned_size);
736763
737 var bucket_index = math.log2(size_class_hint);764 var bucket_index = math.log2(size_class_hint);
738 var size_class: usize = size_class_hint;765 var size_class: usize = size_class_hint;
739 const bucket = while (bucket_index < small_bucket_count) : (bucket_index += 1) {766 const bucket = while (bucket_index < used_small_bucket_count()) : (bucket_index += 1) {
740 if (searchBucket(&self.buckets[bucket_index], @intFromPtr(old_mem.ptr), self.cur_buckets[bucket_index])) |bucket| {767 if (searchBucket(&self.buckets[bucket_index], @intFromPtr(old_mem.ptr), self.cur_buckets[bucket_index])) |bucket| {
741 break bucket;768 break bucket;
742 }769 }
...@@ -847,7 +874,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -847,7 +874,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
847 assert(old_mem.len != 0);874 assert(old_mem.len != 0);
848875
849 const aligned_size = @max(old_mem.len, @as(usize, 1) << log2_old_align);876 const aligned_size = @max(old_mem.len, @as(usize, 1) << log2_old_align);
850 if (aligned_size > largest_bucket_object_size) {877 if (aligned_size > largest_used_bucket_object_size()) {
851 self.freeLarge(old_mem, log2_old_align, ret_addr);878 self.freeLarge(old_mem, log2_old_align, ret_addr);
852 return;879 return;
853 }880 }
...@@ -855,7 +882,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -855,7 +882,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
855882
856 var bucket_index = math.log2(size_class_hint);883 var bucket_index = math.log2(size_class_hint);
857 var size_class: usize = size_class_hint;884 var size_class: usize = size_class_hint;
858 const bucket = while (bucket_index < small_bucket_count) : (bucket_index += 1) {885 const bucket = while (bucket_index < used_small_bucket_count()) : (bucket_index += 1) {
859 if (searchBucket(&self.buckets[bucket_index], @intFromPtr(old_mem.ptr), self.cur_buckets[bucket_index])) |bucket| {886 if (searchBucket(&self.buckets[bucket_index], @intFromPtr(old_mem.ptr), self.cur_buckets[bucket_index])) |bucket| {
860 break bucket;887 break bucket;
861 }888 }
...@@ -944,14 +971,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -944,14 +971,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
944 self.cur_buckets[bucket_index] = null;971 self.cur_buckets[bucket_index] = null;
945 }972 }
946 if (!config.never_unmap) {973 if (!config.never_unmap) {
947 self.backing_allocator.free(bucket.page[0..page_size]);974 self.backing_allocator.free(bucket.page[0..pageSize()]);
948 }975 }
949 if (!config.retain_metadata) {976 if (!config.retain_metadata) {
950 self.freeBucket(bucket, size_class);977 self.freeBucket(bucket, size_class);
951 self.bucket_node_pool.destroy(node);978 self.bucket_node_pool.destroy(node);
952 } else {979 } else {
953 // move alloc_cursor to end so we can tell size_class later980 // move alloc_cursor to end so we can tell size_class later
954 const slot_count = @divExact(page_size, size_class);981 const slot_count = @divExact(pageSize(), size_class);
955 bucket.alloc_cursor = @as(SlotIndex, @truncate(slot_count));982 bucket.alloc_cursor = @as(SlotIndex, @truncate(slot_count));
956 var empty_entry = self.empty_buckets.getEntryFor(node.key);983 var empty_entry = self.empty_buckets.getEntryFor(node.key);
957 empty_entry.set(node);984 empty_entry.set(node);
...@@ -992,7 +1019,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -992,7 +1019,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
992 ret_addr: usize,1019 ret_addr: usize,
993 ) Allocator.Error![*]u8 {1020 ) Allocator.Error![*]u8 {
994 const new_aligned_size = @max(len, @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align)));1021 const new_aligned_size = @max(len, @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align)));
995 if (new_aligned_size > largest_bucket_object_size) {1022 if (new_aligned_size > largest_used_bucket_object_size()) {
996 try self.large_allocations.ensureUnusedCapacity(self.backing_allocator, 1);1023 try self.large_allocations.ensureUnusedCapacity(self.backing_allocator, 1);
997 const ptr = self.backing_allocator.rawAlloc(len, log2_ptr_align, ret_addr) orelse1024 const ptr = self.backing_allocator.rawAlloc(len, log2_ptr_align, ret_addr) orelse
998 return error.OutOfMemory;1025 return error.OutOfMemory;
...@@ -1035,7 +1062,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -1035,7 +1062,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
1035 }1062 }
10361063
1037 fn createBucket(self: *Self, size_class: usize) Error!*BucketHeader {1064 fn createBucket(self: *Self, size_class: usize) Error!*BucketHeader {
1038 const page = try self.backing_allocator.alignedAlloc(u8, page_size, page_size);1065 const page = try self.backing_allocator.alignedAlloc(u8, min_page_size, pageSize());
1039 errdefer self.backing_allocator.free(page);1066 errdefer self.backing_allocator.free(page);
10401067
1041 const bucket_size = bucketSize(size_class);1068 const bucket_size = bucketSize(size_class);
...@@ -1179,17 +1206,17 @@ test "large object - grow" {...@@ -1179,17 +1206,17 @@ test "large object - grow" {
1179 defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");1206 defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");
1180 const allocator = gpa.allocator();1207 const allocator = gpa.allocator();
11811208
1182 var slice1 = try allocator.alloc(u8, page_size * 2 - 20);1209 var slice1 = try allocator.alloc(u8, pageSize() * 2 - 20);
1183 defer allocator.free(slice1);1210 defer allocator.free(slice1);
11841211
1185 const old = slice1;1212 const old = slice1;
1186 slice1 = try allocator.realloc(slice1, page_size * 2 - 10);1213 slice1 = try allocator.realloc(slice1, pageSize() * 2 - 10);
1187 try std.testing.expect(slice1.ptr == old.ptr);1214 try std.testing.expect(slice1.ptr == old.ptr);
11881215
1189 slice1 = try allocator.realloc(slice1, page_size * 2);1216 slice1 = try allocator.realloc(slice1, pageSize() * 2);
1190 try std.testing.expect(slice1.ptr == old.ptr);1217 try std.testing.expect(slice1.ptr == old.ptr);
11911218
1192 slice1 = try allocator.realloc(slice1, page_size * 2 + 1);1219 slice1 = try allocator.realloc(slice1, pageSize() * 2 + 1);
1193}1220}
11941221
1195test "realloc small object to large object" {1222test "realloc small object to large object" {
...@@ -1203,7 +1230,7 @@ test "realloc small object to large object" {...@@ -1203,7 +1230,7 @@ test "realloc small object to large object" {
1203 slice[60] = 0x34;1230 slice[60] = 0x34;
12041231
1205 // This requires upgrading to a large object1232 // This requires upgrading to a large object
1206 const large_object_size = page_size * 2 + 50;1233 const large_object_size = pageSize() * 2 + 50;
1207 slice = try allocator.realloc(slice, large_object_size);1234 slice = try allocator.realloc(slice, large_object_size);
1208 try std.testing.expect(slice[0] == 0x12);1235 try std.testing.expect(slice[0] == 0x12);
1209 try std.testing.expect(slice[60] == 0x34);1236 try std.testing.expect(slice[60] == 0x34);
...@@ -1214,22 +1241,22 @@ test "shrink large object to large object" {...@@ -1214,22 +1241,22 @@ test "shrink large object to large object" {
1214 defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");1241 defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");
1215 const allocator = gpa.allocator();1242 const allocator = gpa.allocator();
12161243
1217 var slice = try allocator.alloc(u8, page_size * 2 + 50);1244 var slice = try allocator.alloc(u8, pageSize() * 2 + 50);
1218 defer allocator.free(slice);1245 defer allocator.free(slice);
1219 slice[0] = 0x12;1246 slice[0] = 0x12;
1220 slice[60] = 0x34;1247 slice[60] = 0x34;
12211248
1222 if (!allocator.resize(slice, page_size * 2 + 1)) return;1249 if (!allocator.resize(slice, pageSize() * 2 + 1)) return;
1223 slice = slice.ptr[0 .. page_size * 2 + 1];1250 slice = slice.ptr[0 .. pageSize() * 2 + 1];
1224 try std.testing.expect(slice[0] == 0x12);1251 try std.testing.expect(slice[0] == 0x12);
1225 try std.testing.expect(slice[60] == 0x34);1252 try std.testing.expect(slice[60] == 0x34);
12261253
1227 try std.testing.expect(allocator.resize(slice, page_size * 2 + 1));1254 try std.testing.expect(allocator.resize(slice, pageSize() * 2 + 1));
1228 slice = slice[0 .. page_size * 2 + 1];1255 slice = slice[0 .. pageSize() * 2 + 1];
1229 try std.testing.expect(slice[0] == 0x12);1256 try std.testing.expect(slice[0] == 0x12);
1230 try std.testing.expect(slice[60] == 0x34);1257 try std.testing.expect(slice[60] == 0x34);
12311258
1232 slice = try allocator.realloc(slice, page_size * 2);1259 slice = try allocator.realloc(slice, pageSize() * 2);
1233 try std.testing.expect(slice[0] == 0x12);1260 try std.testing.expect(slice[0] == 0x12);
1234 try std.testing.expect(slice[60] == 0x34);1261 try std.testing.expect(slice[60] == 0x34);
1235}1262}
...@@ -1245,13 +1272,13 @@ test "shrink large object to large object with larger alignment" {...@@ -1245,13 +1272,13 @@ test "shrink large object to large object with larger alignment" {
1245 var fba = std.heap.FixedBufferAllocator.init(&debug_buffer);1272 var fba = std.heap.FixedBufferAllocator.init(&debug_buffer);
1246 const debug_allocator = fba.allocator();1273 const debug_allocator = fba.allocator();
12471274
1248 const alloc_size = page_size * 2 + 50;1275 const alloc_size = pageSize() * 2 + 50;
1249 var slice = try allocator.alignedAlloc(u8, 16, alloc_size);1276 var slice = try allocator.alignedAlloc(u8, 16, alloc_size);
1250 defer allocator.free(slice);1277 defer allocator.free(slice);
12511278
1252 const big_alignment: usize = switch (builtin.os.tag) {1279 const big_alignment: usize = switch (builtin.os.tag) {
1253 .windows => page_size * 32, // Windows aligns to 64K.1280 .windows => pageSize() * 32, // Windows aligns to 64K.
1254 else => page_size * 2,1281 else => pageSize() * 2,
1255 };1282 };
1256 // This loop allocates until we find a page that is not aligned to the big1283 // This loop allocates until we find a page that is not aligned to the big
1257 // alignment. Then we shrink the allocation after the loop, but increase the1284 // alignment. Then we shrink the allocation after the loop, but increase the
...@@ -1277,7 +1304,7 @@ test "realloc large object to small object" {...@@ -1277,7 +1304,7 @@ test "realloc large object to small object" {
1277 defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");1304 defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");
1278 const allocator = gpa.allocator();1305 const allocator = gpa.allocator();
12791306
1280 var slice = try allocator.alloc(u8, page_size * 2 + 50);1307 var slice = try allocator.alloc(u8, pageSize() * 2 + 50);
1281 defer allocator.free(slice);1308 defer allocator.free(slice);
1282 slice[0] = 0x12;1309 slice[0] = 0x12;
1283 slice[16] = 0x34;1310 slice[16] = 0x34;
...@@ -1319,18 +1346,18 @@ test "realloc large object to larger alignment" {...@@ -1319,18 +1346,18 @@ test "realloc large object to larger alignment" {
1319 var fba = std.heap.FixedBufferAllocator.init(&debug_buffer);1346 var fba = std.heap.FixedBufferAllocator.init(&debug_buffer);
1320 const debug_allocator = fba.allocator();1347 const debug_allocator = fba.allocator();
13211348
1322 var slice = try allocator.alignedAlloc(u8, 16, page_size * 2 + 50);1349 var slice = try allocator.alignedAlloc(u8, 16, pageSize() * 2 + 50);
1323 defer allocator.free(slice);1350 defer allocator.free(slice);
13241351
1325 const big_alignment: usize = switch (builtin.os.tag) {1352 const big_alignment: usize = switch (builtin.os.tag) {
1326 .windows => page_size * 32, // Windows aligns to 64K.1353 .windows => pageSize() * 32, // Windows aligns to 64K.
1327 else => page_size * 2,1354 else => pageSize() * 2,
1328 };1355 };
1329 // This loop allocates until we find a page that is not aligned to the big alignment.1356 // This loop allocates until we find a page that is not aligned to the big alignment.
1330 var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator);1357 var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator);
1331 while (mem.isAligned(@intFromPtr(slice.ptr), big_alignment)) {1358 while (mem.isAligned(@intFromPtr(slice.ptr), big_alignment)) {
1332 try stuff_to_free.append(slice);1359 try stuff_to_free.append(slice);
1333 slice = try allocator.alignedAlloc(u8, 16, page_size * 2 + 50);1360 slice = try allocator.alignedAlloc(u8, 16, pageSize() * 2 + 50);
1334 }1361 }
1335 while (stuff_to_free.popOrNull()) |item| {1362 while (stuff_to_free.popOrNull()) |item| {
1336 allocator.free(item);1363 allocator.free(item);
...@@ -1338,15 +1365,15 @@ test "realloc large object to larger alignment" {...@@ -1338,15 +1365,15 @@ test "realloc large object to larger alignment" {
1338 slice[0] = 0x12;1365 slice[0] = 0x12;
1339 slice[16] = 0x34;1366 slice[16] = 0x34;
13401367
1341 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 100);1368 slice = try allocator.reallocAdvanced(slice, 32, pageSize() * 2 + 100);
1342 try std.testing.expect(slice[0] == 0x12);1369 try std.testing.expect(slice[0] == 0x12);
1343 try std.testing.expect(slice[16] == 0x34);1370 try std.testing.expect(slice[16] == 0x34);
13441371
1345 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 25);1372 slice = try allocator.reallocAdvanced(slice, 32, pageSize() * 2 + 25);
1346 try std.testing.expect(slice[0] == 0x12);1373 try std.testing.expect(slice[0] == 0x12);
1347 try std.testing.expect(slice[16] == 0x34);1374 try std.testing.expect(slice[16] == 0x34);
13481375
1349 slice = try allocator.reallocAdvanced(slice, big_alignment, page_size * 2 + 100);1376 slice = try allocator.reallocAdvanced(slice, big_alignment, pageSize() * 2 + 100);
1350 try std.testing.expect(slice[0] == 0x12);1377 try std.testing.expect(slice[0] == 0x12);
1351 try std.testing.expect(slice[16] == 0x34);1378 try std.testing.expect(slice[16] == 0x34);
1352}1379}
...@@ -1362,7 +1389,7 @@ test "large object shrinks to small but allocation fails during shrink" {...@@ -1362,7 +1389,7 @@ test "large object shrinks to small but allocation fails during shrink" {
1362 defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");1389 defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");
1363 const allocator = gpa.allocator();1390 const allocator = gpa.allocator();
13641391
1365 var slice = try allocator.alloc(u8, page_size * 2 + 50);1392 var slice = try allocator.alloc(u8, pageSize() * 2 + 50);
1366 defer allocator.free(slice);1393 defer allocator.free(slice);
1367 slice[0] = 0x12;1394 slice[0] = 0x12;
1368 slice[3] = 0x34;1395 slice[3] = 0x34;
...@@ -1433,7 +1460,7 @@ test "double frees" {...@@ -1433,7 +1460,7 @@ test "double frees" {
1433 try std.testing.expect(GPA.searchBucket(&gpa.empty_buckets, @intFromPtr(small.ptr), null) != null);1460 try std.testing.expect(GPA.searchBucket(&gpa.empty_buckets, @intFromPtr(small.ptr), null) != null);
14341461
1435 // detect a large allocation double free1462 // detect a large allocation double free
1436 const large = try allocator.alloc(u8, 2 * page_size);1463 const large = try allocator.alloc(u8, 2 * pageSize());
1437 try std.testing.expect(gpa.large_allocations.contains(@intFromPtr(large.ptr)));1464 try std.testing.expect(gpa.large_allocations.contains(@intFromPtr(large.ptr)));
1438 try std.testing.expectEqual(gpa.large_allocations.getEntry(@intFromPtr(large.ptr)).?.value_ptr.bytes, large);1465 try std.testing.expectEqual(gpa.large_allocations.getEntry(@intFromPtr(large.ptr)).?.value_ptr.bytes, large);
1439 allocator.free(large);1466 allocator.free(large);
...@@ -1442,7 +1469,7 @@ test "double frees" {...@@ -1442,7 +1469,7 @@ test "double frees" {
14421469
1443 const normal_small = try allocator.alloc(u8, size_class);1470 const normal_small = try allocator.alloc(u8, size_class);
1444 defer allocator.free(normal_small);1471 defer allocator.free(normal_small);
1445 const normal_large = try allocator.alloc(u8, 2 * page_size);1472 const normal_large = try allocator.alloc(u8, 2 * pageSize());
1446 defer allocator.free(normal_large);1473 defer allocator.free(normal_large);
14471474
1448 // check that flushing retained metadata doesn't disturb live allocations1475 // check that flushing retained metadata doesn't disturb live allocations
...@@ -1475,8 +1502,8 @@ test "bug 9995 fix, large allocs count requested size not backing size" {...@@ -1475,8 +1502,8 @@ test "bug 9995 fix, large allocs count requested size not backing size" {
1475 var gpa = GeneralPurposeAllocator(.{ .enable_memory_limit = true }){};1502 var gpa = GeneralPurposeAllocator(.{ .enable_memory_limit = true }){};
1476 const allocator = gpa.allocator();1503 const allocator = gpa.allocator();
14771504
1478 var buf = try allocator.alignedAlloc(u8, 1, page_size + 1);1505 var buf = try allocator.alignedAlloc(u8, 1, pageSize() + 1);
1479 try std.testing.expect(gpa.total_requested_bytes == page_size + 1);1506 try std.testing.expect(gpa.total_requested_bytes == pageSize() + 1);
1480 buf = try allocator.realloc(buf, 1);1507 buf = try allocator.realloc(buf, 1);
1481 try std.testing.expect(gpa.total_requested_bytes == 1);1508 try std.testing.expect(gpa.total_requested_bytes == 1);
1482 buf = try allocator.realloc(buf, 2);1509 buf = try allocator.realloc(buf, 2);
lib/std/heap/sbrk_allocator.zig+4-3
...@@ -3,6 +3,7 @@ const builtin = @import("builtin");...@@ -3,6 +3,7 @@ const builtin = @import("builtin");
3const math = std.math;3const math = std.math;
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
5const mem = std.mem;5const mem = std.mem;
6const heap = std.heap;
6const assert = std.debug.assert;7const assert = std.debug.assert;
78
8pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {9pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {
...@@ -18,7 +19,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {...@@ -18,7 +19,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {
18 const max_usize = math.maxInt(usize);19 const max_usize = math.maxInt(usize);
19 const ushift = math.Log2Int(usize);20 const ushift = math.Log2Int(usize);
20 const bigpage_size = 64 * 1024;21 const bigpage_size = 64 * 1024;
21 const pages_per_bigpage = bigpage_size / mem.page_size;22 const pages_per_bigpage = bigpage_size / heap.pageSize();
22 const bigpage_count = max_usize / bigpage_size;23 const bigpage_count = max_usize / bigpage_size;
2324
24 /// Because of storing free list pointers, the minimum size class is 3.25 /// Because of storing free list pointers, the minimum size class is 3.
...@@ -58,7 +59,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {...@@ -58,7 +59,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {
58 }59 }
5960
60 const next_addr = next_addrs[class];61 const next_addr = next_addrs[class];
61 if (next_addr % mem.page_size == 0) {62 if (next_addr % heap.pageSize == 0) {
62 const addr = allocBigPages(1);63 const addr = allocBigPages(1);
63 if (addr == 0) return null;64 if (addr == 0) return null;
64 //std.debug.print("allocated fresh slot_size={d} class={d} addr=0x{x}\n", .{65 //std.debug.print("allocated fresh slot_size={d} class={d} addr=0x{x}\n", .{
...@@ -153,7 +154,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {...@@ -153,7 +154,7 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {
153 big_frees[class] = node.*;154 big_frees[class] = node.*;
154 return top_free_ptr;155 return top_free_ptr;
155 }156 }
156 return sbrk(pow2_pages * pages_per_bigpage * mem.page_size);157 return sbrk(pow2_pages * pages_per_bigpage * heap.pageSize());
157 }158 }
158 };159 };
159}160}
lib/std/mem.zig+9-28
...@@ -8,26 +8,6 @@ const testing = std.testing;...@@ -8,26 +8,6 @@ const testing = std.testing;
8const Endian = std.builtin.Endian;8const Endian = std.builtin.Endian;
9const native_endian = builtin.cpu.arch.endian();9const native_endian = builtin.cpu.arch.endian();
1010
11/// Compile time known minimum page size.
12/// https://github.com/ziglang/zig/issues/4082
13pub const page_size = switch (builtin.cpu.arch) {
14 .wasm32, .wasm64 => 64 * 1024,
15 .aarch64 => switch (builtin.os.tag) {
16 .macos, .ios, .watchos, .tvos, .visionos => 16 * 1024,
17 else => 4 * 1024,
18 },
19 .sparc64 => 8 * 1024,
20 .loongarch32, .loongarch64 => switch (builtin.os.tag) {
21 // Linux default KConfig value is 16KiB
22 .linux => 16 * 1024,
23 // FIXME:
24 // There is no other OS supported yet. Use the same value
25 // as Linux for now.
26 else => 16 * 1024,
27 },
28 else => 4 * 1024,
29};
30
31/// The standard library currently thoroughly depends on byte size11/// The standard library currently thoroughly depends on byte size
32/// being 8 bits. (see the use of u8 throughout allocation code as12/// being 8 bits. (see the use of u8 throughout allocation code as
33/// the "byte" type.) Code which depends on this can reference this13/// the "byte" type.) Code which depends on this can reference this
...@@ -1072,12 +1052,13 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co...@@ -1072,12 +1052,13 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co
1072 const Block = @Vector(block_len, T);1052 const Block = @Vector(block_len, T);
1073 const mask: Block = @splat(sentinel);1053 const mask: Block = @splat(sentinel);
10741054
1075 comptime std.debug.assert(std.mem.page_size % block_size == 0);1055 comptime std.debug.assert(std.heap.max_page_size % @sizeOf(Block) == 0);
1056 std.debug.assert(std.heap.pageSize() % @sizeOf(Block) == 0);
10761057
1077 // First block may be unaligned1058 // First block may be unaligned
1078 const start_addr = @intFromPtr(&p[i]);1059 const start_addr = @intFromPtr(&p[i]);
1079 const offset_in_page = start_addr & (std.mem.page_size - 1);1060 const offset_in_page = start_addr & (std.heap.pageSize() - 1);
1080 if (offset_in_page <= std.mem.page_size - block_size) {1061 if (offset_in_page <= std.heap.pageSize() - @sizeOf(Block)) {
1081 // Will not read past the end of a page, full block.1062 // Will not read past the end of a page, full block.
1082 const block: Block = p[i..][0..block_len].*;1063 const block: Block = p[i..][0..block_len].*;
1083 const matches = block == mask;1064 const matches = block == mask;
...@@ -1125,18 +1106,18 @@ test "indexOfSentinel vector paths" {...@@ -1125,18 +1106,18 @@ test "indexOfSentinel vector paths" {
1125 const block_len = std.simd.suggestVectorLength(T) orelse continue;1106 const block_len = std.simd.suggestVectorLength(T) orelse continue;
11261107
1127 // Allocate three pages so we guarantee a page-crossing address with a full page after1108 // Allocate three pages so we guarantee a page-crossing address with a full page after
1128 const memory = try allocator.alloc(T, 3 * std.mem.page_size / @sizeOf(T));1109 const memory = try allocator.alloc(T, 3 * std.heap.pageSize() / @sizeOf(T));
1129 defer allocator.free(memory);1110 defer allocator.free(memory);
1130 @memset(memory, 0xaa);1111 @memset(memory, 0xaa);
11311112
1132 // Find starting page-alignment = 01113 // Find starting page-alignment = 0
1133 var start: usize = 0;1114 var start: usize = 0;
1134 const start_addr = @intFromPtr(&memory);1115 const start_addr = @intFromPtr(&memory);
1135 start += (std.mem.alignForward(usize, start_addr, std.mem.page_size) - start_addr) / @sizeOf(T);1116 start += (std.mem.alignForward(usize, start_addr, std.heap.pageSize()) - start_addr) / @sizeOf(T);
1136 try testing.expect(start < std.mem.page_size / @sizeOf(T));1117 try testing.expect(start < std.heap.pageSize() / @sizeOf(T));
11371118
1138 // Validate all sub-block alignments1119 // Validate all sub-block alignments
1139 const search_len = std.mem.page_size / @sizeOf(T);1120 const search_len = std.heap.pageSize() / @sizeOf(T);
1140 memory[start + search_len] = 0;1121 memory[start + search_len] = 0;
1141 for (0..block_len) |offset| {1122 for (0..block_len) |offset| {
1142 try testing.expectEqual(search_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start + offset])));1123 try testing.expectEqual(search_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start + offset])));
...@@ -1144,7 +1125,7 @@ test "indexOfSentinel vector paths" {...@@ -1144,7 +1125,7 @@ test "indexOfSentinel vector paths" {
1144 memory[start + search_len] = 0xaa;1125 memory[start + search_len] = 0xaa;
11451126
1146 // Validate page boundary crossing1127 // Validate page boundary crossing
1147 const start_page_boundary = start + (std.mem.page_size / @sizeOf(T));1128 const start_page_boundary = start + (std.heap.pageSize() / @sizeOf(T));
1148 memory[start_page_boundary + block_len] = 0;1129 memory[start_page_boundary + block_len] = 0;
1149 for (0..block_len) |offset| {1130 for (0..block_len) |offset| {
1150 try testing.expectEqual(2 * block_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start_page_boundary - block_len + offset])));1131 try testing.expectEqual(2 * block_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start_page_boundary - block_len + offset])));
lib/std/mem/Allocator.zig+1-1
...@@ -218,7 +218,7 @@ fn allocBytesWithAlignment(self: Allocator, comptime alignment: u29, byte_count:...@@ -218,7 +218,7 @@ fn allocBytesWithAlignment(self: Allocator, comptime alignment: u29, byte_count:
218 // The Zig Allocator interface is not intended to solve alignments beyond218 // 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 OS219 // the minimum OS page size. For these use cases, the caller must use OS
220 // APIs directly.220 // APIs directly.
221 comptime assert(alignment <= mem.page_size);221 if (!@inComptime() and alignment > std.heap.pageSize()) @panic("Alignment must be smaller than page size.");
222222
223 if (byte_count == 0) {223 if (byte_count == 0) {
224 const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), alignment);224 const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), alignment);
lib/std/os/linux/IoUring.zig+8-7
...@@ -3,6 +3,7 @@ const std = @import("std");...@@ -3,6 +3,7 @@ const std = @import("std");
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const mem = std.mem;5const mem = std.mem;
6const heap = std.heap;
6const net = std.net;7const net = std.net;
7const posix = std.posix;8const posix = std.posix;
8const linux = std.os.linux;9const linux = std.os.linux;
...@@ -1341,8 +1342,8 @@ pub const SubmissionQueue = struct {...@@ -1341,8 +1342,8 @@ pub const SubmissionQueue = struct {
1341 dropped: *u32,1342 dropped: *u32,
1342 array: []u32,1343 array: []u32,
1343 sqes: []linux.io_uring_sqe,1344 sqes: []linux.io_uring_sqe,
1344 mmap: []align(mem.page_size) u8,1345 mmap: []align(heap.min_page_size) u8,
1345 mmap_sqes: []align(mem.page_size) u8,1346 mmap_sqes: []align(heap.min_page_size) u8,
13461347
1347 // 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:
1348 // 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()`.
...@@ -1460,7 +1461,7 @@ pub const BufferGroup = struct {...@@ -1460,7 +1461,7 @@ pub const BufferGroup = struct {
1460 /// Pointer to the memory shared by the kernel.1461 /// Pointer to the memory shared by the kernel.
1461 /// `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.
1462 /// 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.
1463 br: *align(mem.page_size) linux.io_uring_buf_ring,1464 br: *align(heap.min_page_size) linux.io_uring_buf_ring,
1464 /// Contiguous block of memory of size (buffers_count * buffer_size).1465 /// Contiguous block of memory of size (buffers_count * buffer_size).
1465 buffers: []u8,1466 buffers: []u8,
1466 /// Size of each buffer in buffers.1467 /// Size of each buffer in buffers.
...@@ -1555,7 +1556,7 @@ pub const BufferGroup = struct {...@@ -1555,7 +1556,7 @@ pub const BufferGroup = struct {
1555/// `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.
1556/// `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.
1557/// `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.
1558pub fn setup_buf_ring(fd: posix.fd_t, entries: u16, group_id: u16) !*align(mem.page_size) linux.io_uring_buf_ring {1559pub fn setup_buf_ring(fd: posix.fd_t, entries: u16, group_id: u16) !*align(heap.min_page_size) linux.io_uring_buf_ring {
1559 if (entries == 0 or entries > 1 << 15) return error.EntriesNotInRange;1560 if (entries == 0 or entries > 1 << 15) return error.EntriesNotInRange;
1560 if (!std.math.isPowerOfTwo(entries)) return error.EntriesNotPowerOfTwo;1561 if (!std.math.isPowerOfTwo(entries)) return error.EntriesNotPowerOfTwo;
15611562
...@@ -1571,7 +1572,7 @@ pub fn setup_buf_ring(fd: posix.fd_t, entries: u16, group_id: u16) !*align(mem.p...@@ -1571,7 +1572,7 @@ pub fn setup_buf_ring(fd: posix.fd_t, entries: u16, group_id: u16) !*align(mem.p
1571 errdefer posix.munmap(mmap);1572 errdefer posix.munmap(mmap);
1572 assert(mmap.len == mmap_size);1573 assert(mmap.len == mmap_size);
15731574
1574 const br: *align(mem.page_size) linux.io_uring_buf_ring = @ptrCast(mmap.ptr);1575 const br: *align(heap.min_page_size) linux.io_uring_buf_ring = @ptrCast(mmap.ptr);
1575 try register_buf_ring(fd, @intFromPtr(br), entries, group_id);1576 try register_buf_ring(fd, @intFromPtr(br), entries, group_id);
1576 return br;1577 return br;
1577}1578}
...@@ -1613,9 +1614,9 @@ fn handle_register_buf_ring_result(res: usize) !void {...@@ -1613,9 +1614,9 @@ fn handle_register_buf_ring_result(res: usize) !void {
1613}1614}
16141615
1615// 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.
1616pub fn free_buf_ring(fd: posix.fd_t, br: *align(mem.page_size) linux.io_uring_buf_ring, entries: u32, group_id: u16) void {1617pub 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 unregister_buf_ring(fd, group_id) catch {};1618 unregister_buf_ring(fd, group_id) catch {};
1618 var mmap: []align(mem.page_size) u8 = undefined;1619 var mmap: []align(heap.min_page_size) u8 = undefined;
1619 mmap.ptr = @ptrCast(br);1620 mmap.ptr = @ptrCast(br);
1620 mmap.len = entries * @sizeOf(linux.io_uring_buf);1621 mmap.len = entries * @sizeOf(linux.io_uring_buf);
1621 posix.munmap(mmap);1622 posix.munmap(mmap);
lib/std/os/linux/tls.zig+4-3
...@@ -11,6 +11,7 @@...@@ -11,6 +11,7 @@
1111
12const std = @import("std");12const std = @import("std");
13const mem = std.mem;13const mem = std.mem;
14const heap = std.heap;
14const elf = std.elf;15const elf = std.elf;
15const math = std.math;16const math = std.math;
16const assert = std.debug.assert;17const assert = std.debug.assert;
...@@ -490,7 +491,7 @@ pub fn prepareArea(area: []u8) usize {...@@ -490,7 +491,7 @@ pub fn prepareArea(area: []u8) usize {
490// and LLVM or LLD is not smart enough to lay out the TLS data in a space-conserving way. Anyway, I491// and LLVM or LLD is not smart enough to lay out the TLS data in a space-conserving way. Anyway, I
491// think it's fine because it's less than 3 pages of memory, and putting it in the ELF like this is492// think it's fine because it's less than 3 pages of memory, and putting it in the ELF like this is
492// 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.
493var main_thread_area_buffer: [0x2100]u8 align(mem.page_size) = undefined;494var main_thread_area_buffer: [0x2100]u8 align(heap.min_page_size) = undefined;
494495
495/// 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,
496/// and assigns the architecture-specific value to the TP register.497/// and assigns the architecture-specific value to the TP register.
...@@ -503,7 +504,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void {...@@ -503,7 +504,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void {
503 const area = blk: {504 const area = blk: {
504 // Fast path for the common case where the TLS data is really small, avoid an allocation and505 // Fast path for the common case where the TLS data is really small, avoid an allocation and
505 // use our local buffer.506 // use our local buffer.
506 if (area_desc.alignment <= mem.page_size and area_desc.size <= main_thread_area_buffer.len) {507 if (area_desc.alignment <= heap.min_page_size and area_desc.size <= main_thread_area_buffer.len) {
507 break :blk main_thread_area_buffer[0..area_desc.size];508 break :blk main_thread_area_buffer[0..area_desc.size];
508 }509 }
509510
...@@ -517,7 +518,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void {...@@ -517,7 +518,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void {
517 );518 );
518 if (@as(isize, @bitCast(begin_addr)) < 0) @trap();519 if (@as(isize, @bitCast(begin_addr)) < 0) @trap();
519520
520 const area_ptr: [*]align(mem.page_size) u8 = @ptrFromInt(begin_addr);521 const area_ptr: [*]align(heap.min_page_size) u8 = @ptrFromInt(begin_addr);
521522
522 // Make sure the slice is correctly aligned.523 // Make sure the slice is correctly aligned.
523 const begin_aligned_addr = alignForward(begin_addr, area_desc.alignment);524 const begin_aligned_addr = alignForward(begin_addr, area_desc.alignment);
lib/std/os/plan9.zig+2-2
...@@ -367,8 +367,8 @@ pub fn sbrk(n: usize) usize {...@@ -367,8 +367,8 @@ pub fn sbrk(n: usize) usize {
367 bloc = @intFromPtr(&ExecData.end);367 bloc = @intFromPtr(&ExecData.end);
368 bloc_max = @intFromPtr(&ExecData.end);368 bloc_max = @intFromPtr(&ExecData.end);
369 }369 }
370 const bl = std.mem.alignForward(usize, bloc, std.mem.page_size);370 const bl = std.mem.alignForward(usize, bloc, std.heap.pageSize());
371 const n_aligned = std.mem.alignForward(usize, n, std.mem.page_size);371 const n_aligned = std.mem.alignForward(usize, n, std.heap.pageSize());
372 if (bl + n_aligned > bloc_max) {372 if (bl + n_aligned > bloc_max) {
373 // we need to allocate373 // we need to allocate
374 if (brk_(bl + n_aligned) < 0) return 0;374 if (brk_(bl + n_aligned) < 0) return 0;
lib/std/os/windows/kernel32.zig+4-3
...@@ -42,6 +42,7 @@ const WCHAR = windows.WCHAR;...@@ -42,6 +42,7 @@ const WCHAR = windows.WCHAR;
42const WIN32_FIND_DATAW = windows.WIN32_FIND_DATAW;42const WIN32_FIND_DATAW = windows.WIN32_FIND_DATAW;
43const Win32Error = windows.Win32Error;43const Win32Error = windows.Win32Error;
44const WORD = windows.WORD;44const WORD = windows.WORD;
45const SYSTEM_INFO = windows.SYSTEM_INFO;
4546
46// I/O - Filesystem47// I/O - Filesystem
4748
...@@ -667,6 +668,6 @@ pub extern "kernel32" fn SetLastError(...@@ -667,6 +668,6 @@ pub extern "kernel32" fn SetLastError(
667// TODO:668// TODO:
668// Wrapper around KUSER_SHARED_DATA.SystemTime.669// Wrapper around KUSER_SHARED_DATA.SystemTime.
669// Much better to use NtQuerySystemTime or NtQuerySystemTimePrecise for guaranteed 0.1ns precision.670// Much better to use NtQuerySystemTime or NtQuerySystemTimePrecise for guaranteed 0.1ns precision.
670pub extern "kernel32" fn GetSystemTimeAsFileTime(671pub extern "kernel32" fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: *FILETIME) callconv(.winapi) void;
671 lpSystemTimeAsFileTime: *FILETIME,672
672) callconv(.winapi) void;673pub extern "kernel32" fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) callconv(.winapi) void;
lib/std/posix.zig+10-9
...@@ -18,6 +18,7 @@ const builtin = @import("builtin");...@@ -18,6 +18,7 @@ const builtin = @import("builtin");
18const root = @import("root");18const root = @import("root");
19const std = @import("std.zig");19const std = @import("std.zig");
20const mem = std.mem;20const mem = std.mem;
21const heap = std.heap;
21const fs = std.fs;22const fs = std.fs;
22const max_path_bytes = fs.max_path_bytes;23const max_path_bytes = fs.max_path_bytes;
23const maxInt = std.math.maxInt;24const maxInt = std.math.maxInt;
...@@ -4694,7 +4695,7 @@ pub const MProtectError = error{...@@ -4694,7 +4695,7 @@ pub const MProtectError = error{
4694 OutOfMemory,4695 OutOfMemory,
4695} || UnexpectedError;4696} || UnexpectedError;
46964697
4697pub fn mprotect(memory: []align(mem.page_size) u8, protection: u32) MProtectError!void {4698pub fn mprotect(memory: []align(heap.min_page_size) u8, protection: u32) MProtectError!void {
4698 if (native_os == .windows) {4699 if (native_os == .windows) {
4699 const win_prot: windows.DWORD = switch (@as(u3, @truncate(protection))) {4700 const win_prot: windows.DWORD = switch (@as(u3, @truncate(protection))) {
4700 0b000 => windows.PAGE_NOACCESS,4701 0b000 => windows.PAGE_NOACCESS,
...@@ -4759,21 +4760,21 @@ pub const MMapError = error{...@@ -4759,21 +4760,21 @@ pub const MMapError = error{
4759/// * SIGSEGV - Attempted write into a region mapped as read-only.4760/// * SIGSEGV - Attempted write into a region mapped as read-only.
4760/// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file4761/// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file
4761pub fn mmap(4762pub fn mmap(
4762 ptr: ?[*]align(mem.page_size) u8,4763 ptr: ?[*]align(heap.min_page_size) u8,
4763 length: usize,4764 length: usize,
4764 prot: u32,4765 prot: u32,
4765 flags: system.MAP,4766 flags: system.MAP,
4766 fd: fd_t,4767 fd: fd_t,
4767 offset: u64,4768 offset: u64,
4768) MMapError![]align(mem.page_size) u8 {4769) MMapError![]align(heap.min_page_size) u8 {
4769 const mmap_sym = if (lfs64_abi) system.mmap64 else system.mmap;4770 const mmap_sym = if (lfs64_abi) system.mmap64 else system.mmap;
4770 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));
4771 const err: E = if (builtin.link_libc) blk: {4772 const err: E = if (builtin.link_libc) blk: {
4772 if (rc != std.c.MAP_FAILED) return @as([*]align(mem.page_size) u8, @ptrCast(@alignCast(rc)))[0..length];4773 if (rc != std.c.MAP_FAILED) return @as([*]align(heap.min_page_size) u8, @ptrCast(@alignCast(rc)))[0..length];
4773 break :blk @enumFromInt(system._errno().*);4774 break :blk @enumFromInt(system._errno().*);
4774 } else blk: {4775 } else blk: {
4775 const err = errno(rc);4776 const err = errno(rc);
4776 if (err == .SUCCESS) return @as([*]align(mem.page_size) u8, @ptrFromInt(rc))[0..length];4777 if (err == .SUCCESS) return @as([*]align(heap.min_page_size) u8, @ptrFromInt(rc))[0..length];
4777 break :blk err;4778 break :blk err;
4778 };4779 };
4779 switch (err) {4780 switch (err) {
...@@ -4799,7 +4800,7 @@ pub fn mmap(...@@ -4799,7 +4800,7 @@ pub fn mmap(
4799/// Zig's munmap function does not, for two reasons:4800/// Zig's munmap function does not, for two reasons:
4800/// * It violates the Zig principle that resource deallocation must succeed.4801/// * It violates the Zig principle that resource deallocation must succeed.
4801/// * The Windows function, VirtualFree, has this restriction.4802/// * The Windows function, VirtualFree, has this restriction.
4802pub fn munmap(memory: []align(mem.page_size) const u8) void {4803pub fn munmap(memory: []align(heap.min_page_size) const u8) void {
4803 switch (errno(system.munmap(memory.ptr, memory.len))) {4804 switch (errno(system.munmap(memory.ptr, memory.len))) {
4804 .SUCCESS => return,4805 .SUCCESS => return,
4805 .INVAL => unreachable, // Invalid parameters.4806 .INVAL => unreachable, // Invalid parameters.
...@@ -4813,7 +4814,7 @@ pub const MSyncError = error{...@@ -4813,7 +4814,7 @@ pub const MSyncError = error{
4813 PermissionDenied,4814 PermissionDenied,
4814} || UnexpectedError;4815} || UnexpectedError;
48154816
4816pub fn msync(memory: []align(mem.page_size) u8, flags: i32) MSyncError!void {4817pub fn msync(memory: []align(heap.min_page_size) u8, flags: i32) MSyncError!void {
4817 switch (errno(system.msync(memory.ptr, memory.len, flags))) {4818 switch (errno(system.msync(memory.ptr, memory.len, flags))) {
4818 .SUCCESS => return,4819 .SUCCESS => return,
4819 .PERM => return error.PermissionDenied,4820 .PERM => return error.PermissionDenied,
...@@ -7135,7 +7136,7 @@ pub const MincoreError = error{...@@ -7135,7 +7136,7 @@ pub const MincoreError = error{
7135} || UnexpectedError;7136} || UnexpectedError;
71367137
7137/// Determine whether pages are resident in memory.7138/// Determine whether pages are resident in memory.
7138pub fn mincore(ptr: [*]align(mem.page_size) u8, length: usize, vec: [*]u8) MincoreError!void {7139pub fn mincore(ptr: [*]align(heap.min_page_size) u8, length: usize, vec: [*]u8) MincoreError!void {
7139 return switch (errno(system.mincore(ptr, length, vec))) {7140 return switch (errno(system.mincore(ptr, length, vec))) {
7140 .SUCCESS => {},7141 .SUCCESS => {},
7141 .AGAIN => error.SystemResources,7142 .AGAIN => error.SystemResources,
...@@ -7181,7 +7182,7 @@ pub const MadviseError = error{...@@ -7181,7 +7182,7 @@ pub const MadviseError = error{
71817182
7182/// Give advice about use of memory.7183/// Give advice about use of memory.
7183/// This syscall is optional and is sometimes configured to be disabled.7184/// This syscall is optional and is sometimes configured to be disabled.
7184pub fn madvise(ptr: [*]align(mem.page_size) u8, length: usize, advice: u32) MadviseError!void {7185pub fn madvise(ptr: [*]align(heap.min_page_size) u8, length: usize, advice: u32) MadviseError!void {
7185 switch (errno(system.madvise(ptr, length, advice))) {7186 switch (errno(system.madvise(ptr, length, advice))) {
7186 .SUCCESS => return,7187 .SUCCESS => return,
7187 .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 };
15621562
1563 var buf: [std.mem.page_size]u8 = undefined;1563 var buf: [std.heap.min_page_size]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.mem.page_size == 0);579 assert(phdr.p_memsz % std.heap.pageSize() == 0);
580580
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+4
...@@ -119,6 +119,10 @@ pub const Options = struct {...@@ -119,6 +119,10 @@ pub const Options = struct {
119 args: anytype,119 args: anytype,
120 ) void = log.defaultLog,120 ) void = log.defaultLog,
121121
122 min_page_size: ?usize = null,
123 max_page_size: ?usize = null,
124 queryPageSizeFn: fn () usize = heap.defaultQueryPageSize,
125
122 fmt_max_depth: usize = fmt.default_max_depth,126 fmt_max_depth: usize = fmt.default_max_depth,
123127
124 cryptoRandomSeed: fn (buffer: []u8) void = @import("crypto/tlcsprng.zig").defaultRandomSeed,128 cryptoRandomSeed: fn (buffer: []u8) void = @import("crypto/tlcsprng.zig").defaultRandomSeed,
lib/std/zip.zig+1-1
...@@ -162,7 +162,7 @@ pub fn decompress(...@@ -162,7 +162,7 @@ pub fn decompress(
162 var total_uncompressed: u64 = 0;162 var total_uncompressed: u64 = 0;
163 switch (method) {163 switch (method) {
164 .store => {164 .store => {
165 var buf: [std.mem.page_size]u8 = undefined;165 var buf: [4096]u8 = undefined;
166 while (true) {166 while (true) {
167 const len = try reader.read(&buf);167 const len = try reader.read(&buf);
168 if (len == 0) break;168 if (len == 0) break;
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.mem.page_size]u8 = undefined;1252 var buf: [std.heap.min_page_size]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}",