authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-05 18:03:14-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-06 14:23:23-08:00
log5e9b8c38d360a254bf951674f4b39ea7a602c515
tree616cbec186d110af2a8f4e1250725764afb40eba
parentf82ec3f02af68ca25870f8ae3861a416225af554

std.heap: remove HeapAllocator

Windows-only, depends on kernel32 in violation of zig std lib policy, and redundant with other cross-platform APIs that perform the same functionality.

3 files changed, 0 insertions(+), 158 deletions(-)

lib/std/heap.zig-137
...@@ -363,127 +363,6 @@ pub const wasm_allocator: Allocator = .{...@@ -363,127 +363,6 @@ pub const wasm_allocator: Allocator = .{
363 .vtable = &WasmAllocator.vtable,363 .vtable = &WasmAllocator.vtable,
364};364};
365365
366pub const HeapAllocator = switch (builtin.os.tag) {
367 .windows => struct {
368 heap_handle: ?HeapHandle,
369
370 const HeapHandle = windows.HANDLE;
371
372 pub fn init() HeapAllocator {
373 return HeapAllocator{
374 .heap_handle = null,
375 };
376 }
377
378 pub fn allocator(self: *HeapAllocator) Allocator {
379 return .{
380 .ptr = self,
381 .vtable = &.{
382 .alloc = alloc,
383 .resize = resize,
384 .remap = remap,
385 .free = free,
386 },
387 };
388 }
389
390 pub fn deinit(self: *HeapAllocator) void {
391 if (self.heap_handle) |heap_handle| {
392 windows.HeapDestroy(heap_handle);
393 }
394 }
395
396 fn getRecordPtr(buf: []u8) *align(1) usize {
397 return @as(*align(1) usize, @ptrFromInt(@intFromPtr(buf.ptr) + buf.len));
398 }
399
400 fn alloc(
401 ctx: *anyopaque,
402 n: usize,
403 alignment: mem.Alignment,
404 return_address: usize,
405 ) ?[*]u8 {
406 _ = return_address;
407 const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
408
409 const ptr_align = alignment.toByteUnits();
410 const amt = n + ptr_align - 1 + @sizeOf(usize);
411 const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, .seq_cst);
412 const heap_handle = optional_heap_handle orelse blk: {
413 const options = if (builtin.single_threaded) windows.HEAP_NO_SERIALIZE else 0;
414 const hh = windows.kernel32.HeapCreate(options, amt, 0) orelse return null;
415 const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, .seq_cst, .seq_cst) orelse break :blk hh;
416 windows.HeapDestroy(hh);
417 break :blk other_hh.?; // can't be null because of the cmpxchg
418 };
419 const ptr = windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return null;
420 const root_addr = @intFromPtr(ptr);
421 const aligned_addr = mem.alignForward(usize, root_addr, ptr_align);
422 const buf = @as([*]u8, @ptrFromInt(aligned_addr))[0..n];
423 getRecordPtr(buf).* = root_addr;
424 return buf.ptr;
425 }
426
427 fn resize(
428 ctx: *anyopaque,
429 buf: []u8,
430 alignment: mem.Alignment,
431 new_size: usize,
432 return_address: usize,
433 ) bool {
434 _ = alignment;
435 _ = return_address;
436 const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
437
438 const root_addr = getRecordPtr(buf).*;
439 const align_offset = @intFromPtr(buf.ptr) - root_addr;
440 const amt = align_offset + new_size + @sizeOf(usize);
441 const new_ptr = windows.kernel32.HeapReAlloc(
442 self.heap_handle.?,
443 windows.HEAP_REALLOC_IN_PLACE_ONLY,
444 @as(*anyopaque, @ptrFromInt(root_addr)),
445 amt,
446 ) orelse return false;
447 assert(new_ptr == @as(*anyopaque, @ptrFromInt(root_addr)));
448 getRecordPtr(buf.ptr[0..new_size]).* = root_addr;
449 return true;
450 }
451
452 fn remap(
453 ctx: *anyopaque,
454 buf: []u8,
455 alignment: mem.Alignment,
456 new_size: usize,
457 return_address: usize,
458 ) ?[*]u8 {
459 _ = alignment;
460 _ = return_address;
461 const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
462
463 const root_addr = getRecordPtr(buf).*;
464 const align_offset = @intFromPtr(buf.ptr) - root_addr;
465 const amt = align_offset + new_size + @sizeOf(usize);
466 const new_ptr = windows.kernel32.HeapReAlloc(self.heap_handle.?, 0, @ptrFromInt(root_addr), amt) orelse return null;
467 assert(new_ptr == @as(*anyopaque, @ptrFromInt(root_addr)));
468 getRecordPtr(buf.ptr[0..new_size]).* = root_addr;
469 return @ptrCast(new_ptr);
470 }
471
472 fn free(
473 ctx: *anyopaque,
474 buf: []u8,
475 alignment: mem.Alignment,
476 return_address: usize,
477 ) void {
478 _ = alignment;
479 _ = return_address;
480 const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
481 windows.HeapFree(self.heap_handle.?, 0, @as(*anyopaque, @ptrFromInt(getRecordPtr(buf).*)));
482 }
483 },
484 else => @compileError("Unsupported OS"),
485};
486
487/// Returns a `StackFallbackAllocator` allocating using either a366/// Returns a `StackFallbackAllocator` allocating using either a
488/// `FixedBufferAllocator` on an array of size `size` and falling back to367/// `FixedBufferAllocator` on an array of size `size` and falling back to
489/// `fallback_allocator` if that fails.368/// `fallback_allocator` if that fails.
...@@ -628,22 +507,6 @@ test PageAllocator {...@@ -628,22 +507,6 @@ test PageAllocator {
628 }507 }
629}508}
630509
631test HeapAllocator {
632 if (builtin.os.tag == .windows) {
633 // https://github.com/ziglang/zig/issues/13702
634 if (builtin.cpu.arch == .aarch64) return error.SkipZigTest;
635
636 var heap_allocator = HeapAllocator.init();
637 defer heap_allocator.deinit();
638 const allocator = heap_allocator.allocator();
639
640 try testAllocator(allocator);
641 try testAllocatorAligned(allocator);
642 try testAllocatorLargeAlignment(allocator);
643 try testAllocatorAlignedShrink(allocator);
644 }
645}
646
647test ArenaAllocator {510test ArenaAllocator {
648 var arena_allocator = ArenaAllocator.init(page_allocator);511 var arena_allocator = ArenaAllocator.init(page_allocator);
649 defer arena_allocator.deinit();512 defer arena_allocator.deinit();
lib/std/os/windows.zig-12
...@@ -2016,18 +2016,6 @@ pub fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter...@@ -2016,18 +2016,6 @@ pub fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter
2016 assert(kernel32.InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) != 0);2016 assert(kernel32.InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) != 0);
2017}2017}
20182018
2019pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *anyopaque) void {
2020 assert(kernel32.HeapFree(hHeap, dwFlags, lpMem) != 0);
2021}
2022
2023pub fn HeapDestroy(hHeap: HANDLE) void {
2024 assert(kernel32.HeapDestroy(hHeap) != 0);
2025}
2026
2027pub fn LocalFree(hMem: HLOCAL) void {
2028 assert(kernel32.LocalFree(hMem) == null);
2029}
2030
2031pub const SetFileTimeError = error{Unexpected};2019pub const SetFileTimeError = error{Unexpected};
20322020
2033pub fn SetFileTime(2021pub fn SetFileTime(
lib/std/os/windows/kernel32.zig-9
...@@ -528,11 +528,6 @@ pub extern "kernel32" fn HeapCreate(...@@ -528,11 +528,6 @@ pub extern "kernel32" fn HeapCreate(
528 dwMaximumSize: SIZE_T,528 dwMaximumSize: SIZE_T,
529) callconv(.winapi) ?HANDLE;529) callconv(.winapi) ?HANDLE;
530530
531// TODO: Wrapper around RtlDestroyHeap (BOOLEAN -> BOOL).
532pub extern "kernel32" fn HeapDestroy(
533 hHeap: HANDLE,
534) callconv(.winapi) BOOL;
535
536// TODO: Forwarder to RtlReAllocateHeap.531// TODO: Forwarder to RtlReAllocateHeap.
537pub extern "kernel32" fn HeapReAlloc(532pub extern "kernel32" fn HeapReAlloc(
538 hHeap: HANDLE,533 hHeap: HANDLE,
...@@ -585,10 +580,6 @@ pub extern "kernel32" fn VirtualQuery(...@@ -585,10 +580,6 @@ pub extern "kernel32" fn VirtualQuery(
585 dwLength: SIZE_T,580 dwLength: SIZE_T,
586) callconv(.winapi) SIZE_T;581) callconv(.winapi) SIZE_T;
587582
588pub extern "kernel32" fn LocalFree(
589 hMem: HLOCAL,
590) callconv(.winapi) ?HLOCAL;
591
592// TODO: Getter for peb.ProcessHeap583// TODO: Getter for peb.ProcessHeap
593pub extern "kernel32" fn GetProcessHeap() callconv(.winapi) ?HANDLE;584pub extern "kernel32" fn GetProcessHeap() callconv(.winapi) ?HANDLE;
594585