| ... | ... | @@ -363,127 +363,6 @@ pub const wasm_allocator: Allocator = .{ |
| 363 | 363 | .vtable = &WasmAllocator.vtable, |
| 364 | 364 | }; |
| 365 | 365 | |
| 366 | | pub 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 | 366 | /// Returns a `StackFallbackAllocator` allocating using either a |
| 488 | 367 | /// `FixedBufferAllocator` on an array of size `size` and falling back to |
| 489 | 368 | /// `fallback_allocator` if that fails. |
| ... | ... | @@ -628,22 +507,6 @@ test PageAllocator { |
| 628 | 507 | } |
| 629 | 508 | } |
| 630 | 509 | |
| 631 | | test 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 | | |
| 647 | 510 | test ArenaAllocator { |
| 648 | 511 | var arena_allocator = ArenaAllocator.init(page_allocator); |
| 649 | 512 | defer arena_allocator.deinit(); |