authorgravatar for leecannon@leecannon.xyzLee Cannon <leecannon@leecannon.xyz> 2021-10-29 04:17:21+01:00
committergravatar for leecannon@leecannon.xyzLee Cannon <leecannon@leecannon.xyz> 2021-11-30 23:32:48+00:00
log9377f32c089a925d7e6f1c64c1ce7777d108213c
treeb8f42ee42e8a0825b74be70499a2569184c10c52
parent80bbf234e0d31266c72bb6e93db2d2199ac5920d
signaturelock-open Commit is signed but in an unrecognized format.

allocgate: utilize a *const vtable field


8 files changed, 90 insertions(+), 66 deletions(-)

lib/std/heap.zig+24-10
......@@ -154,8 +154,11 @@ const CAllocator = struct {
154154/// `malloc`/`free`, see `raw_c_allocator`.
155155pub const c_allocator = Allocator{
156156 .ptr = undefined,
157 .allocFn = CAllocator.alloc,
158 .resizeFn = CAllocator.resize,
157 .vtable = &c_allocator_vtable,
158};
159const c_allocator_vtable = Allocator.VTable{
160 .alloc = CAllocator.alloc,
161 .resize = CAllocator.resize,
159162};
160163
161164/// Asserts allocations are within `@alignOf(std.c.max_align_t)` and directly calls
......@@ -165,8 +168,11 @@ pub const c_allocator = Allocator{
165168/// than `c_allocator`.
166169pub const raw_c_allocator = Allocator{
167170 .ptr = undefined,
168 .allocFn = rawCAlloc,
169 .resizeFn = rawCResize,
171 .vtable = &raw_c_allocator_vtable,
172};
173const raw_c_allocator_vtable = Allocator.VTable{
174 .alloc = rawCAlloc,
175 .resize = rawCResize,
170176};
171177
172178fn rawCAlloc(
......@@ -208,16 +214,14 @@ fn rawCResize(
208214pub const page_allocator = if (builtin.target.isWasm())
209215 Allocator{
210216 .ptr = undefined,
211 .allocFn = WasmPageAllocator.alloc,
212 .resizeFn = WasmPageAllocator.resize,
217 .vtable = &WasmPageAllocator.vtable,
213218 }
214219else if (builtin.target.os.tag == .freestanding)
215220 root.os.heap.page_allocator
216221else
217222 Allocator{
218223 .ptr = undefined,
219 .allocFn = PageAllocator.alloc,
220 .resizeFn = PageAllocator.resize,
224 .vtable = &PageAllocator.vtable,
221225 };
222226
223227/// Verifies that the adjusted length will still map to the full length
......@@ -231,6 +235,11 @@ pub fn alignPageAllocLen(full_len: usize, len: usize, len_align: u29) usize {
231235pub var next_mmap_addr_hint: ?[*]align(mem.page_size) u8 = null;
232236
233237const PageAllocator = struct {
238 const vtable = Allocator.VTable{
239 .alloc = alloc,
240 .resize = resize,
241 };
242
234243 fn alloc(_: *c_void, n: usize, alignment: u29, len_align: u29, ra: usize) error{OutOfMemory}![]u8 {
235244 _ = ra;
236245 assert(n > 0);
......@@ -400,6 +409,11 @@ const WasmPageAllocator = struct {
400409 }
401410 }
402411
412 const vtable = Allocator.VTable{
413 .alloc = alloc,
414 .resize = resize,
415 };
416
403417 const PageStatus = enum(u1) {
404418 used = 0,
405419 free = 1,
......@@ -807,7 +821,7 @@ pub fn StackFallbackAllocator(comptime size: usize) type {
807821 return_address: usize,
808822 ) error{OutOfMemory}![]u8 {
809823 return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, ptr_align, len_align, return_address) catch
810 return self.fallback_allocator.allocFn(self.fallback_allocator.ptr, len, ptr_align, len_align, return_address);
824 return self.fallback_allocator.vtable.alloc(self.fallback_allocator.ptr, len, ptr_align, len_align, return_address);
811825 }
812826
813827 fn resize(
......@@ -821,7 +835,7 @@ pub fn StackFallbackAllocator(comptime size: usize) type {
821835 if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
822836 return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, buf_align, new_len, len_align, return_address);
823837 } else {
824 return self.fallback_allocator.resizeFn(self.fallback_allocator.ptr, buf, buf_align, new_len, len_align, return_address);
838 return self.fallback_allocator.vtable.resize(self.fallback_allocator.ptr, buf, buf_align, new_len, len_align, return_address);
825839 }
826840 }
827841 };
lib/std/heap/arena_allocator.zig+1-1
......@@ -47,7 +47,7 @@ pub const ArenaAllocator = struct {
4747 const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
4848 const big_enough_len = prev_len + actual_min_size;
4949 const len = big_enough_len + big_enough_len / 2;
50 const buf = try self.child_allocator.allocFn(self.child_allocator.ptr, len, @alignOf(BufNode), 1, @returnAddress());
50 const buf = try self.child_allocator.vtable.alloc(self.child_allocator.ptr, len, @alignOf(BufNode), 1, @returnAddress());
5151 const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), buf.ptr));
5252 buf_node.* = BufNode{
5353 .data = buf,
lib/std/heap/general_purpose_allocator.zig+1-1
......@@ -388,7 +388,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
388388 var it = self.large_allocations.iterator();
389389 while (it.next()) |large| {
390390 if (large.value_ptr.freed) {
391 _ = self.backing_allocator.resizeFn(self.backing_allocator.ptr, large.value_ptr.bytes, large.value_ptr.ptr_align, 0, 0, @returnAddress()) catch unreachable;
391 _ = self.backing_allocator.vtable.resize(self.backing_allocator.ptr, large.value_ptr.bytes, large.value_ptr.ptr_align, 0, 0, @returnAddress()) catch unreachable;
392392 }
393393 }
394394 }
lib/std/heap/log_to_writer_allocator.zig+2-2
......@@ -29,7 +29,7 @@ pub fn LogToWriterAllocator(comptime Writer: type) type {
2929 ra: usize,
3030 ) error{OutOfMemory}![]u8 {
3131 self.writer.print("alloc : {}", .{len}) catch {};
32 const result = self.parent_allocator.allocFn(self.parent_allocator.ptr, len, ptr_align, len_align, ra);
32 const result = self.parent_allocator.vtable.alloc(self.parent_allocator.ptr, len, ptr_align, len_align, ra);
3333 if (result) |_| {
3434 self.writer.print(" success!\n", .{}) catch {};
3535 } else |_| {
......@@ -53,7 +53,7 @@ pub fn LogToWriterAllocator(comptime Writer: type) type {
5353 } else {
5454 self.writer.print("expand: {} to {}", .{ buf.len, new_len }) catch {};
5555 }
56 if (self.parent_allocator.resizeFn(self.parent_allocator.ptr, buf, buf_align, new_len, len_align, ra)) |resized_len| {
56 if (self.parent_allocator.vtable.resize(self.parent_allocator.ptr, buf, buf_align, new_len, len_align, ra)) |resized_len| {
5757 if (new_len > buf.len) {
5858 self.writer.print(" success!\n", .{}) catch {};
5959 }
lib/std/heap/logging_allocator.zig+2-2
......@@ -53,7 +53,7 @@ pub fn ScopedLoggingAllocator(
5353 len_align: u29,
5454 ra: usize,
5555 ) error{OutOfMemory}![]u8 {
56 const result = self.parent_allocator.allocFn(self.parent_allocator.ptr, len, ptr_align, len_align, ra);
56 const result = self.parent_allocator.vtable.alloc(self.parent_allocator.ptr, len, ptr_align, len_align, ra);
5757 if (result) |_| {
5858 logHelper(
5959 success_log_level,
......@@ -78,7 +78,7 @@ pub fn ScopedLoggingAllocator(
7878 len_align: u29,
7979 ra: usize,
8080 ) error{OutOfMemory}!usize {
81 if (self.parent_allocator.resizeFn(self.parent_allocator.ptr, buf, buf_align, new_len, len_align, ra)) |resized_len| {
81 if (self.parent_allocator.vtable.resize(self.parent_allocator.ptr, buf, buf_align, new_len, len_align, ra)) |resized_len| {
8282 if (new_len == 0) {
8383 logHelper(success_log_level, "free - success - len: {}", .{buf.len});
8484 } else if (new_len <= buf.len) {
lib/std/mem.zig+11-7
......@@ -70,7 +70,7 @@ pub fn ValidationAllocator(comptime T: type) type {
7070 }
7171
7272 const underlying = self.getUnderlyingAllocatorPtr();
73 const result = try underlying.allocFn(underlying.ptr, n, ptr_align, len_align, ret_addr);
73 const result = try underlying.vtable.alloc(underlying.ptr, n, ptr_align, len_align, ret_addr);
7474 assert(mem.isAligned(@ptrToInt(result.ptr), ptr_align));
7575 if (len_align == 0) {
7676 assert(result.len == n);
......@@ -95,7 +95,7 @@ pub fn ValidationAllocator(comptime T: type) type {
9595 assert(new_len >= len_align);
9696 }
9797 const underlying = self.getUnderlyingAllocatorPtr();
98 const result = try underlying.resizeFn(underlying.ptr, buf, buf_align, new_len, len_align, ret_addr);
98 const result = try underlying.vtable.resize(underlying.ptr, buf, buf_align, new_len, len_align, ret_addr);
9999 if (len_align == 0) {
100100 assert(result == new_len);
101101 } else {
......@@ -131,10 +131,14 @@ pub fn alignAllocLen(full_len: usize, alloc_len: usize, len_align: u29) usize {
131131 return adjusted;
132132}
133133
134const failAllocator = Allocator{
134const fail_allocator = Allocator{
135135 .ptr = undefined,
136 .allocFn = failAllocatorAlloc,
137 .resizeFn = Allocator.NoResize(c_void).noResize,
136 .vtable = &failAllocator_vtable,
137};
138
139const failAllocator_vtable = Allocator.VTable{
140 .alloc = failAllocatorAlloc,
141 .resize = Allocator.NoResize(c_void).noResize,
138142};
139143
140144fn failAllocatorAlloc(_: *c_void, n: usize, alignment: u29, len_align: u29, ra: usize) Allocator.Error![]u8 {
......@@ -146,8 +150,8 @@ fn failAllocatorAlloc(_: *c_void, n: usize, alignment: u29, len_align: u29, ra:
146150}
147151
148152test "mem.Allocator basics" {
149 try testing.expectError(error.OutOfMemory, failAllocator.alloc(u8, 1));
150 try testing.expectError(error.OutOfMemory, failAllocator.allocSentinel(u8, 1, 0));
153 try testing.expectError(error.OutOfMemory, fail_allocator.alloc(u8, 1));
154 try testing.expectError(error.OutOfMemory, fail_allocator.allocSentinel(u8, 1, 0));
151155}
152156
153157test "Allocator.resize" {
lib/std/mem/Allocator.zig+47-41
......@@ -10,39 +10,42 @@ pub const Error = error{OutOfMemory};
1010
1111// The type erased pointer to the allocator implementation
1212ptr: *c_void,
13
14/// Attempt to allocate at least `len` bytes aligned to `ptr_align`.
15///
16/// If `len_align` is `0`, then the length returned MUST be exactly `len` bytes,
17/// otherwise, the length must be aligned to `len_align`.
18///
19/// `len` must be greater than or equal to `len_align` and must be aligned by `len_align`.
20///
21/// `ret_addr` is optionally provided as the first return address of the allocation call stack.
22/// If the value is `0` it means no return address has been provided.
23allocFn: fn (ptr: *c_void, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8,
24
25/// Attempt to expand or shrink memory in place. `buf.len` must equal the most recent
26/// length returned by `allocFn` or `resizeFn`. `buf_align` must equal the same value
27/// that was passed as the `ptr_align` parameter to the original `allocFn` call.
28///
29/// Passing a `new_len` of 0 frees and invalidates the buffer such that it can no
30/// longer be passed to `resizeFn`.
31///
32/// error.OutOfMemory can only be returned if `new_len` is greater than `buf.len`.
33/// If `buf` cannot be expanded to accomodate `new_len`, then the allocation MUST be
34/// unmodified and error.OutOfMemory MUST be returned.
35///
36/// If `len_align` is `0`, then the length returned MUST be exactly `len` bytes,
37/// otherwise, the length must be aligned to `len_align`. Note that `len_align` does *not*
38/// provide a way to modify the alignment of a pointer. Rather it provides an API for
39/// accepting more bytes of memory from the allocator than requested.
40///
41/// `new_len` must be greater than or equal to `len_align` and must be aligned by `len_align`.
42///
43/// `ret_addr` is optionally provided as the first return address of the allocation call stack.
44/// If the value is `0` it means no return address has been provided.
45resizeFn: fn (ptr: *c_void, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) Error!usize,
13vtable: *const VTable,
14
15pub const VTable = struct {
16 /// Attempt to allocate at least `len` bytes aligned to `ptr_align`.
17 ///
18 /// If `len_align` is `0`, then the length returned MUST be exactly `len` bytes,
19 /// otherwise, the length must be aligned to `len_align`.
20 ///
21 /// `len` must be greater than or equal to `len_align` and must be aligned by `len_align`.
22 ///
23 /// `ret_addr` is optionally provided as the first return address of the allocation call stack.
24 /// If the value is `0` it means no return address has been provided.
25 alloc: fn (ptr: *c_void, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8,
26
27 /// Attempt to expand or shrink memory in place. `buf.len` must equal the most recent
28 /// length returned by `alloc` or `resize`. `buf_align` must equal the same value
29 /// that was passed as the `ptr_align` parameter to the original `alloc` call.
30 ///
31 /// Passing a `new_len` of 0 frees and invalidates the buffer such that it can no
32 /// longer be passed to `resize`.
33 ///
34 /// error.OutOfMemory can only be returned if `new_len` is greater than `buf.len`.
35 /// If `buf` cannot be expanded to accomodate `new_len`, then the allocation MUST be
36 /// unmodified and error.OutOfMemory MUST be returned.
37 ///
38 /// If `len_align` is `0`, then the length returned MUST be exactly `len` bytes,
39 /// otherwise, the length must be aligned to `len_align`. Note that `len_align` does *not*
40 /// provide a way to modify the alignment of a pointer. Rather it provides an API for
41 /// accepting more bytes of memory from the allocator than requested.
42 ///
43 /// `new_len` must be greater than or equal to `len_align` and must be aligned by `len_align`.
44 ///
45 /// `ret_addr` is optionally provided as the first return address of the allocation call stack.
46 /// If the value is `0` it means no return address has been provided.
47 resize: fn (ptr: *c_void, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) Error!usize,
48};
4649
4750pub fn init(
4851 pointer: anytype,
......@@ -64,11 +67,14 @@ pub fn init(
6467 return resizeFn(self, buf, buf_align, new_len, len_align, ret_addr);
6568 }
6669 };
70 const vtable = VTable{
71 .alloc = gen.alloc,
72 .resize = gen.resize,
73 };
6774
6875 return .{
6976 .ptr = pointer,
70 .allocFn = gen.alloc,
71 .resizeFn = gen.resize,
77 .vtable = &vtable,
7278 };
7379}
7480
......@@ -141,7 +147,7 @@ fn reallocBytes(
141147 return_address: usize,
142148) Error![]u8 {
143149 if (old_mem.len == 0) {
144 const new_mem = try self.allocFn(self.ptr, new_byte_count, new_alignment, len_align, return_address);
150 const new_mem = try self.vtable.alloc(self.ptr, new_byte_count, new_alignment, len_align, return_address);
145151 // TODO: https://github.com/ziglang/zig/issues/4298
146152 @memset(new_mem.ptr, undefined, new_byte_count);
147153 return new_mem;
......@@ -152,7 +158,7 @@ fn reallocBytes(
152158 const shrunk_len = self.shrinkBytes(old_mem, old_alignment, new_byte_count, len_align, return_address);
153159 return old_mem.ptr[0..shrunk_len];
154160 }
155 if (self.resizeFn(self.ptr, old_mem, old_alignment, new_byte_count, len_align, return_address)) |resized_len| {
161 if (self.vtable.resize(self.ptr, old_mem, old_alignment, new_byte_count, len_align, return_address)) |resized_len| {
156162 assert(resized_len >= new_byte_count);
157163 // TODO: https://github.com/ziglang/zig/issues/4298
158164 @memset(old_mem.ptr + new_byte_count, undefined, resized_len - new_byte_count);
......@@ -178,7 +184,7 @@ fn moveBytes(
178184) Error![]u8 {
179185 assert(old_mem.len > 0);
180186 assert(new_len > 0);
181 const new_mem = try self.allocFn(self.ptr, new_len, new_alignment, len_align, return_address);
187 const new_mem = try self.vtable.alloc(self.ptr, new_len, new_alignment, len_align, return_address);
182188 @memcpy(new_mem.ptr, old_mem.ptr, math.min(new_len, old_mem.len));
183189 // TODO https://github.com/ziglang/zig/issues/4298
184190 @memset(old_mem.ptr, undefined, old_mem.len);
......@@ -320,7 +326,7 @@ pub fn allocAdvancedWithRetAddr(
320326 .exact => 0,
321327 .at_least => size_of_T,
322328 };
323 const byte_slice = try self.allocFn(self.ptr, byte_count, a, len_align, return_address);
329 const byte_slice = try self.vtable.alloc(self.ptr, byte_count, a, len_align, return_address);
324330 switch (exact) {
325331 .exact => assert(byte_slice.len == byte_count),
326332 .at_least => assert(byte_slice.len >= byte_count),
......@@ -345,7 +351,7 @@ pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) Error!@TypeOf(old
345351 }
346352 const old_byte_slice = mem.sliceAsBytes(old_mem);
347353 const new_byte_count = math.mul(usize, @sizeOf(T), new_n) catch return Error.OutOfMemory;
348 const rc = try self.resizeFn(self.ptr, old_byte_slice, Slice.alignment, new_byte_count, 0, @returnAddress());
354 const rc = try self.vtable.resize(self.ptr, old_byte_slice, Slice.alignment, new_byte_count, 0, @returnAddress());
349355 assert(rc == new_byte_count);
350356 const new_byte_slice = old_byte_slice.ptr[0..new_byte_count];
351357 return mem.bytesAsSlice(T, new_byte_slice);
......@@ -514,5 +520,5 @@ pub fn shrinkBytes(
514520 return_address: usize,
515521) usize {
516522 assert(new_len <= buf.len);
517 return self.resizeFn(self.ptr, buf, buf_align, new_len, len_align, return_address) catch unreachable;
523 return self.vtable.resize(self.ptr, buf, buf_align, new_len, len_align, return_address) catch unreachable;
518524}
lib/std/testing/failing_allocator.zig+2-2
......@@ -54,7 +54,7 @@ pub const FailingAllocator = struct {
5454 if (self.index == self.fail_index) {
5555 return error.OutOfMemory;
5656 }
57 const result = try self.internal_allocator.allocFn(self.internal_allocator.ptr, len, ptr_align, len_align, return_address);
57 const result = try self.internal_allocator.vtable.alloc(self.internal_allocator.ptr, len, ptr_align, len_align, return_address);
5858 self.allocated_bytes += result.len;
5959 self.allocations += 1;
6060 self.index += 1;
......@@ -69,7 +69,7 @@ pub const FailingAllocator = struct {
6969 len_align: u29,
7070 ra: usize,
7171 ) error{OutOfMemory}!usize {
72 const r = self.internal_allocator.resizeFn(self.internal_allocator.ptr, old_mem, old_align, new_len, len_align, ra) catch |e| {
72 const r = self.internal_allocator.vtable.resize(self.internal_allocator.ptr, old_mem, old_align, new_len, len_align, ra) catch |e| {
7373 std.debug.assert(new_len > old_mem.len);
7474 return e;
7575 };