authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-29 14:16:25-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-06 14:23:23-08:00
log284de7d957037c8a7032bd6e2a95bd5f55b73666
tree852d4ef1e8fd8c052485fd38d0dcdfafd28594bb
parent439667be0476f5bf60f3efbb82a3c4d5aae96ee4

adjust runtime page size APIs

* fix merge conflicts * rename the declarations * reword documentation * extract FixedBufferAllocator to separate file * take advantage of locals * remove the assertion about max alignment in Allocator API, leaving it Allocator implementation defined * fix non-inline function call in start logic The GeneralPurposeAllocator implementation is totally broken because it uses global state but I didn't address that in this commit.

23 files changed, 703 insertions(+), 698 deletions(-)

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