diff --git a/lib/std/heap/PageAllocator.zig b/lib/std/heap/PageAllocator.zig index 59b0c6015d..c0c0c14695 100644 --- a/lib/std/heap/PageAllocator.zig +++ b/lib/std/heap/PageAllocator.zig @@ -140,7 +140,8 @@ fn free(context: *anyopaque, slice: []u8, alignment: mem.Alignment, return_addre } } -fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 { +fn realloc(uncasted_memory: []u8, new_len: usize, may_move: bool) ?[*]u8 { + const memory: []align(std.heap.page_size_min) u8 = @alignCast(uncasted_memory); const page_size = std.heap.pageSize(); const new_size_aligned = mem.alignForward(usize, new_len, page_size); @@ -153,7 +154,7 @@ fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 { // For shrinking that is not releasing, we will only decommit // the pages not needed anymore. windows.VirtualFree( - @as(*anyopaque, @ptrFromInt(new_addr_end)), + @ptrFromInt(new_addr_end), old_addr_end - new_addr_end, windows.MEM_DECOMMIT, ); @@ -171,10 +172,11 @@ fn realloc(memory: []u8, new_len: usize, may_move: bool) ?[*]u8 { if (new_size_aligned == page_aligned_len) return memory.ptr; - const mremap_available = false; // native_os == .linux; + const mremap_available = native_os == .linux; if (mremap_available) { // TODO: if the next_mmap_addr_hint is within the remapped range, update it - return posix.mremap(memory, new_len, .{ .MAYMOVE = may_move }, null) catch return null; + const new_memory = posix.mremap(memory.ptr, memory.len, new_len, .{ .MAYMOVE = may_move }, null) catch return null; + return new_memory.ptr; } if (new_size_aligned < page_aligned_len) { diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 365fb9f05f..6e64d022cb 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -305,6 +305,13 @@ pub const MAP = switch (native_arch) { else => @compileError("missing std.os.linux.MAP constants for this architecture"), }; +pub const MREMAP = packed struct(u32) { + MAYMOVE: bool = false, + FIXED: bool = false, + DONTUNMAP: bool = false, + _: u29 = 0, +}; + pub const O = switch (native_arch) { .x86_64 => packed struct(u32) { ACCMODE: ACCMODE = .RDONLY, @@ -934,6 +941,17 @@ pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize { return syscall3(.mprotect, @intFromPtr(address), length, protection); } +pub fn mremap(old_addr: ?[*]const u8, old_len: usize, new_len: usize, flags: MREMAP, new_addr: ?[*]const u8) usize { + return syscall5( + .mremap, + @intFromPtr(old_addr), + old_len, + new_len, + @as(u32, @bitCast(flags)), + @intFromPtr(new_addr), + ); +} + pub const MSF = struct { pub const ASYNC = 1; pub const INVALIDATE = 2; diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 5b36c9b139..a1409705bf 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -83,6 +83,7 @@ pub const MAP = system.MAP; pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN; pub const MFD = system.MFD; pub const MMAP2_UNIT = system.MMAP2_UNIT; +pub const MREMAP = system.MREMAP; pub const MSF = system.MSF; pub const MSG = system.MSG; pub const NAME_MAX = system.NAME_MAX; @@ -4809,6 +4810,40 @@ pub fn munmap(memory: []align(page_size_min) const u8) void { } } +pub const MRemapError = error{ + LockedMemoryLimitExceeded, + /// Either a bug in the calling code, or the operating system abused the + /// EINVAL error code. + InvalidSyscallParameters, + OutOfMemory, +} || UnexpectedError; + +pub fn mremap( + old_address: ?[*]align(page_size_min) u8, + old_len: usize, + new_len: usize, + flags: system.MREMAP, + new_address: ?[*]align(page_size_min) u8, +) MRemapError![]align(page_size_min) u8 { + const rc = system.mremap(old_address, old_len, new_len, flags, new_address); + const err: E = if (builtin.link_libc) blk: { + if (rc != std.c.MAP_FAILED) return @as([*]align(page_size_min) u8, @ptrCast(@alignCast(rc)))[0..new_len]; + break :blk @enumFromInt(system._errno().*); + } else blk: { + const err = errno(rc); + if (err == .SUCCESS) return @as([*]align(page_size_min) u8, @ptrFromInt(rc))[0..new_len]; + break :blk err; + }; + switch (err) { + .SUCCESS => unreachable, + .AGAIN => return error.LockedMemoryLimitExceeded, + .INVAL => return error.InvalidSyscallParameters, + .NOMEM => return error.OutOfMemory, + .FAULT => unreachable, + else => return unexpectedErrno(err), + } +} + pub const MSyncError = error{ UnmappedMemory, PermissionDenied,