authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-03 21:03:27-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-06 14:23:23-08:00
log0d8166be3f7e1cc2a2200956155ed5a8792614b8
treea772fb858ab7101dd9d2ebbc244d7449b5c4b1f6
parenta4d4e086c59b702c34218105764d4ec491ecc566

std: update to new Allocator API


3 files changed, 105 insertions(+), 66 deletions(-)

lib/std/heap.zig+49-33
......@@ -147,12 +147,12 @@ const CAllocator = struct {
147147 return @as(*[*]u8, @ptrFromInt(@intFromPtr(ptr) - @sizeOf(usize)));
148148 }
149149
150 fn alignedAlloc(len: usize, log2_align: u8) ?[*]u8 {
151 const alignment = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_align));
150 fn alignedAlloc(len: usize, alignment: mem.Alignment) ?[*]u8 {
151 const alignment_bytes = alignment.toByteUnits();
152152 if (supports_posix_memalign) {
153153 // The posix_memalign only accepts alignment values that are a
154154 // multiple of the pointer size
155 const eff_alignment = @max(alignment, @sizeOf(usize));
155 const eff_alignment = @max(alignment_bytes, @sizeOf(usize));
156156
157157 var aligned_ptr: ?*anyopaque = undefined;
158158 if (c.posix_memalign(&aligned_ptr, eff_alignment, len) != 0)
......@@ -164,9 +164,9 @@ const CAllocator = struct {
164164 // Thin wrapper around regular malloc, overallocate to account for
165165 // alignment padding and store the original malloc()'ed pointer before
166166 // the aligned address.
167 const unaligned_ptr = @as([*]u8, @ptrCast(c.malloc(len + alignment - 1 + @sizeOf(usize)) orelse return null));
167 const unaligned_ptr = @as([*]u8, @ptrCast(c.malloc(len + alignment_bytes - 1 + @sizeOf(usize)) orelse return null));
168168 const unaligned_addr = @intFromPtr(unaligned_ptr);
169 const aligned_addr = mem.alignForward(usize, unaligned_addr + @sizeOf(usize), alignment);
169 const aligned_addr = mem.alignForward(usize, unaligned_addr + @sizeOf(usize), alignment_bytes);
170170 const aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr);
171171 getHeader(aligned_ptr).* = unaligned_ptr;
172172
......@@ -195,22 +195,22 @@ const CAllocator = struct {
195195 fn alloc(
196196 _: *anyopaque,
197197 len: usize,
198 log2_align: u8,
198 alignment: mem.Alignment,
199199 return_address: usize,
200200 ) ?[*]u8 {
201201 _ = return_address;
202202 assert(len > 0);
203 return alignedAlloc(len, log2_align);
203 return alignedAlloc(len, alignment);
204204 }
205205
206206 fn resize(
207207 _: *anyopaque,
208208 buf: []u8,
209 log2_buf_align: u8,
209 alignment: mem.Alignment,
210210 new_len: usize,
211211 return_address: usize,
212212 ) bool {
213 _ = log2_buf_align;
213 _ = alignment;
214214 _ = return_address;
215215 if (new_len <= buf.len) {
216216 return true;
......@@ -227,10 +227,10 @@ const CAllocator = struct {
227227 fn free(
228228 _: *anyopaque,
229229 buf: []u8,
230 log2_buf_align: u8,
230 alignment: mem.Alignment,
231231 return_address: usize,
232232 ) void {
233 _ = log2_buf_align;
233 _ = alignment;
234234 _ = return_address;
235235 alignedFree(buf.ptr);
236236 }
......@@ -267,28 +267,28 @@ const raw_c_allocator_vtable = Allocator.VTable{
267267fn rawCAlloc(
268268 _: *anyopaque,
269269 len: usize,
270 log2_ptr_align: u8,
270 alignment: mem.Alignment,
271271 ret_addr: usize,
272272) ?[*]u8 {
273273 _ = ret_addr;
274 assert(log2_ptr_align <= comptime std.math.log2_int(usize, @alignOf(std.c.max_align_t)));
274 assert(alignment.order(.le, comptime .fromByteUnits(@alignOf(std.c.max_align_t))));
275275 // Note that this pointer cannot be aligncasted to max_align_t because if
276276 // len is < max_align_t then the alignment can be smaller. For example, if
277277 // max_align_t is 16, but the user requests 8 bytes, there is no built-in
278278 // type in C that is size 8 and has 16 byte alignment, so the alignment may
279279 // be 8 bytes rather than 16. Similarly if only 1 byte is requested, malloc
280280 // is allowed to return a 1-byte aligned pointer.
281 return @as(?[*]u8, @ptrCast(c.malloc(len)));
281 return @ptrCast(c.malloc(len));
282282}
283283
284284fn rawCResize(
285285 _: *anyopaque,
286286 buf: []u8,
287 log2_old_align: u8,
287 alignment: mem.Alignment,
288288 new_len: usize,
289289 ret_addr: usize,
290290) bool {
291 _ = log2_old_align;
291 _ = alignment;
292292 _ = ret_addr;
293293
294294 if (new_len <= buf.len)
......@@ -305,10 +305,10 @@ fn rawCResize(
305305fn rawCFree(
306306 _: *anyopaque,
307307 buf: []u8,
308 log2_old_align: u8,
308 alignment: mem.Alignment,
309309 ret_addr: usize,
310310) void {
311 _ = log2_old_align;
311 _ = alignment;
312312 _ = ret_addr;
313313 c.free(buf.ptr);
314314}
......@@ -380,13 +380,13 @@ pub const HeapAllocator = switch (builtin.os.tag) {
380380 fn alloc(
381381 ctx: *anyopaque,
382382 n: usize,
383 log2_ptr_align: u8,
383 alignment: mem.Alignment,
384384 return_address: usize,
385385 ) ?[*]u8 {
386386 _ = return_address;
387387 const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
388388
389 const ptr_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_ptr_align));
389 const ptr_align = alignment.toByteUnits();
390390 const amt = n + ptr_align - 1 + @sizeOf(usize);
391391 const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, .seq_cst);
392392 const heap_handle = optional_heap_handle orelse blk: {
......@@ -407,11 +407,11 @@ pub const HeapAllocator = switch (builtin.os.tag) {
407407 fn resize(
408408 ctx: *anyopaque,
409409 buf: []u8,
410 log2_buf_align: u8,
410 alignment: mem.Alignment,
411411 new_size: usize,
412412 return_address: usize,
413413 ) bool {
414 _ = log2_buf_align;
414 _ = alignment;
415415 _ = return_address;
416416 const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
417417
......@@ -432,10 +432,10 @@ pub const HeapAllocator = switch (builtin.os.tag) {
432432 fn free(
433433 ctx: *anyopaque,
434434 buf: []u8,
435 log2_buf_align: u8,
435 alignment: mem.Alignment,
436436 return_address: usize,
437437 ) void {
438 _ = log2_buf_align;
438 _ = alignment;
439439 _ = return_address;
440440 const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
441441 windows.HeapFree(self.heap_handle.?, 0, @as(*anyopaque, @ptrFromInt(getRecordPtr(buf).*)));
......@@ -482,6 +482,7 @@ pub fn StackFallbackAllocator(comptime size: usize) type {
482482 .vtable = &.{
483483 .alloc = alloc,
484484 .resize = resize,
485 .remap = remap,
485486 .free = free,
486487 },
487488 };
......@@ -496,40 +497,55 @@ pub fn StackFallbackAllocator(comptime size: usize) type {
496497 fn alloc(
497498 ctx: *anyopaque,
498499 len: usize,
499 log2_ptr_align: u8,
500 alignment: mem.Alignment,
500501 ra: usize,
501502 ) ?[*]u8 {
502503 const self: *Self = @ptrCast(@alignCast(ctx));
503 return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, log2_ptr_align, ra) orelse
504 return self.fallback_allocator.rawAlloc(len, log2_ptr_align, ra);
504 return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, alignment, ra) orelse
505 return self.fallback_allocator.rawAlloc(len, alignment, ra);
505506 }
506507
507508 fn resize(
508509 ctx: *anyopaque,
509510 buf: []u8,
510 log2_buf_align: u8,
511 alignment: mem.Alignment,
511512 new_len: usize,
512513 ra: usize,
513514 ) bool {
514515 const self: *Self = @ptrCast(@alignCast(ctx));
515516 if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
516 return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, log2_buf_align, new_len, ra);
517 return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, alignment, new_len, ra);
517518 } else {
518 return self.fallback_allocator.rawResize(buf, log2_buf_align, new_len, ra);
519 return self.fallback_allocator.rawResize(buf, alignment, new_len, ra);
520 }
521 }
522
523 fn remap(
524 context: *anyopaque,
525 memory: []u8,
526 alignment: mem.Alignment,
527 new_len: usize,
528 return_address: usize,
529 ) ?[*]u8 {
530 const self: *Self = @ptrCast(@alignCast(context));
531 if (self.fixed_buffer_allocator.ownsPtr(memory.ptr)) {
532 return FixedBufferAllocator.remap(&self.fixed_buffer_allocator, memory, alignment, new_len, return_address);
533 } else {
534 return self.fallback_allocator.rawRemap(memory, alignment, new_len, return_address);
519535 }
520536 }
521537
522538 fn free(
523539 ctx: *anyopaque,
524540 buf: []u8,
525 log2_buf_align: u8,
541 alignment: mem.Alignment,
526542 ra: usize,
527543 ) void {
528544 const self: *Self = @ptrCast(@alignCast(ctx));
529545 if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
530 return FixedBufferAllocator.free(&self.fixed_buffer_allocator, buf, log2_buf_align, ra);
546 return FixedBufferAllocator.free(&self.fixed_buffer_allocator, buf, alignment, ra);
531547 } else {
532 return self.fallback_allocator.rawFree(buf, log2_buf_align, ra);
548 return self.fallback_allocator.rawFree(buf, alignment, ra);
533549 }
534550 }
535551 };
lib/std/heap/log_to_writer_allocator.zig+33-6
......@@ -23,6 +23,7 @@ pub fn LogToWriterAllocator(comptime Writer: type) type {
2323 .vtable = &.{
2424 .alloc = alloc,
2525 .resize = resize,
26 .remap = remap,
2627 .free = free,
2728 },
2829 };
......@@ -31,12 +32,12 @@ pub fn LogToWriterAllocator(comptime Writer: type) type {
3132 fn alloc(
3233 ctx: *anyopaque,
3334 len: usize,
34 log2_ptr_align: u8,
35 alignment: std.mem.Alignment,
3536 ra: usize,
3637 ) ?[*]u8 {
3738 const self: *Self = @ptrCast(@alignCast(ctx));
3839 self.writer.print("alloc : {}", .{len}) catch {};
39 const result = self.parent_allocator.rawAlloc(len, log2_ptr_align, ra);
40 const result = self.parent_allocator.rawAlloc(len, alignment, ra);
4041 if (result != null) {
4142 self.writer.print(" success!\n", .{}) catch {};
4243 } else {
......@@ -48,7 +49,7 @@ pub fn LogToWriterAllocator(comptime Writer: type) type {
4849 fn resize(
4950 ctx: *anyopaque,
5051 buf: []u8,
51 log2_buf_align: u8,
52 alignment: std.mem.Alignment,
5253 new_len: usize,
5354 ra: usize,
5455 ) bool {
......@@ -59,7 +60,7 @@ pub fn LogToWriterAllocator(comptime Writer: type) type {
5960 self.writer.print("expand: {} to {}", .{ buf.len, new_len }) catch {};
6061 }
6162
62 if (self.parent_allocator.rawResize(buf, log2_buf_align, new_len, ra)) {
63 if (self.parent_allocator.rawResize(buf, alignment, new_len, ra)) {
6364 if (new_len > buf.len) {
6465 self.writer.print(" success!\n", .{}) catch {};
6566 }
......@@ -71,15 +72,41 @@ pub fn LogToWriterAllocator(comptime Writer: type) type {
7172 return false;
7273 }
7374
75 fn remap(
76 ctx: *anyopaque,
77 buf: []u8,
78 alignment: std.mem.Alignment,
79 new_len: usize,
80 ra: usize,
81 ) ?[*]u8 {
82 const self: *Self = @ptrCast(@alignCast(ctx));
83 if (new_len <= buf.len) {
84 self.writer.print("shrink: {} to {}\n", .{ buf.len, new_len }) catch {};
85 } else {
86 self.writer.print("expand: {} to {}", .{ buf.len, new_len }) catch {};
87 }
88
89 if (self.parent_allocator.rawRemap(buf, alignment, new_len, ra)) |new_memory| {
90 if (new_len > buf.len) {
91 self.writer.print(" success!\n", .{}) catch {};
92 }
93 return new_memory;
94 }
95
96 std.debug.assert(new_len > buf.len);
97 self.writer.print(" failure!\n", .{}) catch {};
98 return null;
99 }
100
74101 fn free(
75102 ctx: *anyopaque,
76103 buf: []u8,
77 log2_buf_align: u8,
104 alignment: std.mem.Alignment,
78105 ra: usize,
79106 ) void {
80107 const self: *Self = @ptrCast(@alignCast(ctx));
81108 self.writer.print("free : {}\n", .{buf.len}) catch {};
82 self.parent_allocator.rawFree(buf, log2_buf_align, ra);
109 self.parent_allocator.rawFree(buf, alignment, ra);
83110 }
84111 };
85112}
lib/std/mem.zig+23-27
......@@ -92,6 +92,7 @@ pub fn ValidationAllocator(comptime T: type) type {
9292 .vtable = &.{
9393 .alloc = alloc,
9494 .resize = resize,
95 .remap = remap,
9596 .free = free,
9697 },
9798 };
......@@ -105,41 +106,54 @@ pub fn ValidationAllocator(comptime T: type) type {
105106 pub fn alloc(
106107 ctx: *anyopaque,
107108 n: usize,
108 log2_ptr_align: u8,
109 alignment: mem.Alignment,
109110 ret_addr: usize,
110111 ) ?[*]u8 {
111112 assert(n > 0);
112113 const self: *Self = @ptrCast(@alignCast(ctx));
113114 const underlying = self.getUnderlyingAllocatorPtr();
114 const result = underlying.rawAlloc(n, log2_ptr_align, ret_addr) orelse
115 const result = underlying.rawAlloc(n, alignment, ret_addr) orelse
115116 return null;
116 assert(mem.isAlignedLog2(@intFromPtr(result), log2_ptr_align));
117 assert(alignment.check(@intFromPtr(result)));
117118 return result;
118119 }
119120
120121 pub fn resize(
121122 ctx: *anyopaque,
122123 buf: []u8,
123 log2_buf_align: u8,
124 alignment: Alignment,
124125 new_len: usize,
125126 ret_addr: usize,
126127 ) bool {
127128 const self: *Self = @ptrCast(@alignCast(ctx));
128129 assert(buf.len > 0);
129130 const underlying = self.getUnderlyingAllocatorPtr();
130 return underlying.rawResize(buf, log2_buf_align, new_len, ret_addr);
131 return underlying.rawResize(buf, alignment, new_len, ret_addr);
132 }
133
134 pub fn remap(
135 ctx: *anyopaque,
136 buf: []u8,
137 alignment: Alignment,
138 new_len: usize,
139 ret_addr: usize,
140 ) ?[*]u8 {
141 const self: *Self = @ptrCast(@alignCast(ctx));
142 assert(buf.len > 0);
143 const underlying = self.getUnderlyingAllocatorPtr();
144 return underlying.rawRemap(buf, alignment, new_len, ret_addr);
131145 }
132146
133147 pub fn free(
134148 ctx: *anyopaque,
135149 buf: []u8,
136 log2_buf_align: u8,
150 alignment: Alignment,
137151 ret_addr: usize,
138152 ) void {
139153 const self: *Self = @ptrCast(@alignCast(ctx));
140154 assert(buf.len > 0);
141155 const underlying = self.getUnderlyingAllocatorPtr();
142 underlying.rawFree(buf, log2_buf_align, ret_addr);
156 underlying.rawFree(buf, alignment, ret_addr);
143157 }
144158
145159 pub fn reset(self: *Self) void {
......@@ -167,27 +181,9 @@ pub fn alignAllocLen(full_len: usize, alloc_len: usize, len_align: u29) usize {
167181 return adjusted;
168182}
169183
170const fail_allocator = Allocator{
171 .ptr = undefined,
172 .vtable = &failAllocator_vtable,
173};
174
175const failAllocator_vtable = Allocator.VTable{
176 .alloc = failAllocatorAlloc,
177 .resize = Allocator.noResize,
178 .free = Allocator.noFree,
179};
180
181fn failAllocatorAlloc(_: *anyopaque, n: usize, log2_alignment: u8, ra: usize) ?[*]u8 {
182 _ = n;
183 _ = log2_alignment;
184 _ = ra;
185 return null;
186}
187
188184test "Allocator basics" {
189 try testing.expectError(error.OutOfMemory, fail_allocator.alloc(u8, 1));
190 try testing.expectError(error.OutOfMemory, fail_allocator.allocSentinel(u8, 1, 0));
185 try testing.expectError(error.OutOfMemory, testing.failing_allocator.alloc(u8, 1));
186 try testing.expectError(error.OutOfMemory, testing.failing_allocator.allocSentinel(u8, 1, 0));
191187}
192188
193189test "Allocator.resize" {