| author | |
| committer | |
| log | 066eaa5e9cbfde172449f6d95bb884c7d86ac10c |
| tree | 7829767fd8b421f6a1c58798692f45ebec43746d |
| parent | f68cda738ad0d3e9bc0f328befad301d9e23756e |
| signature |
15 files changed, 112 insertions(+), 196 deletions(-)
lib/std/build/OptionsStep.zig+1-1| ... | ... | @@ -350,5 +350,5 @@ test "OptionsStep" { |
| 350 | 350 | \\ |
| 351 | 351 | , options.contents.items); |
| 352 | 352 | |
| 353 | _ = try std.zig.parse(&arena.allocator, try options.contents.toOwnedSliceSentinel(0)); | |
| 353 | _ = try std.zig.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(0)); | |
| 354 | 354 | } |
lib/std/heap.zig+16-18| ... | ... | @@ -129,7 +129,7 @@ const CAllocator = struct { |
| 129 | 129 | new_len: usize, |
| 130 | 130 | len_align: u29, |
| 131 | 131 | return_address: usize, |
| 132 | ) Allocator.Error!usize { | |
| 132 | ) ?usize { | |
| 133 | 133 | _ = buf_align; |
| 134 | 134 | _ = return_address; |
| 135 | 135 | if (new_len <= buf.len) { |
| ... | ... | @@ -141,7 +141,7 @@ const CAllocator = struct { |
| 141 | 141 | return mem.alignAllocLen(full_len, new_len, len_align); |
| 142 | 142 | } |
| 143 | 143 | } |
| 144 | return error.OutOfMemory; | |
| 144 | return null; | |
| 145 | 145 | } |
| 146 | 146 | |
| 147 | 147 | fn free( |
| ... | ... | @@ -205,13 +205,13 @@ fn rawCResize( |
| 205 | 205 | new_len: usize, |
| 206 | 206 | len_align: u29, |
| 207 | 207 | ret_addr: usize, |
| 208 | ) Allocator.Error!usize { | |
| 208 | ) ?usize { | |
| 209 | 209 | _ = old_align; |
| 210 | 210 | _ = ret_addr; |
| 211 | 211 | if (new_len <= buf.len) { |
| 212 | 212 | return mem.alignAllocLen(buf.len, new_len, len_align); |
| 213 | 213 | } |
| 214 | return error.OutOfMemory; | |
| 214 | return null; | |
| 215 | 215 | } |
| 216 | 216 | |
| 217 | 217 | fn rawCFree( |
| ... | ... | @@ -361,7 +361,7 @@ const PageAllocator = struct { |
| 361 | 361 | new_size: usize, |
| 362 | 362 | len_align: u29, |
| 363 | 363 | return_address: usize, |
| 364 | ) Allocator.Error!usize { | |
| 364 | ) ?usize { | |
| 365 | 365 | _ = buf_align; |
| 366 | 366 | _ = return_address; |
| 367 | 367 | const new_size_aligned = mem.alignForward(new_size, mem.page_size); |
| ... | ... | @@ -387,7 +387,7 @@ const PageAllocator = struct { |
| 387 | 387 | if (new_size_aligned <= old_size_aligned) { |
| 388 | 388 | return alignPageAllocLen(new_size_aligned, new_size, len_align); |
| 389 | 389 | } |
| 390 | return error.OutOfMemory; | |
| 390 | return null; | |
| 391 | 391 | } |
| 392 | 392 | |
| 393 | 393 | const buf_aligned_len = mem.alignForward(buf_unaligned.len, mem.page_size); |
| ... | ... | @@ -403,7 +403,7 @@ const PageAllocator = struct { |
| 403 | 403 | |
| 404 | 404 | // TODO: call mremap |
| 405 | 405 | // TODO: if the next_mmap_addr_hint is within the remapped range, update it |
| 406 | return error.OutOfMemory; | |
| 406 | return null; | |
| 407 | 407 | } |
| 408 | 408 | |
| 409 | 409 | fn free(_: *c_void, buf_unaligned: []u8, buf_align: u29, return_address: usize) void { |
| ... | ... | @@ -579,11 +579,11 @@ const WasmPageAllocator = struct { |
| 579 | 579 | new_len: usize, |
| 580 | 580 | len_align: u29, |
| 581 | 581 | return_address: usize, |
| 582 | ) error{OutOfMemory}!usize { | |
| 582 | ) ?usize { | |
| 583 | 583 | _ = buf_align; |
| 584 | 584 | _ = return_address; |
| 585 | 585 | const aligned_len = mem.alignForward(buf.len, mem.page_size); |
| 586 | if (new_len > aligned_len) return error.OutOfMemory; | |
| 586 | if (new_len > aligned_len) return null; | |
| 587 | 587 | const current_n = nPages(aligned_len); |
| 588 | 588 | const new_n = nPages(new_len); |
| 589 | 589 | if (new_n != current_n) { |
| ... | ... | @@ -674,7 +674,7 @@ pub const HeapAllocator = switch (builtin.os.tag) { |
| 674 | 674 | new_size: usize, |
| 675 | 675 | len_align: u29, |
| 676 | 676 | return_address: usize, |
| 677 | ) error{OutOfMemory}!usize { | |
| 677 | ) ?usize { | |
| 678 | 678 | _ = buf_align; |
| 679 | 679 | _ = return_address; |
| 680 | 680 | |
| ... | ... | @@ -686,7 +686,7 @@ pub const HeapAllocator = switch (builtin.os.tag) { |
| 686 | 686 | os.windows.HEAP_REALLOC_IN_PLACE_ONLY, |
| 687 | 687 | @intToPtr(*c_void, root_addr), |
| 688 | 688 | amt, |
| 689 | ) orelse return error.OutOfMemory; | |
| 689 | ) orelse return null; | |
| 690 | 690 | assert(new_ptr == @intToPtr(*c_void, root_addr)); |
| 691 | 691 | const return_len = init: { |
| 692 | 692 | if (len_align == 0) break :init new_size; |
| ... | ... | @@ -788,14 +788,13 @@ pub const FixedBufferAllocator = struct { |
| 788 | 788 | new_size: usize, |
| 789 | 789 | len_align: u29, |
| 790 | 790 | return_address: usize, |
| 791 | ) Allocator.Error!usize { | |
| 791 | ) ?usize { | |
| 792 | 792 | _ = buf_align; |
| 793 | 793 | _ = return_address; |
| 794 | 794 | assert(self.ownsSlice(buf)); // sanity check |
| 795 | 795 | |
| 796 | 796 | if (!self.isLastAllocation(buf)) { |
| 797 | if (new_size > buf.len) | |
| 798 | return error.OutOfMemory; | |
| 797 | if (new_size > buf.len) return null; | |
| 799 | 798 | return mem.alignAllocLen(buf.len, new_size, len_align); |
| 800 | 799 | } |
| 801 | 800 | |
| ... | ... | @@ -806,9 +805,8 @@ pub const FixedBufferAllocator = struct { |
| 806 | 805 | } |
| 807 | 806 | |
| 808 | 807 | const add = new_size - buf.len; |
| 809 | if (add + self.end_index > self.buffer.len) { | |
| 810 | return error.OutOfMemory; | |
| 811 | } | |
| 808 | if (add + self.end_index > self.buffer.len) return null; | |
| 809 | ||
| 812 | 810 | self.end_index += add; |
| 813 | 811 | return new_size; |
| 814 | 812 | } |
| ... | ... | @@ -891,7 +889,7 @@ pub fn StackFallbackAllocator(comptime size: usize) type { |
| 891 | 889 | new_len: usize, |
| 892 | 890 | len_align: u29, |
| 893 | 891 | return_address: usize, |
| 894 | ) error{OutOfMemory}!usize { | |
| 892 | ) ?usize { | |
| 895 | 893 | if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) { |
| 896 | 894 | return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, buf_align, new_len, len_align, return_address); |
| 897 | 895 | } else { |
lib/std/heap/arena_allocator.zig+8-11| ... | ... | @@ -78,26 +78,23 @@ pub const ArenaAllocator = struct { |
| 78 | 78 | |
| 79 | 79 | const bigger_buf_size = @sizeOf(BufNode) + new_end_index; |
| 80 | 80 | // Try to grow the buffer in-place |
| 81 | cur_node.data = self.child_allocator.resize(cur_node.data, bigger_buf_size) catch |err| switch (err) { | |
| 82 | error.OutOfMemory => { | |
| 83 | // Allocate a new node if that's not possible | |
| 84 | cur_node = try self.createNode(cur_buf.len, n + ptr_align); | |
| 85 | continue; | |
| 86 | }, | |
| 81 | cur_node.data = self.child_allocator.resize(cur_node.data, bigger_buf_size) orelse { | |
| 82 | // Allocate a new node if that's not possible | |
| 83 | cur_node = try self.createNode(cur_buf.len, n + ptr_align); | |
| 84 | continue; | |
| 87 | 85 | }; |
| 88 | 86 | } |
| 89 | 87 | } |
| 90 | 88 | |
| 91 | fn resize(self: *ArenaAllocator, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) Allocator.Error!usize { | |
| 89 | fn resize(self: *ArenaAllocator, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize { | |
| 92 | 90 | _ = buf_align; |
| 93 | 91 | _ = len_align; |
| 94 | 92 | _ = ret_addr; |
| 95 | 93 | |
| 96 | const cur_node = self.state.buffer_list.first orelse return error.OutOfMemory; | |
| 94 | const cur_node = self.state.buffer_list.first orelse return null; | |
| 97 | 95 | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; |
| 98 | 96 | if (@ptrToInt(cur_buf.ptr) + self.state.end_index != @ptrToInt(buf.ptr) + buf.len) { |
| 99 | if (new_len > buf.len) | |
| 100 | return error.OutOfMemory; | |
| 97 | if (new_len > buf.len) return null; | |
| 101 | 98 | return new_len; |
| 102 | 99 | } |
| 103 | 100 | |
| ... | ... | @@ -108,7 +105,7 @@ pub const ArenaAllocator = struct { |
| 108 | 105 | self.state.end_index += new_len - buf.len; |
| 109 | 106 | return new_len; |
| 110 | 107 | } else { |
| 111 | return error.OutOfMemory; | |
| 108 | return null; | |
| 112 | 109 | } |
| 113 | 110 | } |
| 114 | 111 |
lib/std/heap/general_purpose_allocator.zig+10-10| ... | ... | @@ -517,7 +517,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 517 | 517 | new_size: usize, |
| 518 | 518 | len_align: u29, |
| 519 | 519 | ret_addr: usize, |
| 520 | ) Error!usize { | |
| 520 | ) ?usize { | |
| 521 | 521 | const entry = self.large_allocations.getEntry(@ptrToInt(old_mem.ptr)) orelse { |
| 522 | 522 | if (config.safety) { |
| 523 | 523 | @panic("Invalid free"); |
| ... | ... | @@ -557,7 +557,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 557 | 557 | if (config.enable_memory_limit) { |
| 558 | 558 | const new_req_bytes = prev_req_bytes + new_size - entry.value_ptr.requested_size; |
| 559 | 559 | if (new_req_bytes > prev_req_bytes and new_req_bytes > self.requested_memory_limit) { |
| 560 | return error.OutOfMemory; | |
| 560 | return null; | |
| 561 | 561 | } |
| 562 | 562 | self.total_requested_bytes = new_req_bytes; |
| 563 | 563 | } |
| ... | ... | @@ -565,7 +565,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 565 | 565 | self.total_requested_bytes = prev_req_bytes; |
| 566 | 566 | }; |
| 567 | 567 | |
| 568 | const result_len = try self.backing_allocator.rawResize(old_mem, old_align, new_size, len_align, ret_addr); | |
| 568 | const result_len = self.backing_allocator.rawResize(old_mem, old_align, new_size, len_align, ret_addr) orelse return null; | |
| 569 | 569 | |
| 570 | 570 | if (config.enable_memory_limit) { |
| 571 | 571 | entry.value_ptr.requested_size = new_size; |
| ... | ... | @@ -650,7 +650,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 650 | 650 | new_size: usize, |
| 651 | 651 | len_align: u29, |
| 652 | 652 | ret_addr: usize, |
| 653 | ) Error!usize { | |
| 653 | ) ?usize { | |
| 654 | 654 | self.mutex.lock(); |
| 655 | 655 | defer self.mutex.unlock(); |
| 656 | 656 | |
| ... | ... | @@ -705,7 +705,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 705 | 705 | if (config.enable_memory_limit) { |
| 706 | 706 | const new_req_bytes = prev_req_bytes + new_size - old_mem.len; |
| 707 | 707 | if (new_req_bytes > prev_req_bytes and new_req_bytes > self.requested_memory_limit) { |
| 708 | return error.OutOfMemory; | |
| 708 | return null; | |
| 709 | 709 | } |
| 710 | 710 | self.total_requested_bytes = new_req_bytes; |
| 711 | 711 | } |
| ... | ... | @@ -726,7 +726,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 726 | 726 | } |
| 727 | 727 | return new_size; |
| 728 | 728 | } |
| 729 | return error.OutOfMemory; | |
| 729 | return null; | |
| 730 | 730 | } |
| 731 | 731 | |
| 732 | 732 | fn free( |
| ... | ... | @@ -735,8 +735,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 735 | 735 | old_align: u29, |
| 736 | 736 | ret_addr: usize, |
| 737 | 737 | ) void { |
| 738 | const held = self.mutex.acquire(); | |
| 739 | defer held.release(); | |
| 738 | self.mutex.lock(); | |
| 739 | defer self.mutex.unlock(); | |
| 740 | 740 | |
| 741 | 741 | assert(old_mem.len != 0); |
| 742 | 742 | |
| ... | ... | @@ -850,7 +850,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 850 | 850 | return true; |
| 851 | 851 | } |
| 852 | 852 | |
| 853 | fn alloc(self: Allocator, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 { | |
| 853 | fn alloc(self: *Self, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 { | |
| 854 | 854 | self.mutex.lock(); |
| 855 | 855 | defer self.mutex.unlock(); |
| 856 | 856 | |
| ... | ... | @@ -1065,7 +1065,7 @@ test "shrink large object to large object" { |
| 1065 | 1065 | slice[0] = 0x12; |
| 1066 | 1066 | slice[60] = 0x34; |
| 1067 | 1067 | |
| 1068 | slice = try allocator.resize(slice, page_size * 2 + 1); | |
| 1068 | slice = allocator.resize(slice, page_size * 2 + 1) orelse return; | |
| 1069 | 1069 | try std.testing.expect(slice[0] == 0x12); |
| 1070 | 1070 | try std.testing.expect(slice[60] == 0x34); |
| 1071 | 1071 |
lib/std/heap/log_to_writer_allocator.zig+7-6| ... | ... | @@ -45,22 +45,23 @@ pub fn LogToWriterAllocator(comptime Writer: type) type { |
| 45 | 45 | new_len: usize, |
| 46 | 46 | len_align: u29, |
| 47 | 47 | ra: usize, |
| 48 | ) error{OutOfMemory}!usize { | |
| 48 | ) ?usize { | |
| 49 | 49 | if (new_len <= buf.len) { |
| 50 | 50 | self.writer.print("shrink: {} to {}\n", .{ buf.len, new_len }) catch {}; |
| 51 | 51 | } else { |
| 52 | 52 | self.writer.print("expand: {} to {}", .{ buf.len, new_len }) catch {}; |
| 53 | 53 | } |
| 54 | ||
| 54 | 55 | if (self.parent_allocator.rawResize(buf, buf_align, new_len, len_align, ra)) |resized_len| { |
| 55 | 56 | if (new_len > buf.len) { |
| 56 | 57 | self.writer.print(" success!\n", .{}) catch {}; |
| 57 | 58 | } |
| 58 | 59 | return resized_len; |
| 59 | } else |e| { | |
| 60 | std.debug.assert(new_len > buf.len); | |
| 61 | self.writer.print(" failure!\n", .{}) catch {}; | |
| 62 | return e; | |
| 63 | 60 | } |
| 61 | ||
| 62 | std.debug.assert(new_len > buf.len); | |
| 63 | self.writer.print(" failure!\n", .{}) catch {}; | |
| 64 | return null; | |
| 64 | 65 | } |
| 65 | 66 | |
| 66 | 67 | fn free( |
| ... | ... | @@ -95,7 +96,7 @@ test "LogToWriterAllocator" { |
| 95 | 96 | var a = try allocator.alloc(u8, 10); |
| 96 | 97 | a = allocator.shrink(a, 5); |
| 97 | 98 | try std.testing.expect(a.len == 5); |
| 98 | try std.testing.expectError(error.OutOfMemory, allocator.resize(a, 20)); | |
| 99 | try std.testing.expect(allocator.resize(a, 20) == null); | |
| 99 | 100 | allocator.free(a); |
| 100 | 101 | |
| 101 | 102 | try std.testing.expectEqualSlices(u8, |
lib/std/heap/logging_allocator.zig+9-9| ... | ... | @@ -77,7 +77,7 @@ pub fn ScopedLoggingAllocator( |
| 77 | 77 | new_len: usize, |
| 78 | 78 | len_align: u29, |
| 79 | 79 | ra: usize, |
| 80 | ) error{OutOfMemory}!usize { | |
| 80 | ) ?usize { | |
| 81 | 81 | if (self.parent_allocator.rawResize(buf, buf_align, new_len, len_align, ra)) |resized_len| { |
| 82 | 82 | if (new_len <= buf.len) { |
| 83 | 83 | logHelper( |
| ... | ... | @@ -94,15 +94,15 @@ pub fn ScopedLoggingAllocator( |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | 96 | return resized_len; |
| 97 | } else |err| { | |
| 98 | std.debug.assert(new_len > buf.len); | |
| 99 | logHelper( | |
| 100 | failure_log_level, | |
| 101 | "expand - failure: {s} - {} to {}, len_align: {}, buf_align: {}", | |
| 102 | .{ @errorName(err), buf.len, new_len, len_align, buf_align }, | |
| 103 | ); | |
| 104 | return err; | |
| 105 | 97 | } |
| 98 | ||
| 99 | std.debug.assert(new_len > buf.len); | |
| 100 | logHelper( | |
| 101 | failure_log_level, | |
| 102 | "expand - failure - {} to {}, len_align: {}, buf_align: {}", | |
| 103 | .{ buf.len, new_len, len_align, buf_align }, | |
| 104 | ); | |
| 105 | return null; | |
| 106 | 106 | } |
| 107 | 107 | |
| 108 | 108 | fn free( |
lib/std/mem.zig+4-4| ... | ... | @@ -88,14 +88,14 @@ pub fn ValidationAllocator(comptime T: type) type { |
| 88 | 88 | new_len: usize, |
| 89 | 89 | len_align: u29, |
| 90 | 90 | ret_addr: usize, |
| 91 | ) Allocator.Error!usize { | |
| 91 | ) ?usize { | |
| 92 | 92 | assert(buf.len > 0); |
| 93 | 93 | if (len_align != 0) { |
| 94 | 94 | assert(mem.isAlignedAnyAlign(new_len, len_align)); |
| 95 | 95 | assert(new_len >= len_align); |
| 96 | 96 | } |
| 97 | 97 | const underlying = self.getUnderlyingAllocatorPtr(); |
| 98 | const result = try underlying.rawResize(buf, buf_align, new_len, len_align, ret_addr); | |
| 98 | const result = underlying.rawResize(buf, buf_align, new_len, len_align, ret_addr) orelse return null; | |
| 99 | 99 | if (len_align == 0) { |
| 100 | 100 | assert(result == new_len); |
| 101 | 101 | } else { |
| ... | ... | @@ -188,7 +188,7 @@ test "Allocator.resize" { |
| 188 | 188 | defer testing.allocator.free(values); |
| 189 | 189 | |
| 190 | 190 | for (values) |*v, i| v.* = @intCast(T, i); |
| 191 | values = try testing.allocator.resize(values, values.len + 10); | |
| 191 | values = testing.allocator.resize(values, values.len + 10) orelse return error.OutOfMemory; | |
| 192 | 192 | try testing.expect(values.len == 110); |
| 193 | 193 | } |
| 194 | 194 | |
| ... | ... | @@ -203,7 +203,7 @@ test "Allocator.resize" { |
| 203 | 203 | defer testing.allocator.free(values); |
| 204 | 204 | |
| 205 | 205 | for (values) |*v, i| v.* = @intToFloat(T, i); |
| 206 | values = try testing.allocator.resize(values, values.len + 10); | |
| 206 | values = testing.allocator.resize(values, values.len + 10) orelse return error.OutOfMemory; | |
| 207 | 207 | try testing.expect(values.len == 110); |
| 208 | 208 | } |
| 209 | 209 | } |
lib/std/mem/Allocator.zig+38-110| ... | ... | @@ -29,9 +29,9 @@ pub const VTable = struct { |
| 29 | 29 | /// length returned by `alloc` or `resize`. `buf_align` must equal the same value |
| 30 | 30 | /// that was passed as the `ptr_align` parameter to the original `alloc` call. |
| 31 | 31 | /// |
| 32 | /// error.OutOfMemory can only be returned if `new_len` is greater than `buf.len`. | |
| 32 | /// `null` can only be returned if `new_len` is greater than `buf.len`. | |
| 33 | 33 | /// If `buf` cannot be expanded to accomodate `new_len`, then the allocation MUST be |
| 34 | /// unmodified and error.OutOfMemory MUST be returned. | |
| 34 | /// unmodified and `null` MUST be returned. | |
| 35 | 35 | /// |
| 36 | 36 | /// If `len_align` is `0`, then the length returned MUST be exactly `len` bytes, |
| 37 | 37 | /// otherwise, the length must be aligned to `len_align`. Note that `len_align` does *not* |
| ... | ... | @@ -42,7 +42,7 @@ pub const VTable = struct { |
| 42 | 42 | /// |
| 43 | 43 | /// `ret_addr` is optionally provided as the first return address of the allocation call stack. |
| 44 | 44 | /// If the value is `0` it means no return address has been provided. |
| 45 | resize: fn (ptr: *c_void, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) Error!usize, | |
| 45 | resize: fn (ptr: *c_void, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize, | |
| 46 | 46 | |
| 47 | 47 | /// Free and invalidate a buffer. `buf.len` must equal the most recent length returned by `alloc` or `resize`. |
| 48 | 48 | /// `buf_align` must equal the same value that was passed as the `ptr_align` parameter to the original `alloc` call. |
| ... | ... | @@ -55,7 +55,7 @@ pub const VTable = struct { |
| 55 | 55 | pub fn init( |
| 56 | 56 | pointer: anytype, |
| 57 | 57 | comptime allocFn: fn (ptr: @TypeOf(pointer), len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8, |
| 58 | comptime resizeFn: fn (ptr: @TypeOf(pointer), buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) Error!usize, | |
| 58 | comptime resizeFn: fn (ptr: @TypeOf(pointer), buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize, | |
| 59 | 59 | comptime freeFn: fn (ptr: @TypeOf(pointer), buf: []u8, buf_align: u29, ret_addr: usize) void, |
| 60 | 60 | ) Allocator { |
| 61 | 61 | const Ptr = @TypeOf(pointer); |
| ... | ... | @@ -71,7 +71,7 @@ pub fn init( |
| 71 | 71 | const self = @ptrCast(Ptr, @alignCast(alignment, ptr)); |
| 72 | 72 | return @call(.{ .modifier = .always_inline }, allocFn, .{ self, len, ptr_align, len_align, ret_addr }); |
| 73 | 73 | } |
| 74 | fn resize(ptr: *c_void, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) Error!usize { | |
| 74 | fn resize(ptr: *c_void, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize { | |
| 75 | 75 | assert(new_len != 0); |
| 76 | 76 | const self = @ptrCast(Ptr, @alignCast(alignment, ptr)); |
| 77 | 77 | return @call(.{ .modifier = .always_inline }, resizeFn, .{ self, buf, buf_align, new_len, len_align, ret_addr }); |
| ... | ... | @@ -104,14 +104,12 @@ pub fn NoResize(comptime AllocatorType: type) type { |
| 104 | 104 | new_len: usize, |
| 105 | 105 | len_align: u29, |
| 106 | 106 | ret_addr: usize, |
| 107 | ) Error!usize { | |
| 107 | ) ?usize { | |
| 108 | 108 | _ = self; |
| 109 | 109 | _ = buf_align; |
| 110 | 110 | _ = len_align; |
| 111 | 111 | _ = ret_addr; |
| 112 | if (new_len > buf.len) | |
| 113 | return error.OutOfMemory; | |
| 114 | return new_len; | |
| 112 | return if (new_len > buf.len) null else new_len; | |
| 115 | 113 | } |
| 116 | 114 | }; |
| 117 | 115 | } |
| ... | ... | @@ -157,7 +155,7 @@ pub inline fn rawAlloc(self: Allocator, len: usize, ptr_align: u29, len_align: u |
| 157 | 155 | } |
| 158 | 156 | |
| 159 | 157 | /// This function is not intended to be called except from within the implementation of an Allocator |
| 160 | pub inline fn rawResize(self: Allocator, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) Error!usize { | |
| 158 | pub inline fn rawResize(self: Allocator, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize { | |
| 161 | 159 | return self.vtable.resize(self.ptr, buf, buf_align, new_len, len_align, ret_addr); |
| 162 | 160 | } |
| 163 | 161 | |
| ... | ... | @@ -166,99 +164,6 @@ pub inline fn rawFree(self: Allocator, buf: []u8, buf_align: u29, ret_addr: usiz |
| 166 | 164 | return self.vtable.free(self.ptr, buf, buf_align, ret_addr); |
| 167 | 165 | } |
| 168 | 166 | |
| 169 | /// Realloc is used to modify the size or alignment of an existing allocation, | |
| 170 | /// as well as to provide the allocator with an opportunity to move an allocation | |
| 171 | /// to a better location. | |
| 172 | /// When the size/alignment is greater than the previous allocation, this function | |
| 173 | /// returns `error.OutOfMemory` when the requested new allocation could not be granted. | |
| 174 | /// When the size/alignment is less than or equal to the previous allocation, | |
| 175 | /// this function returns `error.OutOfMemory` when the allocator decides the client | |
| 176 | /// would be better off keeping the extra alignment/size. Clients will call | |
| 177 | /// `vtable.resize` when they require the allocator to track a new alignment/size, | |
| 178 | /// and so this function should only return success when the allocator considers | |
| 179 | /// the reallocation desirable from the allocator's perspective. | |
| 180 | /// As an example, `std.ArrayList` tracks a "capacity", and therefore can handle | |
| 181 | /// reallocation failure, even when `new_n` <= `old_mem.len`. A `FixedBufferAllocator` | |
| 182 | /// would always return `error.OutOfMemory` for `reallocFn` when the size/alignment | |
| 183 | /// is less than or equal to the old allocation, because it cannot reclaim the memory, | |
| 184 | /// and thus the `std.ArrayList` would be better off retaining its capacity. | |
| 185 | /// When `reallocFn` returns, | |
| 186 | /// `return_value[0..min(old_mem.len, new_byte_count)]` must be the same | |
| 187 | /// as `old_mem` was when `reallocFn` is called. The bytes of | |
| 188 | /// `return_value[old_mem.len..]` have undefined values. | |
| 189 | /// The returned slice must have its pointer aligned at least to `new_alignment` bytes. | |
| 190 | fn reallocBytes( | |
| 191 | self: Allocator, | |
| 192 | /// Guaranteed to be the same as what was returned from most recent call to | |
| 193 | /// `vtable.alloc` or `vtable.resize`. | |
| 194 | /// If `old_mem.len == 0` then this is a new allocation and `new_byte_count` | |
| 195 | /// is guaranteed to be >= 1. | |
| 196 | old_mem: []u8, | |
| 197 | /// If `old_mem.len == 0` then this is `undefined`, otherwise: | |
| 198 | /// Guaranteed to be the same as what was passed to `allocFn`. | |
| 199 | /// Guaranteed to be >= 1. | |
| 200 | /// Guaranteed to be a power of 2. | |
| 201 | old_alignment: u29, | |
| 202 | /// `new_byte_count` must be greater than zero | |
| 203 | new_byte_count: usize, | |
| 204 | /// Guaranteed to be >= 1. | |
| 205 | /// Guaranteed to be a power of 2. | |
| 206 | /// Returned slice's pointer must have this alignment. | |
| 207 | new_alignment: u29, | |
| 208 | /// 0 indicates the length of the slice returned MUST match `new_byte_count` exactly | |
| 209 | /// non-zero means the length of the returned slice must be aligned by `len_align` | |
| 210 | /// `new_len` must be aligned by `len_align` | |
| 211 | len_align: u29, | |
| 212 | return_address: usize, | |
| 213 | ) Error![]u8 { | |
| 214 | if (old_mem.len == 0) { | |
| 215 | const new_mem = try self.rawAlloc(new_byte_count, new_alignment, len_align, return_address); | |
| 216 | // TODO: https://github.com/ziglang/zig/issues/4298 | |
| 217 | @memset(new_mem.ptr, undefined, new_byte_count); | |
| 218 | return new_mem; | |
| 219 | } | |
| 220 | ||
| 221 | assert(new_byte_count > 0); // `new_byte_count` must greater than zero, this is a resize not a free | |
| 222 | ||
| 223 | if (mem.isAligned(@ptrToInt(old_mem.ptr), new_alignment)) { | |
| 224 | if (new_byte_count <= old_mem.len) { | |
| 225 | const shrunk_len = self.shrinkBytes(old_mem, old_alignment, new_byte_count, len_align, return_address); | |
| 226 | return old_mem.ptr[0..shrunk_len]; | |
| 227 | } | |
| 228 | if (self.rawResize(old_mem, old_alignment, new_byte_count, len_align, return_address)) |resized_len| { | |
| 229 | assert(resized_len >= new_byte_count); | |
| 230 | // TODO: https://github.com/ziglang/zig/issues/4298 | |
| 231 | @memset(old_mem.ptr + new_byte_count, undefined, resized_len - new_byte_count); | |
| 232 | return old_mem.ptr[0..resized_len]; | |
| 233 | } else |_| {} | |
| 234 | } | |
| 235 | if (new_byte_count <= old_mem.len and new_alignment <= old_alignment) { | |
| 236 | return error.OutOfMemory; | |
| 237 | } | |
| 238 | return self.moveBytes(old_mem, old_alignment, new_byte_count, new_alignment, len_align, return_address); | |
| 239 | } | |
| 240 | ||
| 241 | /// Move the given memory to a new location in the given allocator to accomodate a new | |
| 242 | /// size and alignment. | |
| 243 | fn moveBytes( | |
| 244 | self: Allocator, | |
| 245 | old_mem: []u8, | |
| 246 | old_align: u29, | |
| 247 | new_len: usize, | |
| 248 | new_alignment: u29, | |
| 249 | len_align: u29, | |
| 250 | return_address: usize, | |
| 251 | ) Error![]u8 { | |
| 252 | assert(old_mem.len > 0); | |
| 253 | assert(new_len > 0); | |
| 254 | const new_mem = try self.rawAlloc(new_len, new_alignment, len_align, return_address); | |
| 255 | @memcpy(new_mem.ptr, old_mem.ptr, math.min(new_len, old_mem.len)); | |
| 256 | // TODO https://github.com/ziglang/zig/issues/4298 | |
| 257 | @memset(old_mem.ptr, undefined, old_mem.len); | |
| 258 | self.rawFree(old_mem, old_align, return_address); | |
| 259 | return new_mem; | |
| 260 | } | |
| 261 | ||
| 262 | 167 | /// Returns a pointer to undefined memory. |
| 263 | 168 | /// Call `destroy` with the result to free the memory. |
| 264 | 169 | pub fn create(self: Allocator, comptime T: type) Error!*T { |
| ... | ... | @@ -409,7 +314,7 @@ pub fn allocAdvancedWithRetAddr( |
| 409 | 314 | } |
| 410 | 315 | |
| 411 | 316 | /// Increases or decreases the size of an allocation. It is guaranteed to not move the pointer. |
| 412 | pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) Error!@TypeOf(old_mem) { | |
| 317 | pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) ?@TypeOf(old_mem) { | |
| 413 | 318 | const Slice = @typeInfo(@TypeOf(old_mem)).Pointer; |
| 414 | 319 | const T = Slice.child; |
| 415 | 320 | if (new_n == 0) { |
| ... | ... | @@ -417,8 +322,8 @@ pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) Error!@TypeOf(old |
| 417 | 322 | return &[0]T{}; |
| 418 | 323 | } |
| 419 | 324 | const old_byte_slice = mem.sliceAsBytes(old_mem); |
| 420 | const new_byte_count = math.mul(usize, @sizeOf(T), new_n) catch return Error.OutOfMemory; | |
| 421 | const rc = try self.rawResize(old_byte_slice, Slice.alignment, new_byte_count, 0, @returnAddress()); | |
| 325 | const new_byte_count = math.mul(usize, @sizeOf(T), new_n) catch return null; | |
| 326 | const rc = self.rawResize(old_byte_slice, Slice.alignment, new_byte_count, 0, @returnAddress()) orelse return null; | |
| 422 | 327 | assert(rc == new_byte_count); |
| 423 | 328 | const new_byte_slice = old_byte_slice.ptr[0..new_byte_count]; |
| 424 | 329 | return mem.bytesAsSlice(T, new_byte_slice); |
| ... | ... | @@ -488,8 +393,31 @@ pub fn reallocAdvancedWithRetAddr( |
| 488 | 393 | .exact => 0, |
| 489 | 394 | .at_least => @sizeOf(T), |
| 490 | 395 | }; |
| 491 | const new_byte_slice = try self.reallocBytes(old_byte_slice, Slice.alignment, byte_count, new_alignment, len_align, return_address); | |
| 492 | return mem.bytesAsSlice(T, @alignCast(new_alignment, new_byte_slice)); | |
| 396 | ||
| 397 | if (mem.isAligned(@ptrToInt(old_byte_slice.ptr), new_alignment)) { | |
| 398 | if (byte_count <= old_byte_slice.len) { | |
| 399 | const shrunk_len = self.shrinkBytes(old_byte_slice, Slice.alignment, byte_count, len_align, return_address); | |
| 400 | return mem.bytesAsSlice(T, @alignCast(new_alignment, old_byte_slice.ptr[0..shrunk_len])); | |
| 401 | } | |
| 402 | ||
| 403 | if (self.rawResize(old_byte_slice, Slice.alignment, byte_count, len_align, return_address)) |resized_len| { | |
| 404 | // TODO: https://github.com/ziglang/zig/issues/4298 | |
| 405 | @memset(old_byte_slice.ptr + byte_count, undefined, resized_len - byte_count); | |
| 406 | return mem.bytesAsSlice(T, @alignCast(new_alignment, old_byte_slice.ptr[0..resized_len])); | |
| 407 | } | |
| 408 | } | |
| 409 | ||
| 410 | if (byte_count <= old_byte_slice.len and new_alignment <= Slice.alignment) { | |
| 411 | return error.OutOfMemory; | |
| 412 | } | |
| 413 | ||
| 414 | const new_mem = try self.rawAlloc(byte_count, new_alignment, len_align, return_address); | |
| 415 | @memcpy(new_mem.ptr, old_byte_slice.ptr, math.min(byte_count, old_byte_slice.len)); | |
| 416 | // TODO https://github.com/ziglang/zig/issues/4298 | |
| 417 | @memset(old_byte_slice.ptr, undefined, old_byte_slice.len); | |
| 418 | self.rawFree(old_byte_slice, Slice.alignment, return_address); | |
| 419 | ||
| 420 | return mem.bytesAsSlice(T, @alignCast(new_alignment, new_mem)); | |
| 493 | 421 | } |
| 494 | 422 | |
| 495 | 423 | /// Prefer calling realloc to shrink if you can tolerate failure, such as |
| ... | ... | @@ -580,7 +508,7 @@ pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) ![:0]T { |
| 580 | 508 | } |
| 581 | 509 | |
| 582 | 510 | /// Call `vtable.resize`, but caller guarantees that `new_len` <= `buf.len` meaning |
| 583 | /// error.OutOfMemory should be impossible. | |
| 511 | /// than a `null` return value should be impossible. | |
| 584 | 512 | /// This function allows a runtime `buf_align` value. Callers should generally prefer |
| 585 | 513 | /// to call `shrink` directly. |
| 586 | 514 | pub fn shrinkBytes( |
| ... | ... | @@ -592,5 +520,5 @@ pub fn shrinkBytes( |
| 592 | 520 | return_address: usize, |
| 593 | 521 | ) usize { |
| 594 | 522 | assert(new_len <= buf.len); |
| 595 | return self.rawResize(buf, buf_align, new_len, len_align, return_address) catch unreachable; | |
| 523 | return self.rawResize(buf, buf_align, new_len, len_align, return_address) orelse unreachable; | |
| 596 | 524 | } |
lib/std/testing/failing_allocator.zig+2-5| ... | ... | @@ -68,11 +68,8 @@ pub const FailingAllocator = struct { |
| 68 | 68 | new_len: usize, |
| 69 | 69 | len_align: u29, |
| 70 | 70 | ra: usize, |
| 71 | ) error{OutOfMemory}!usize { | |
| 72 | const r = self.internal_allocator.rawResize(old_mem, old_align, new_len, len_align, ra) catch |e| { | |
| 73 | std.debug.assert(new_len > old_mem.len); | |
| 74 | return e; | |
| 75 | }; | |
| 71 | ) ?usize { | |
| 72 | const r = self.internal_allocator.rawResize(old_mem, old_align, new_len, len_align, ra) orelse return null; | |
| 76 | 73 | if (r < old_mem.len) { |
| 77 | 74 | self.freed_bytes += old_mem.len - r; |
| 78 | 75 | } else { |
src/link/MachO.zig+1-1| ... | ... | @@ -1288,7 +1288,7 @@ fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs: any |
| 1288 | 1288 | // TODO this should not be performed if the user specifies `-flat_namespace` flag. |
| 1289 | 1289 | // See ld64 manpages. |
| 1290 | 1290 | var arena_alloc = std.heap.ArenaAllocator.init(self.base.allocator); |
| 1291 | const arena = &arena_alloc.allocator; | |
| 1291 | const arena = arena_alloc.allocator(); | |
| 1292 | 1292 | defer arena_alloc.deinit(); |
| 1293 | 1293 | |
| 1294 | 1294 | while (dependent_libs.readItem()) |*id| { |
src/link/tapi.zig+1-1| ... | ... | @@ -138,7 +138,7 @@ pub const LibStub = struct { |
| 138 | 138 | err: { |
| 139 | 139 | log.debug("trying to parse as []TbdV3", .{}); |
| 140 | 140 | const inner = lib_stub.yaml.parse([]TbdV3) catch break :err; |
| 141 | var out = try lib_stub.yaml.arena.allocator.alloc(Tbd, inner.len); | |
| 141 | var out = try lib_stub.yaml.arena.allocator().alloc(Tbd, inner.len); | |
| 142 | 142 | for (inner) |doc, i| { |
| 143 | 143 | out[i] = .{ .v3 = doc }; |
| 144 | 144 | } |
src/main.zig+1-1| ... | ... | @@ -159,7 +159,7 @@ pub fn main() anyerror!void { |
| 159 | 159 | |
| 160 | 160 | if (tracy.enable_allocation) { |
| 161 | 161 | var gpa_tracy = tracy.tracyAllocator(gpa); |
| 162 | return mainArgs(&gpa_tracy.allocator, arena, args); | |
| 162 | return mainArgs(gpa_tracy.allocator(), arena, args); | |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | 165 | return mainArgs(gpa, arena, args); |
src/tracy.zig+10-15| ... | ... | @@ -113,20 +113,16 @@ pub fn TracyAllocator(comptime name: ?[:0]const u8) type { |
| 113 | 113 | |
| 114 | 114 | const Self = @This(); |
| 115 | 115 | |
| 116 | pub fn allocator(self: *Self) std.mem.Allocator { | |
| 117 | return std.mem.Allocator.init(self, allocFn, resizeFn); | |
| 118 | } | |
| 119 | ||
| 120 | pub fn init(allocator: std.mem.Allocator) Self { | |
| 116 | pub fn init(parent_allocator: std.mem.Allocator) Self { | |
| 121 | 117 | return .{ |
| 122 | .parent_allocator = allocator, | |
| 123 | .allocator = .{ | |
| 124 | .allocFn = allocFn, | |
| 125 | .resizeFn = resizeFn, | |
| 126 | }, | |
| 118 | .parent_allocator = parent_allocator, | |
| 127 | 119 | }; |
| 128 | 120 | } |
| 129 | 121 | |
| 122 | pub fn allocator(self: *Self) std.mem.Allocator { | |
| 123 | return std.mem.Allocator.init(self, allocFn, resizeFn, freeFn); | |
| 124 | } | |
| 125 | ||
| 130 | 126 | fn allocFn(self: *Self, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) std.mem.Allocator.Error![]u8 { |
| 131 | 127 | const result = self.parent_allocator.allocFn(self.parent_allocator, len, ptr_align, len_align, ret_addr); |
| 132 | 128 | if (result) |data| { |
| ... | ... | @@ -162,12 +158,11 @@ pub fn TracyAllocator(comptime name: ?[:0]const u8) type { |
| 162 | 158 | } |
| 163 | 159 | |
| 164 | 160 | return resized_len; |
| 165 | } else |err| { | |
| 166 | // this is not really an error condition, during normal operation the compiler hits this case thousands of times | |
| 167 | // due to this emitting messages for it is both slow and causes clutter | |
| 168 | // messageColor("allocation resize failed", 0xFF0000); | |
| 169 | return err; | |
| 170 | 161 | } |
| 162 | ||
| 163 | // during normal operation the compiler hits this case thousands of times due to this | |
| 164 | // emitting messages for it is both slow and causes clutter | |
| 165 | return null; | |
| 171 | 166 | } |
| 172 | 167 | |
| 173 | 168 | fn freeFn(self: *Self, buf: []u8, buf_align: u29, ret_addr: usize) void { |
test/compare_output.zig+3-3| ... | ... | @@ -496,7 +496,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 496 | 496 | \\ var a = try allocator.alloc(u8, 10); |
| 497 | 497 | \\ a = allocator.shrink(a, 5); |
| 498 | 498 | \\ try std.testing.expect(a.len == 5); |
| 499 | \\ try std.testing.expectError(error.OutOfMemory, allocator.resize(a, 20)); | |
| 499 | \\ try std.testing.expect(allocator.resize(a, 20) == null); | |
| 500 | 500 | \\ allocator.free(a); |
| 501 | 501 | \\} |
| 502 | 502 | \\ |
| ... | ... | @@ -514,8 +514,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 514 | 514 | , |
| 515 | 515 | \\debug: alloc - success - len: 10, ptr_align: 1, len_align: 0 |
| 516 | 516 | \\debug: shrink - success - 10 to 5, len_align: 0, buf_align: 1 |
| 517 | \\error: expand - failure: OutOfMemory - 5 to 20, len_align: 0, buf_align: 1 | |
| 518 | \\debug: free - success - len: 5 | |
| 517 | \\error: expand - failure - 5 to 20, len_align: 0, buf_align: 1 | |
| 518 | \\debug: free - len: 5 | |
| 519 | 519 | \\ |
| 520 | 520 | ); |
| 521 | 521 | } |
tools/update-linux-headers.zig+1-1| ... | ... | @@ -131,7 +131,7 @@ const PathTable = std.StringHashMap(*TargetToHash); |
| 131 | 131 | |
| 132 | 132 | pub fn main() !void { |
| 133 | 133 | var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| 134 | const arena = &arena_state.allocator; | |
| 134 | const arena = arena_state.allocator(); | |
| 135 | 135 | const args = try std.process.argsAlloc(arena); |
| 136 | 136 | var search_paths = std.ArrayList([]const u8).init(arena); |
| 137 | 137 | var opt_out_dir: ?[]const u8 = null; |