authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-30 01:44:34-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-11-30 01:44:34-05:00
loge35f297aeb993ec956ae80379ddf7f86069e109b
tree45cbb5b3ebbe23a46e27b04aa5898a6c00ec4a61
parentdeda6b514691c3a7ffc7931469886d0e7be2f67e
parentf4666678886c2a7a993ad30b63de4ff25594085a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13666 from ziglang/allocator-interface

std.mem.Allocator: allow shrink to fail

58 files changed, 993 insertions(+), 1303 deletions(-)

doc/docgen.zig+7-7
......@@ -471,7 +471,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
471471 },
472472 Token.Id.Separator => {},
473473 Token.Id.BracketClose => {
474 try nodes.append(Node{ .SeeAlso = list.toOwnedSlice() });
474 try nodes.append(Node{ .SeeAlso = try list.toOwnedSlice() });
475475 break;
476476 },
477477 else => return parseError(tokenizer, see_also_tok, "invalid see_also token", .{}),
......@@ -610,7 +610,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
610610 .source_token = source_token,
611611 .just_check_syntax = just_check_syntax,
612612 .mode = mode,
613 .link_objects = link_objects.toOwnedSlice(),
613 .link_objects = try link_objects.toOwnedSlice(),
614614 .target_str = target_str,
615615 .link_libc = link_libc,
616616 .backend_stage1 = backend_stage1,
......@@ -707,8 +707,8 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
707707 }
708708
709709 return Toc{
710 .nodes = nodes.toOwnedSlice(),
711 .toc = toc_buf.toOwnedSlice(),
710 .nodes = try nodes.toOwnedSlice(),
711 .toc = try toc_buf.toOwnedSlice(),
712712 .urls = urls,
713713 };
714714}
......@@ -729,7 +729,7 @@ fn urlize(allocator: Allocator, input: []const u8) ![]u8 {
729729 else => {},
730730 }
731731 }
732 return buf.toOwnedSlice();
732 return try buf.toOwnedSlice();
733733}
734734
735735fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {
......@@ -738,7 +738,7 @@ fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {
738738
739739 const out = buf.writer();
740740 try writeEscaped(out, input);
741 return buf.toOwnedSlice();
741 return try buf.toOwnedSlice();
742742}
743743
744744fn writeEscaped(out: anytype, input: []const u8) !void {
......@@ -854,7 +854,7 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 {
854854 },
855855 }
856856 }
857 return buf.toOwnedSlice();
857 return try buf.toOwnedSlice();
858858}
859859
860860const builtin_types = [_][]const u8{
lib/std/array_hash_map.zig+1-1
......@@ -1872,7 +1872,7 @@ const IndexHeader = struct {
18721872 const len = @as(usize, 1) << @intCast(math.Log2Int(usize), new_bit_index);
18731873 const index_size = hash_map.capacityIndexSize(new_bit_index);
18741874 const nbytes = @sizeOf(IndexHeader) + index_size * len;
1875 const bytes = try allocator.allocAdvanced(u8, @alignOf(IndexHeader), nbytes, .exact);
1875 const bytes = try allocator.alignedAlloc(u8, @alignOf(IndexHeader), nbytes);
18761876 @memset(bytes.ptr + @sizeOf(IndexHeader), 0xff, bytes.len - @sizeOf(IndexHeader));
18771877 const result = @ptrCast(*IndexHeader, bytes.ptr);
18781878 result.* = .{
lib/std/array_list.zig+141-49
......@@ -47,6 +47,10 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
4747
4848 pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
4949
50 pub fn SentinelSlice(comptime s: T) type {
51 return if (alignment) |a| ([:s]align(a) T) else [:s]T;
52 }
53
5054 /// Deinitialize with `deinit` or use `toOwnedSlice`.
5155 pub fn init(allocator: Allocator) Self {
5256 return Self{
......@@ -92,18 +96,31 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
9296 return result;
9397 }
9498
95 /// The caller owns the returned memory. Empties this ArrayList.
96 pub fn toOwnedSlice(self: *Self) Slice {
99 /// The caller owns the returned memory. Empties this ArrayList,
100 /// however its capacity may or may not be cleared and deinit() is
101 /// still required to clean up its memory.
102 pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice {
97103 const allocator = self.allocator;
98 const result = allocator.shrink(self.allocatedSlice(), self.items.len);
99 self.* = init(allocator);
100 return result;
104
105 const old_memory = self.allocatedSlice();
106 if (allocator.resize(old_memory, self.items.len)) {
107 const result = self.items;
108 self.* = init(allocator);
109 return result;
110 }
111
112 const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);
113 mem.copy(T, new_memory, self.items);
114 @memset(@ptrCast([*]u8, self.items.ptr), undefined, self.items.len * @sizeOf(T));
115 self.items.len = 0;
116 return new_memory;
101117 }
102118
103119 /// The caller owns the returned memory. Empties this ArrayList.
104 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error![:sentinel]T {
105 try self.append(sentinel);
106 const result = self.toOwnedSlice();
120 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
121 try self.ensureTotalCapacityPrecise(self.items.len + 1);
122 self.appendAssumeCapacity(sentinel);
123 const result = try self.toOwnedSlice();
107124 return result[0 .. result.len - 1 :sentinel];
108125 }
109126
......@@ -299,17 +316,30 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
299316 pub fn shrinkAndFree(self: *Self, new_len: usize) void {
300317 assert(new_len <= self.items.len);
301318
302 if (@sizeOf(T) > 0) {
303 self.items = self.allocator.realloc(self.allocatedSlice(), new_len) catch |e| switch (e) {
304 error.OutOfMemory => { // no problem, capacity is still correct then.
305 self.items.len = new_len;
306 return;
307 },
308 };
319 if (@sizeOf(T) == 0) {
320 self.items.len = new_len;
321 return;
322 }
323
324 const old_memory = self.allocatedSlice();
325 if (self.allocator.resize(old_memory, new_len)) {
309326 self.capacity = new_len;
310 } else {
311327 self.items.len = new_len;
328 return;
312329 }
330
331 const new_memory = self.allocator.alignedAlloc(T, alignment, new_len) catch |e| switch (e) {
332 error.OutOfMemory => {
333 // No problem, capacity is still correct then.
334 self.items.len = new_len;
335 return;
336 },
337 };
338
339 mem.copy(T, new_memory, self.items);
340 self.allocator.free(old_memory);
341 self.items = new_memory;
342 self.capacity = new_memory.len;
313343 }
314344
315345 /// Reduce length to `new_len`.
......@@ -334,19 +364,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
334364 /// Modify the array so that it can hold at least `new_capacity` items.
335365 /// Invalidates pointers if additional memory is needed.
336366 pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) Allocator.Error!void {
337 if (@sizeOf(T) > 0) {
338 if (self.capacity >= new_capacity) return;
367 if (@sizeOf(T) == 0) {
368 self.capacity = math.maxInt(usize);
369 return;
370 }
339371
340 var better_capacity = self.capacity;
341 while (true) {
342 better_capacity +|= better_capacity / 2 + 8;
343 if (better_capacity >= new_capacity) break;
344 }
372 if (self.capacity >= new_capacity) return;
345373
346 return self.ensureTotalCapacityPrecise(better_capacity);
347 } else {
348 self.capacity = math.maxInt(usize);
374 var better_capacity = self.capacity;
375 while (true) {
376 better_capacity +|= better_capacity / 2 + 8;
377 if (better_capacity >= new_capacity) break;
349378 }
379
380 return self.ensureTotalCapacityPrecise(better_capacity);
350381 }
351382
352383 /// Modify the array so that it can hold at least `new_capacity` items.
......@@ -354,15 +385,27 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
354385 /// (but not guaranteed) to be equal to `new_capacity`.
355386 /// Invalidates pointers if additional memory is needed.
356387 pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void {
357 if (@sizeOf(T) > 0) {
358 if (self.capacity >= new_capacity) return;
388 if (@sizeOf(T) == 0) {
389 self.capacity = math.maxInt(usize);
390 return;
391 }
359392
360 // TODO This can be optimized to avoid needlessly copying undefined memory.
361 const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), new_capacity);
393 if (self.capacity >= new_capacity) return;
394
395 // Here we avoid copying allocated but unused bytes by
396 // attempting a resize in place, and falling back to allocating
397 // a new buffer and doing our own copy. With a realloc() call,
398 // the allocator implementation would pointlessly copy our
399 // extra capacity.
400 const old_memory = self.allocatedSlice();
401 if (self.allocator.resize(old_memory, new_capacity)) {
402 self.capacity = new_capacity;
403 } else {
404 const new_memory = try self.allocator.alignedAlloc(T, alignment, new_capacity);
405 mem.copy(T, new_memory, self.items);
406 self.allocator.free(old_memory);
362407 self.items.ptr = new_memory.ptr;
363408 self.capacity = new_memory.len;
364 } else {
365 self.capacity = math.maxInt(usize);
366409 }
367410 }
368411
......@@ -381,8 +424,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
381424 /// Increase length by 1, returning pointer to the new item.
382425 /// The returned pointer becomes invalid when the list resized.
383426 pub fn addOne(self: *Self) Allocator.Error!*T {
384 const newlen = self.items.len + 1;
385 try self.ensureTotalCapacity(newlen);
427 try self.ensureTotalCapacity(self.items.len + 1);
386428 return self.addOneAssumeCapacity();
387429 }
388430
......@@ -392,7 +434,6 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
392434 /// **Does not** invalidate element pointers.
393435 pub fn addOneAssumeCapacity(self: *Self) *T {
394436 assert(self.items.len < self.capacity);
395
396437 self.items.len += 1;
397438 return &self.items[self.items.len - 1];
398439 }
......@@ -490,6 +531,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
490531
491532 pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
492533
534 pub fn SentinelSlice(comptime s: T) type {
535 return if (alignment) |a| ([:s]align(a) T) else [:s]T;
536 }
537
493538 /// Initialize with capacity to hold at least num elements.
494539 /// The resulting capacity is likely to be equal to `num`.
495540 /// Deinitialize with `deinit` or use `toOwnedSlice`.
......@@ -511,17 +556,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
511556 return .{ .items = self.items, .capacity = self.capacity, .allocator = allocator };
512557 }
513558
514 /// The caller owns the returned memory. ArrayList becomes empty.
515 pub fn toOwnedSlice(self: *Self, allocator: Allocator) Slice {
516 const result = allocator.shrink(self.allocatedSlice(), self.items.len);
517 self.* = Self{};
518 return result;
559 /// The caller owns the returned memory. Empties this ArrayList,
560 /// however its capacity may or may not be cleared and deinit() is
561 /// still required to clean up its memory.
562 pub fn toOwnedSlice(self: *Self, allocator: Allocator) Allocator.Error!Slice {
563 const old_memory = self.allocatedSlice();
564 if (allocator.resize(old_memory, self.items.len)) {
565 const result = self.items;
566 self.* = .{};
567 return result;
568 }
569
570 const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);
571 mem.copy(T, new_memory, self.items);
572 @memset(@ptrCast([*]u8, self.items.ptr), undefined, self.items.len * @sizeOf(T));
573 self.items.len = 0;
574 return new_memory;
519575 }
520576
521577 /// The caller owns the returned memory. ArrayList becomes empty.
522 pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error![:sentinel]T {
523 try self.append(allocator, sentinel);
524 const result = self.toOwnedSlice(allocator);
578 pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
579 try self.ensureTotalCapacityPrecise(allocator, self.items.len + 1);
580 self.appendAssumeCapacity(sentinel);
581 const result = try self.toOwnedSlice(allocator);
525582 return result[0 .. result.len - 1 :sentinel];
526583 }
527584
......@@ -701,16 +758,34 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
701758 }
702759
703760 /// Reduce allocated capacity to `new_len`.
761 /// May invalidate element pointers.
704762 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {
705763 assert(new_len <= self.items.len);
706764
707 self.items = allocator.realloc(self.allocatedSlice(), new_len) catch |e| switch (e) {
708 error.OutOfMemory => { // no problem, capacity is still correct then.
765 if (@sizeOf(T) == 0) {
766 self.items.len = new_len;
767 return;
768 }
769
770 const old_memory = self.allocatedSlice();
771 if (allocator.resize(old_memory, new_len)) {
772 self.capacity = new_len;
773 self.items.len = new_len;
774 return;
775 }
776
777 const new_memory = allocator.alignedAlloc(T, alignment, new_len) catch |e| switch (e) {
778 error.OutOfMemory => {
779 // No problem, capacity is still correct then.
709780 self.items.len = new_len;
710781 return;
711782 },
712783 };
713 self.capacity = new_len;
784
785 mem.copy(T, new_memory, self.items);
786 allocator.free(old_memory);
787 self.items = new_memory;
788 self.capacity = new_memory.len;
714789 }
715790
716791 /// Reduce length to `new_len`.
......@@ -752,11 +827,28 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
752827 /// (but not guaranteed) to be equal to `new_capacity`.
753828 /// Invalidates pointers if additional memory is needed.
754829 pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {
830 if (@sizeOf(T) == 0) {
831 self.capacity = math.maxInt(usize);
832 return;
833 }
834
755835 if (self.capacity >= new_capacity) return;
756836
757 const new_memory = try allocator.reallocAtLeast(self.allocatedSlice(), new_capacity);
758 self.items.ptr = new_memory.ptr;
759 self.capacity = new_memory.len;
837 // Here we avoid copying allocated but unused bytes by
838 // attempting a resize in place, and falling back to allocating
839 // a new buffer and doing our own copy. With a realloc() call,
840 // the allocator implementation would pointlessly copy our
841 // extra capacity.
842 const old_memory = self.allocatedSlice();
843 if (allocator.resize(old_memory, new_capacity)) {
844 self.capacity = new_capacity;
845 } else {
846 const new_memory = try allocator.alignedAlloc(T, alignment, new_capacity);
847 mem.copy(T, new_memory, self.items);
848 allocator.free(old_memory);
849 self.items.ptr = new_memory.ptr;
850 self.capacity = new_memory.len;
851 }
760852 }
761853
762854 /// Modify the array so that it can hold at least `additional_count` **more** items.
lib/std/build.zig+1-1
......@@ -2934,7 +2934,7 @@ pub const LibExeObjStep = struct {
29342934 }
29352935 }
29362936
2937 try zig_args.append(mcpu_buffer.toOwnedSlice());
2937 try zig_args.append(try mcpu_buffer.toOwnedSlice());
29382938 }
29392939
29402940 if (self.target.dynamic_linker.get()) |dynamic_linker| {
lib/std/child_process.zig+3-3
......@@ -421,8 +421,8 @@ pub const ChildProcess = struct {
421421
422422 return ExecResult{
423423 .term = try child.wait(),
424 .stdout = stdout.toOwnedSlice(),
425 .stderr = stderr.toOwnedSlice(),
424 .stdout = try stdout.toOwnedSlice(),
425 .stderr = try stderr.toOwnedSlice(),
426426 };
427427 }
428428
......@@ -1270,7 +1270,7 @@ pub fn createWindowsEnvBlock(allocator: mem.Allocator, env_map: *const EnvMap) !
12701270 i += 1;
12711271 result[i] = 0;
12721272 i += 1;
1273 return allocator.shrink(result, i);
1273 return try allocator.realloc(result, i);
12741274}
12751275
12761276pub fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) ![:null]?[*:0]u8 {
lib/std/debug.zig+1-1
......@@ -1112,7 +1112,7 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn
11121112 }
11131113 assert(state == .oso_close);
11141114
1115 const symbols = allocator.shrink(symbols_buf, symbol_index);
1115 const symbols = try allocator.realloc(symbols_buf, symbol_index);
11161116
11171117 // Even though lld emits symbols in ascending order, this debug code
11181118 // should work for programs linked in any valid way.
lib/std/fs/file.zig+2-4
......@@ -954,11 +954,9 @@ pub const File = struct {
954954 };
955955
956956 if (optional_sentinel) |sentinel| {
957 try array_list.append(sentinel);
958 const buf = array_list.toOwnedSlice();
959 return buf[0 .. buf.len - 1 :sentinel];
957 return try array_list.toOwnedSliceSentinel(sentinel);
960958 } else {
961 return array_list.toOwnedSlice();
959 return try array_list.toOwnedSlice();
962960 }
963961 }
964962
lib/std/fs/path.zig+1-1
......@@ -1155,7 +1155,7 @@ pub fn relativePosix(allocator: Allocator, from: []const u8, to: []const u8) ![]
11551155 }
11561156 if (to_rest.len == 0) {
11571157 // shave off the trailing slash
1158 return allocator.shrink(result, result_index - 1);
1158 return allocator.realloc(result, result_index - 1);
11591159 }
11601160
11611161 mem.copy(u8, result[result_index..], to_rest);
lib/std/fs/wasi.zig+3-3
......@@ -160,7 +160,7 @@ pub const PreopenList = struct {
160160 if (cwd_root) |root| assert(fs.path.isAbsolute(root));
161161
162162 // Clear contents if we're being called again
163 for (self.toOwnedSlice()) |preopen| {
163 for (try self.toOwnedSlice()) |preopen| {
164164 switch (preopen.type) {
165165 PreopenType.Dir => |path| self.buffer.allocator.free(path),
166166 }
......@@ -263,8 +263,8 @@ pub const PreopenList = struct {
263263 }
264264
265265 /// The caller owns the returned memory. ArrayList becomes empty.
266 pub fn toOwnedSlice(self: *Self) []Preopen {
267 return self.buffer.toOwnedSlice();
266 pub fn toOwnedSlice(self: *Self) ![]Preopen {
267 return try self.buffer.toOwnedSlice();
268268 }
269269};
270270
lib/std/heap.zig+202-293
......@@ -52,11 +52,12 @@ const CAllocator = struct {
5252 return @intToPtr(*[*]u8, @ptrToInt(ptr) - @sizeOf(usize));
5353 }
5454
55 fn alignedAlloc(len: usize, alignment: usize) ?[*]u8 {
55 fn alignedAlloc(len: usize, log2_align: u8) ?[*]u8 {
56 const alignment = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_align);
5657 if (supports_posix_memalign) {
5758 // The posix_memalign only accepts alignment values that are a
5859 // multiple of the pointer size
59 const eff_alignment = std.math.max(alignment, @sizeOf(usize));
60 const eff_alignment = @max(alignment, @sizeOf(usize));
6061
6162 var aligned_ptr: ?*anyopaque = undefined;
6263 if (c.posix_memalign(&aligned_ptr, eff_alignment, len) != 0)
......@@ -99,58 +100,42 @@ const CAllocator = struct {
99100 fn alloc(
100101 _: *anyopaque,
101102 len: usize,
102 alignment: u29,
103 len_align: u29,
103 log2_align: u8,
104104 return_address: usize,
105 ) error{OutOfMemory}![]u8 {
105 ) ?[*]u8 {
106106 _ = return_address;
107107 assert(len > 0);
108 assert(std.math.isPowerOfTwo(alignment));
109
110 var ptr = alignedAlloc(len, alignment) orelse return error.OutOfMemory;
111 if (len_align == 0) {
112 return ptr[0..len];
113 }
114 const full_len = init: {
115 if (CAllocator.supports_malloc_size) {
116 const s = alignedAllocSize(ptr);
117 assert(s >= len);
118 break :init s;
119 }
120 break :init len;
121 };
122 return ptr[0..mem.alignBackwardAnyAlign(full_len, len_align)];
108 return alignedAlloc(len, log2_align);
123109 }
124110
125111 fn resize(
126112 _: *anyopaque,
127113 buf: []u8,
128 buf_align: u29,
114 log2_buf_align: u8,
129115 new_len: usize,
130 len_align: u29,
131116 return_address: usize,
132 ) ?usize {
133 _ = buf_align;
117 ) bool {
118 _ = log2_buf_align;
134119 _ = return_address;
135120 if (new_len <= buf.len) {
136 return mem.alignAllocLen(buf.len, new_len, len_align);
121 return true;
137122 }
138123 if (CAllocator.supports_malloc_size) {
139124 const full_len = alignedAllocSize(buf.ptr);
140125 if (new_len <= full_len) {
141 return mem.alignAllocLen(full_len, new_len, len_align);
126 return true;
142127 }
143128 }
144 return null;
129 return false;
145130 }
146131
147132 fn free(
148133 _: *anyopaque,
149134 buf: []u8,
150 buf_align: u29,
135 log2_buf_align: u8,
151136 return_address: usize,
152137 ) void {
153 _ = buf_align;
138 _ = log2_buf_align;
154139 _ = return_address;
155140 alignedFree(buf.ptr);
156141 }
......@@ -187,40 +172,35 @@ const raw_c_allocator_vtable = Allocator.VTable{
187172fn rawCAlloc(
188173 _: *anyopaque,
189174 len: usize,
190 ptr_align: u29,
191 len_align: u29,
175 log2_ptr_align: u8,
192176 ret_addr: usize,
193) Allocator.Error![]u8 {
194 _ = len_align;
177) ?[*]u8 {
195178 _ = ret_addr;
196 assert(ptr_align <= @alignOf(std.c.max_align_t));
197 const ptr = @ptrCast([*]u8, c.malloc(len) orelse return error.OutOfMemory);
198 return ptr[0..len];
179 assert(log2_ptr_align <= comptime std.math.log2_int(usize, @alignOf(std.c.max_align_t)));
180 // TODO: change the language to make @ptrCast also do alignment cast
181 const ptr = @alignCast(@alignOf(std.c.max_align_t), c.malloc(len));
182 return @ptrCast(?[*]align(@alignOf(std.c.max_align_t)) u8, ptr);
199183}
200184
201185fn rawCResize(
202186 _: *anyopaque,
203187 buf: []u8,
204 old_align: u29,
188 log2_old_align: u8,
205189 new_len: usize,
206 len_align: u29,
207190 ret_addr: usize,
208) ?usize {
209 _ = old_align;
191) bool {
192 _ = log2_old_align;
210193 _ = ret_addr;
211 if (new_len <= buf.len) {
212 return mem.alignAllocLen(buf.len, new_len, len_align);
213 }
214 return null;
194 return new_len <= buf.len;
215195}
216196
217197fn rawCFree(
218198 _: *anyopaque,
219199 buf: []u8,
220 old_align: u29,
200 log2_old_align: u8,
221201 ret_addr: usize,
222202) void {
223 _ = old_align;
203 _ = log2_old_align;
224204 _ = ret_addr;
225205 c.free(buf.ptr);
226206}
......@@ -241,8 +221,8 @@ else
241221 };
242222
243223/// Verifies that the adjusted length will still map to the full length
244pub fn alignPageAllocLen(full_len: usize, len: usize, len_align: u29) usize {
245 const aligned_len = mem.alignAllocLen(full_len, len, len_align);
224pub fn alignPageAllocLen(full_len: usize, len: usize) usize {
225 const aligned_len = mem.alignAllocLen(full_len, len);
246226 assert(mem.alignForward(aligned_len, mem.page_size) == full_len);
247227 return aligned_len;
248228}
......@@ -257,115 +237,47 @@ const PageAllocator = struct {
257237 .free = free,
258238 };
259239
260 fn alloc(_: *anyopaque, n: usize, alignment: u29, len_align: u29, ra: usize) error{OutOfMemory}![]u8 {
240 fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 {
261241 _ = ra;
242 _ = log2_align;
262243 assert(n > 0);
263 if (n > maxInt(usize) - (mem.page_size - 1)) {
264 return error.OutOfMemory;
265 }
244 if (n > maxInt(usize) - (mem.page_size - 1)) return null;
266245 const aligned_len = mem.alignForward(n, mem.page_size);
267246
268247 if (builtin.os.tag == .windows) {
269248 const w = os.windows;
270
271 // Although officially it's at least aligned to page boundary,
272 // Windows is known to reserve pages on a 64K boundary. It's
273 // even more likely that the requested alignment is <= 64K than
274 // 4K, so we're just allocating blindly and hoping for the best.
275 // see https://devblogs.microsoft.com/oldnewthing/?p=42223
276249 const addr = w.VirtualAlloc(
277250 null,
278251 aligned_len,
279252 w.MEM_COMMIT | w.MEM_RESERVE,
280253 w.PAGE_READWRITE,
281 ) catch return error.OutOfMemory;
282
283 // If the allocation is sufficiently aligned, use it.
284 if (mem.isAligned(@ptrToInt(addr), alignment)) {
285 return @ptrCast([*]u8, addr)[0..alignPageAllocLen(aligned_len, n, len_align)];
286 }
287
288 // If it wasn't, actually do an explicitly aligned allocation.
289 w.VirtualFree(addr, 0, w.MEM_RELEASE);
290 const alloc_size = n + alignment - mem.page_size;
291
292 while (true) {
293 // Reserve a range of memory large enough to find a sufficiently
294 // aligned address.
295 const reserved_addr = w.VirtualAlloc(
296 null,
297 alloc_size,
298 w.MEM_RESERVE,
299 w.PAGE_NOACCESS,
300 ) catch return error.OutOfMemory;
301 const aligned_addr = mem.alignForward(@ptrToInt(reserved_addr), alignment);
302
303 // Release the reserved pages (not actually used).
304 w.VirtualFree(reserved_addr, 0, w.MEM_RELEASE);
305
306 // At this point, it is possible that another thread has
307 // obtained some memory space that will cause the next
308 // VirtualAlloc call to fail. To handle this, we will retry
309 // until it succeeds.
310 const ptr = w.VirtualAlloc(
311 @intToPtr(*anyopaque, aligned_addr),
312 aligned_len,
313 w.MEM_COMMIT | w.MEM_RESERVE,
314 w.PAGE_READWRITE,
315 ) catch continue;
316
317 return @ptrCast([*]u8, ptr)[0..alignPageAllocLen(aligned_len, n, len_align)];
318 }
254 ) catch return null;
255 return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, addr));
319256 }
320257
321 const max_drop_len = alignment - @min(alignment, mem.page_size);
322 const alloc_len = if (max_drop_len <= aligned_len - n)
323 aligned_len
324 else
325 mem.alignForward(aligned_len + max_drop_len, mem.page_size);
326258 const hint = @atomicLoad(@TypeOf(next_mmap_addr_hint), &next_mmap_addr_hint, .Unordered);
327259 const slice = os.mmap(
328260 hint,
329 alloc_len,
261 aligned_len,
330262 os.PROT.READ | os.PROT.WRITE,
331263 os.MAP.PRIVATE | os.MAP.ANONYMOUS,
332264 -1,
333265 0,
334 ) catch return error.OutOfMemory;
266 ) catch return null;
335267 assert(mem.isAligned(@ptrToInt(slice.ptr), mem.page_size));
336
337 const result_ptr = mem.alignPointer(slice.ptr, alignment) orelse
338 return error.OutOfMemory;
339
340 // Unmap the extra bytes that were only requested in order to guarantee
341 // that the range of memory we were provided had a proper alignment in
342 // it somewhere. The extra bytes could be at the beginning, or end, or both.
343 const drop_len = @ptrToInt(result_ptr) - @ptrToInt(slice.ptr);
344 if (drop_len != 0) {
345 os.munmap(slice[0..drop_len]);
346 }
347
348 // Unmap extra pages
349 const aligned_buffer_len = alloc_len - drop_len;
350 if (aligned_buffer_len > aligned_len) {
351 os.munmap(@alignCast(mem.page_size, result_ptr[aligned_len..aligned_buffer_len]));
352 }
353
354 const new_hint = @alignCast(mem.page_size, result_ptr + aligned_len);
268 const new_hint = @alignCast(mem.page_size, slice.ptr + aligned_len);
355269 _ = @cmpxchgStrong(@TypeOf(next_mmap_addr_hint), &next_mmap_addr_hint, hint, new_hint, .Monotonic, .Monotonic);
356
357 return result_ptr[0..alignPageAllocLen(aligned_len, n, len_align)];
270 return slice.ptr;
358271 }
359272
360273 fn resize(
361274 _: *anyopaque,
362275 buf_unaligned: []u8,
363 buf_align: u29,
276 log2_buf_align: u8,
364277 new_size: usize,
365 len_align: u29,
366278 return_address: usize,
367 ) ?usize {
368 _ = buf_align;
279 ) bool {
280 _ = log2_buf_align;
369281 _ = return_address;
370282 const new_size_aligned = mem.alignForward(new_size, mem.page_size);
371283
......@@ -384,40 +296,40 @@ const PageAllocator = struct {
384296 w.MEM_DECOMMIT,
385297 );
386298 }
387 return alignPageAllocLen(new_size_aligned, new_size, len_align);
299 return true;
388300 }
389301 const old_size_aligned = mem.alignForward(buf_unaligned.len, mem.page_size);
390302 if (new_size_aligned <= old_size_aligned) {
391 return alignPageAllocLen(new_size_aligned, new_size, len_align);
303 return true;
392304 }
393 return null;
305 return false;
394306 }
395307
396308 const buf_aligned_len = mem.alignForward(buf_unaligned.len, mem.page_size);
397309 if (new_size_aligned == buf_aligned_len)
398 return alignPageAllocLen(new_size_aligned, new_size, len_align);
310 return true;
399311
400312 if (new_size_aligned < buf_aligned_len) {
401313 const ptr = @alignCast(mem.page_size, buf_unaligned.ptr + new_size_aligned);
402314 // TODO: if the next_mmap_addr_hint is within the unmapped range, update it
403315 os.munmap(ptr[0 .. buf_aligned_len - new_size_aligned]);
404 return alignPageAllocLen(new_size_aligned, new_size, len_align);
316 return true;
405317 }
406318
407319 // TODO: call mremap
408320 // TODO: if the next_mmap_addr_hint is within the remapped range, update it
409 return null;
321 return false;
410322 }
411323
412 fn free(_: *anyopaque, buf_unaligned: []u8, buf_align: u29, return_address: usize) void {
413 _ = buf_align;
324 fn free(_: *anyopaque, slice: []u8, log2_buf_align: u8, return_address: usize) void {
325 _ = log2_buf_align;
414326 _ = return_address;
415327
416328 if (builtin.os.tag == .windows) {
417 os.windows.VirtualFree(buf_unaligned.ptr, 0, os.windows.MEM_RELEASE);
329 os.windows.VirtualFree(slice.ptr, 0, os.windows.MEM_RELEASE);
418330 } else {
419 const buf_aligned_len = mem.alignForward(buf_unaligned.len, mem.page_size);
420 const ptr = @alignCast(mem.page_size, buf_unaligned.ptr);
331 const buf_aligned_len = mem.alignForward(slice.len, mem.page_size);
332 const ptr = @alignCast(mem.page_size, slice.ptr);
421333 os.munmap(ptr[0..buf_aligned_len]);
422334 }
423335 }
......@@ -478,7 +390,7 @@ const WasmPageAllocator = struct {
478390 // Revisit if this is settled: https://github.com/ziglang/zig/issues/3806
479391 const not_found = std.math.maxInt(usize);
480392
481 fn useRecycled(self: FreeBlock, num_pages: usize, alignment: u29) usize {
393 fn useRecycled(self: FreeBlock, num_pages: usize, log2_align: u8) usize {
482394 @setCold(true);
483395 for (self.data) |segment, i| {
484396 const spills_into_next = @bitCast(i128, segment) < 0;
......@@ -492,7 +404,7 @@ const WasmPageAllocator = struct {
492404 while (j + count < self.totalPages() and self.getBit(j + count) == .free) {
493405 count += 1;
494406 const addr = j * mem.page_size;
495 if (count >= num_pages and mem.isAligned(addr, alignment)) {
407 if (count >= num_pages and mem.isAlignedLog2(addr, log2_align)) {
496408 self.setBits(j, num_pages, .used);
497409 return j;
498410 }
......@@ -521,31 +433,30 @@ const WasmPageAllocator = struct {
521433 return mem.alignForward(memsize, mem.page_size) / mem.page_size;
522434 }
523435
524 fn alloc(_: *anyopaque, len: usize, alignment: u29, len_align: u29, ra: usize) error{OutOfMemory}![]u8 {
436 fn alloc(_: *anyopaque, len: usize, log2_align: u8, ra: usize) ?[*]u8 {
525437 _ = ra;
526 if (len > maxInt(usize) - (mem.page_size - 1)) {
527 return error.OutOfMemory;
528 }
438 if (len > maxInt(usize) - (mem.page_size - 1)) return null;
529439 const page_count = nPages(len);
530 const page_idx = try allocPages(page_count, alignment);
531 return @intToPtr([*]u8, page_idx * mem.page_size)[0..alignPageAllocLen(page_count * mem.page_size, len, len_align)];
440 const page_idx = allocPages(page_count, log2_align) catch return null;
441 return @intToPtr([*]u8, page_idx * mem.page_size);
532442 }
533 fn allocPages(page_count: usize, alignment: u29) !usize {
443
444 fn allocPages(page_count: usize, log2_align: u8) !usize {
534445 {
535 const idx = conventional.useRecycled(page_count, alignment);
446 const idx = conventional.useRecycled(page_count, log2_align);
536447 if (idx != FreeBlock.not_found) {
537448 return idx;
538449 }
539450 }
540451
541 const idx = extended.useRecycled(page_count, alignment);
452 const idx = extended.useRecycled(page_count, log2_align);
542453 if (idx != FreeBlock.not_found) {
543454 return idx + extendedOffset();
544455 }
545456
546457 const next_page_idx = @wasmMemorySize(0);
547458 const next_page_addr = next_page_idx * mem.page_size;
548 const aligned_addr = mem.alignForward(next_page_addr, alignment);
459 const aligned_addr = mem.alignForwardLog2(next_page_addr, log2_align);
549460 const drop_page_count = @divExact(aligned_addr - next_page_addr, mem.page_size);
550461 const result = @wasmMemoryGrow(0, @intCast(u32, drop_page_count + page_count));
551462 if (result <= 0)
......@@ -573,7 +484,7 @@ const WasmPageAllocator = struct {
573484 // Since this is the first page being freed and we consume it, assume *nothing* is free.
574485 mem.set(u128, extended.data, PageStatus.none_free);
575486 }
576 const clamped_start = std.math.max(extendedOffset(), start);
487 const clamped_start = @max(extendedOffset(), start);
577488 extended.recycle(clamped_start - extendedOffset(), new_end - clamped_start);
578489 }
579490 }
......@@ -581,31 +492,30 @@ const WasmPageAllocator = struct {
581492 fn resize(
582493 _: *anyopaque,
583494 buf: []u8,
584 buf_align: u29,
495 log2_buf_align: u8,
585496 new_len: usize,
586 len_align: u29,
587497 return_address: usize,
588 ) ?usize {
589 _ = buf_align;
498 ) bool {
499 _ = log2_buf_align;
590500 _ = return_address;
591501 const aligned_len = mem.alignForward(buf.len, mem.page_size);
592 if (new_len > aligned_len) return null;
502 if (new_len > aligned_len) return false;
593503 const current_n = nPages(aligned_len);
594504 const new_n = nPages(new_len);
595505 if (new_n != current_n) {
596506 const base = nPages(@ptrToInt(buf.ptr));
597507 freePages(base + new_n, base + current_n);
598508 }
599 return alignPageAllocLen(new_n * mem.page_size, new_len, len_align);
509 return true;
600510 }
601511
602512 fn free(
603513 _: *anyopaque,
604514 buf: []u8,
605 buf_align: u29,
515 log2_buf_align: u8,
606516 return_address: usize,
607517 ) void {
608 _ = buf_align;
518 _ = log2_buf_align;
609519 _ = return_address;
610520 const aligned_len = mem.alignForward(buf.len, mem.page_size);
611521 const current_n = nPages(aligned_len);
......@@ -627,7 +537,14 @@ pub const HeapAllocator = switch (builtin.os.tag) {
627537 }
628538
629539 pub fn allocator(self: *HeapAllocator) Allocator {
630 return Allocator.init(self, alloc, resize, free);
540 return .{
541 .ptr = self,
542 .vtable = &.{
543 .alloc = alloc,
544 .resize = resize,
545 .free = free,
546 },
547 };
631548 }
632549
633550 pub fn deinit(self: *HeapAllocator) void {
......@@ -641,48 +558,42 @@ pub const HeapAllocator = switch (builtin.os.tag) {
641558 }
642559
643560 fn alloc(
644 self: *HeapAllocator,
561 ctx: *anyopaque,
645562 n: usize,
646 ptr_align: u29,
647 len_align: u29,
563 log2_ptr_align: u8,
648564 return_address: usize,
649 ) error{OutOfMemory}![]u8 {
565 ) ?[*]u8 {
650566 _ = return_address;
567 const self = @ptrCast(*HeapAllocator, @alignCast(@alignOf(HeapAllocator), ctx));
651568
569 const ptr_align = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align);
652570 const amt = n + ptr_align - 1 + @sizeOf(usize);
653571 const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, .SeqCst);
654572 const heap_handle = optional_heap_handle orelse blk: {
655573 const options = if (builtin.single_threaded) os.windows.HEAP_NO_SERIALIZE else 0;
656 const hh = os.windows.kernel32.HeapCreate(options, amt, 0) orelse return error.OutOfMemory;
574 const hh = os.windows.kernel32.HeapCreate(options, amt, 0) orelse return null;
657575 const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, .SeqCst, .SeqCst) orelse break :blk hh;
658576 os.windows.HeapDestroy(hh);
659577 break :blk other_hh.?; // can't be null because of the cmpxchg
660578 };
661 const ptr = os.windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
579 const ptr = os.windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return null;
662580 const root_addr = @ptrToInt(ptr);
663581 const aligned_addr = mem.alignForward(root_addr, ptr_align);
664 const return_len = init: {
665 if (len_align == 0) break :init n;
666 const full_len = os.windows.kernel32.HeapSize(heap_handle, 0, ptr);
667 assert(full_len != std.math.maxInt(usize));
668 assert(full_len >= amt);
669 break :init mem.alignBackwardAnyAlign(full_len - (aligned_addr - root_addr) - @sizeOf(usize), len_align);
670 };
671 const buf = @intToPtr([*]u8, aligned_addr)[0..return_len];
582 const buf = @intToPtr([*]u8, aligned_addr)[0..n];
672583 getRecordPtr(buf).* = root_addr;
673 return buf;
584 return buf.ptr;
674585 }
675586
676587 fn resize(
677 self: *HeapAllocator,
588 ctx: *anyopaque,
678589 buf: []u8,
679 buf_align: u29,
590 log2_buf_align: u8,
680591 new_size: usize,
681 len_align: u29,
682592 return_address: usize,
683 ) ?usize {
684 _ = buf_align;
593 ) bool {
594 _ = log2_buf_align;
685595 _ = return_address;
596 const self = @ptrCast(*HeapAllocator, @alignCast(@alignOf(HeapAllocator), ctx));
686597
687598 const root_addr = getRecordPtr(buf).*;
688599 const align_offset = @ptrToInt(buf.ptr) - root_addr;
......@@ -692,27 +603,21 @@ pub const HeapAllocator = switch (builtin.os.tag) {
692603 os.windows.HEAP_REALLOC_IN_PLACE_ONLY,
693604 @intToPtr(*anyopaque, root_addr),
694605 amt,
695 ) orelse return null;
606 ) orelse return false;
696607 assert(new_ptr == @intToPtr(*anyopaque, root_addr));
697 const return_len = init: {
698 if (len_align == 0) break :init new_size;
699 const full_len = os.windows.kernel32.HeapSize(self.heap_handle.?, 0, new_ptr);
700 assert(full_len != std.math.maxInt(usize));
701 assert(full_len >= amt);
702 break :init mem.alignBackwardAnyAlign(full_len - align_offset, len_align);
703 };
704 getRecordPtr(buf.ptr[0..return_len]).* = root_addr;
705 return return_len;
608 getRecordPtr(buf.ptr[0..new_size]).* = root_addr;
609 return true;
706610 }
707611
708612 fn free(
709 self: *HeapAllocator,
613 ctx: *anyopaque,
710614 buf: []u8,
711 buf_align: u29,
615 log2_buf_align: u8,
712616 return_address: usize,
713617 ) void {
714 _ = buf_align;
618 _ = log2_buf_align;
715619 _ = return_address;
620 const self = @ptrCast(*HeapAllocator, @alignCast(@alignOf(HeapAllocator), ctx));
716621 os.windows.HeapFree(self.heap_handle.?, 0, @intToPtr(*anyopaque, getRecordPtr(buf).*));
717622 }
718623 },
......@@ -742,18 +647,27 @@ pub const FixedBufferAllocator = struct {
742647
743648 /// *WARNING* using this at the same time as the interface returned by `threadSafeAllocator` is not thread safe
744649 pub fn allocator(self: *FixedBufferAllocator) Allocator {
745 return Allocator.init(self, alloc, resize, free);
650 return .{
651 .ptr = self,
652 .vtable = &.{
653 .alloc = alloc,
654 .resize = resize,
655 .free = free,
656 },
657 };
746658 }
747659
748660 /// Provides a lock free thread safe `Allocator` interface to the underlying `FixedBufferAllocator`
749661 /// *WARNING* using this at the same time as the interface returned by `allocator` is not thread safe
750662 pub fn threadSafeAllocator(self: *FixedBufferAllocator) Allocator {
751 return Allocator.init(
752 self,
753 threadSafeAlloc,
754 Allocator.NoResize(FixedBufferAllocator).noResize,
755 Allocator.NoOpFree(FixedBufferAllocator).noOpFree,
756 );
663 return .{
664 .ptr = self,
665 .vtable = &.{
666 .alloc = threadSafeAlloc,
667 .resize = Allocator.noResize,
668 .free = Allocator.noFree,
669 },
670 };
757671 }
758672
759673 pub fn ownsPtr(self: *FixedBufferAllocator, ptr: [*]u8) bool {
......@@ -771,59 +685,56 @@ pub const FixedBufferAllocator = struct {
771685 return buf.ptr + buf.len == self.buffer.ptr + self.end_index;
772686 }
773687
774 fn alloc(self: *FixedBufferAllocator, n: usize, ptr_align: u29, len_align: u29, ra: usize) ![]u8 {
775 _ = len_align;
688 fn alloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 {
689 const self = @ptrCast(*FixedBufferAllocator, @alignCast(@alignOf(FixedBufferAllocator), ctx));
776690 _ = ra;
777 const adjust_off = mem.alignPointerOffset(self.buffer.ptr + self.end_index, ptr_align) orelse
778 return error.OutOfMemory;
691 const ptr_align = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align);
692 const adjust_off = mem.alignPointerOffset(self.buffer.ptr + self.end_index, ptr_align) orelse return null;
779693 const adjusted_index = self.end_index + adjust_off;
780694 const new_end_index = adjusted_index + n;
781 if (new_end_index > self.buffer.len) {
782 return error.OutOfMemory;
783 }
784 const result = self.buffer[adjusted_index..new_end_index];
695 if (new_end_index > self.buffer.len) return null;
785696 self.end_index = new_end_index;
786
787 return result;
697 return self.buffer.ptr + adjusted_index;
788698 }
789699
790700 fn resize(
791 self: *FixedBufferAllocator,
701 ctx: *anyopaque,
792702 buf: []u8,
793 buf_align: u29,
703 log2_buf_align: u8,
794704 new_size: usize,
795 len_align: u29,
796705 return_address: usize,
797 ) ?usize {
798 _ = buf_align;
706 ) bool {
707 const self = @ptrCast(*FixedBufferAllocator, @alignCast(@alignOf(FixedBufferAllocator), ctx));
708 _ = log2_buf_align;
799709 _ = return_address;
800710 assert(self.ownsSlice(buf)); // sanity check
801711
802712 if (!self.isLastAllocation(buf)) {
803 if (new_size > buf.len) return null;
804 return mem.alignAllocLen(buf.len, new_size, len_align);
713 if (new_size > buf.len) return false;
714 return true;
805715 }
806716
807717 if (new_size <= buf.len) {
808718 const sub = buf.len - new_size;
809719 self.end_index -= sub;
810 return mem.alignAllocLen(buf.len - sub, new_size, len_align);
720 return true;
811721 }
812722
813723 const add = new_size - buf.len;
814 if (add + self.end_index > self.buffer.len) return null;
724 if (add + self.end_index > self.buffer.len) return false;
815725
816726 self.end_index += add;
817 return new_size;
727 return true;
818728 }
819729
820730 fn free(
821 self: *FixedBufferAllocator,
731 ctx: *anyopaque,
822732 buf: []u8,
823 buf_align: u29,
733 log2_buf_align: u8,
824734 return_address: usize,
825735 ) void {
826 _ = buf_align;
736 const self = @ptrCast(*FixedBufferAllocator, @alignCast(@alignOf(FixedBufferAllocator), ctx));
737 _ = log2_buf_align;
827738 _ = return_address;
828739 assert(self.ownsSlice(buf)); // sanity check
829740
......@@ -832,19 +743,18 @@ pub const FixedBufferAllocator = struct {
832743 }
833744 }
834745
835 fn threadSafeAlloc(self: *FixedBufferAllocator, n: usize, ptr_align: u29, len_align: u29, ra: usize) ![]u8 {
836 _ = len_align;
746 fn threadSafeAlloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 {
747 const self = @ptrCast(*FixedBufferAllocator, @alignCast(@alignOf(FixedBufferAllocator), ctx));
837748 _ = ra;
749 const ptr_align = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align);
838750 var end_index = @atomicLoad(usize, &self.end_index, .SeqCst);
839751 while (true) {
840 const adjust_off = mem.alignPointerOffset(self.buffer.ptr + end_index, ptr_align) orelse
841 return error.OutOfMemory;
752 const adjust_off = mem.alignPointerOffset(self.buffer.ptr + end_index, ptr_align) orelse return null;
842753 const adjusted_index = end_index + adjust_off;
843754 const new_end_index = adjusted_index + n;
844 if (new_end_index > self.buffer.len) {
845 return error.OutOfMemory;
846 }
847 end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, .SeqCst, .SeqCst) orelse return self.buffer[adjusted_index..new_end_index];
755 if (new_end_index > self.buffer.len) return null;
756 end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, .SeqCst, .SeqCst) orelse
757 return self.buffer[adjusted_index..new_end_index].ptr;
848758 }
849759 }
850760
......@@ -878,48 +788,57 @@ pub fn StackFallbackAllocator(comptime size: usize) type {
878788 fallback_allocator: Allocator,
879789 fixed_buffer_allocator: FixedBufferAllocator,
880790
881 /// WARNING: This functions both fetches a `std.mem.Allocator` interface to this allocator *and* resets the internal buffer allocator
791 /// This function both fetches a `Allocator` interface to this
792 /// allocator *and* resets the internal buffer allocator.
882793 pub fn get(self: *Self) Allocator {
883794 self.fixed_buffer_allocator = FixedBufferAllocator.init(self.buffer[0..]);
884 return Allocator.init(self, alloc, resize, free);
795 return .{
796 .ptr = self,
797 .vtable = &.{
798 .alloc = alloc,
799 .resize = resize,
800 .free = free,
801 },
802 };
885803 }
886804
887805 fn alloc(
888 self: *Self,
806 ctx: *anyopaque,
889807 len: usize,
890 ptr_align: u29,
891 len_align: u29,
892 return_address: usize,
893 ) error{OutOfMemory}![]u8 {
894 return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, ptr_align, len_align, return_address) catch
895 return self.fallback_allocator.rawAlloc(len, ptr_align, len_align, return_address);
808 log2_ptr_align: u8,
809 ra: usize,
810 ) ?[*]u8 {
811 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
812 return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, log2_ptr_align, ra) orelse
813 return self.fallback_allocator.rawAlloc(len, log2_ptr_align, ra);
896814 }
897815
898816 fn resize(
899 self: *Self,
817 ctx: *anyopaque,
900818 buf: []u8,
901 buf_align: u29,
819 log2_buf_align: u8,
902820 new_len: usize,
903 len_align: u29,
904 return_address: usize,
905 ) ?usize {
821 ra: usize,
822 ) bool {
823 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
906824 if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
907 return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, buf_align, new_len, len_align, return_address);
825 return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, log2_buf_align, new_len, ra);
908826 } else {
909 return self.fallback_allocator.rawResize(buf, buf_align, new_len, len_align, return_address);
827 return self.fallback_allocator.rawResize(buf, log2_buf_align, new_len, ra);
910828 }
911829 }
912830
913831 fn free(
914 self: *Self,
832 ctx: *anyopaque,
915833 buf: []u8,
916 buf_align: u29,
917 return_address: usize,
834 log2_buf_align: u8,
835 ra: usize,
918836 ) void {
837 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
919838 if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
920 return FixedBufferAllocator.free(&self.fixed_buffer_allocator, buf, buf_align, return_address);
839 return FixedBufferAllocator.free(&self.fixed_buffer_allocator, buf, log2_buf_align, ra);
921840 } else {
922 return self.fallback_allocator.rawFree(buf, buf_align, return_address);
841 return self.fallback_allocator.rawFree(buf, log2_buf_align, ra);
923842 }
924843 }
925844 };
......@@ -987,11 +906,7 @@ test "PageAllocator" {
987906 }
988907
989908 if (builtin.os.tag == .windows) {
990 // Trying really large alignment. As mentionned in the implementation,
991 // VirtualAlloc returns 64K aligned addresses. We want to make sure
992 // PageAllocator works beyond that, as it's not tested by
993 // `testAllocatorLargeAlignment`.
994 const slice = try allocator.alignedAlloc(u8, 1 << 20, 128);
909 const slice = try allocator.alignedAlloc(u8, mem.page_size, 128);
995910 slice[0] = 0x12;
996911 slice[127] = 0x34;
997912 allocator.free(slice);
......@@ -1132,15 +1047,16 @@ pub fn testAllocator(base_allocator: mem.Allocator) !void {
11321047 allocator.destroy(item);
11331048 }
11341049
1135 slice = allocator.shrink(slice, 50);
1136 try testing.expect(slice.len == 50);
1137 slice = allocator.shrink(slice, 25);
1138 try testing.expect(slice.len == 25);
1139 slice = allocator.shrink(slice, 0);
1140 try testing.expect(slice.len == 0);
1141 slice = try allocator.realloc(slice, 10);
1142 try testing.expect(slice.len == 10);
1143
1050 if (allocator.resize(slice, 50)) {
1051 slice = slice[0..50];
1052 if (allocator.resize(slice, 25)) {
1053 slice = slice[0..25];
1054 try testing.expect(allocator.resize(slice, 0));
1055 slice = slice[0..0];
1056 slice = try allocator.realloc(slice, 10);
1057 try testing.expect(slice.len == 10);
1058 }
1059 }
11441060 allocator.free(slice);
11451061
11461062 // Zero-length allocation
......@@ -1151,7 +1067,7 @@ pub fn testAllocator(base_allocator: mem.Allocator) !void {
11511067 zero_bit_ptr.* = 0;
11521068 allocator.destroy(zero_bit_ptr);
11531069
1154 const oversize = try allocator.allocAdvanced(u32, null, 5, .at_least);
1070 const oversize = try allocator.alignedAlloc(u32, null, 5);
11551071 try testing.expect(oversize.len >= 5);
11561072 for (oversize) |*item| {
11571073 item.* = 0xDEADBEEF;
......@@ -1171,21 +1087,18 @@ pub fn testAllocatorAligned(base_allocator: mem.Allocator) !void {
11711087 // grow
11721088 slice = try allocator.realloc(slice, 100);
11731089 try testing.expect(slice.len == 100);
1174 // shrink
1175 slice = allocator.shrink(slice, 10);
1176 try testing.expect(slice.len == 10);
1177 // go to zero
1178 slice = allocator.shrink(slice, 0);
1179 try testing.expect(slice.len == 0);
1090 if (allocator.resize(slice, 10)) {
1091 slice = slice[0..10];
1092 }
1093 try testing.expect(allocator.resize(slice, 0));
1094 slice = slice[0..0];
11801095 // realloc from zero
11811096 slice = try allocator.realloc(slice, 100);
11821097 try testing.expect(slice.len == 100);
1183 // shrink with shrink
1184 slice = allocator.shrink(slice, 10);
1185 try testing.expect(slice.len == 10);
1186 // shrink to zero
1187 slice = allocator.shrink(slice, 0);
1188 try testing.expect(slice.len == 0);
1098 if (allocator.resize(slice, 10)) {
1099 slice = slice[0..10];
1100 }
1101 try testing.expect(allocator.resize(slice, 0));
11891102 }
11901103}
11911104
......@@ -1193,27 +1106,24 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {
11931106 var validationAllocator = mem.validationWrap(base_allocator);
11941107 const allocator = validationAllocator.allocator();
11951108
1196 //Maybe a platform's page_size is actually the same as or
1197 // very near usize?
1198 if (mem.page_size << 2 > maxInt(usize)) return;
1199
1200 const USizeShift = std.meta.Int(.unsigned, std.math.log2(@bitSizeOf(usize)));
1201 const large_align = @as(u29, mem.page_size << 2);
1109 const large_align: usize = mem.page_size / 2;
12021110
12031111 var align_mask: usize = undefined;
1204 _ = @shlWithOverflow(usize, ~@as(usize, 0), @as(USizeShift, @ctz(large_align)), &align_mask);
1112 _ = @shlWithOverflow(usize, ~@as(usize, 0), @as(Allocator.Log2Align, @ctz(large_align)), &align_mask);
12051113
12061114 var slice = try allocator.alignedAlloc(u8, large_align, 500);
12071115 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
12081116
1209 slice = allocator.shrink(slice, 100);
1210 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
1117 if (allocator.resize(slice, 100)) {
1118 slice = slice[0..100];
1119 }
12111120
12121121 slice = try allocator.realloc(slice, 5000);
12131122 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
12141123
1215 slice = allocator.shrink(slice, 10);
1216 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
1124 if (allocator.resize(slice, 10)) {
1125 slice = slice[0..10];
1126 }
12171127
12181128 slice = try allocator.realloc(slice, 20000);
12191129 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
......@@ -1248,8 +1158,7 @@ pub fn testAllocatorAlignedShrink(base_allocator: mem.Allocator) !void {
12481158 slice[0] = 0x12;
12491159 slice[60] = 0x34;
12501160
1251 // realloc to a smaller size but with a larger alignment
1252 slice = try allocator.reallocAdvanced(slice, mem.page_size * 32, alloc_size / 2, .exact);
1161 slice = try allocator.reallocAdvanced(slice, alloc_size / 2, 0);
12531162 try testing.expect(slice[0] == 0x12);
12541163 try testing.expect(slice[60] == 0x34);
12551164}
lib/std/heap/arena_allocator.zig+40-25
......@@ -24,7 +24,14 @@ pub const ArenaAllocator = struct {
2424 };
2525
2626 pub fn allocator(self: *ArenaAllocator) Allocator {
27 return Allocator.init(self, alloc, resize, free);
27 return .{
28 .ptr = self,
29 .vtable = &.{
30 .alloc = alloc,
31 .resize = resize,
32 .free = free,
33 },
34 };
2835 }
2936
3037 const BufNode = std.SinglyLinkedList([]u8).Node;
......@@ -43,14 +50,16 @@ pub const ArenaAllocator = struct {
4350 }
4451 }
4552
46 fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode {
53 fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) ?*BufNode {
4754 const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
4855 const big_enough_len = prev_len + actual_min_size;
4956 const len = big_enough_len + big_enough_len / 2;
50 const buf = try self.child_allocator.rawAlloc(len, @alignOf(BufNode), 1, @returnAddress());
51 const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), buf.ptr));
57 const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode));
58 const ptr = self.child_allocator.rawAlloc(len, log2_align, @returnAddress()) orelse
59 return null;
60 const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), ptr));
5261 buf_node.* = BufNode{
53 .data = buf,
62 .data = ptr[0..len],
5463 .next = null,
5564 };
5665 self.state.buffer_list.prepend(buf_node);
......@@ -58,11 +67,15 @@ pub const ArenaAllocator = struct {
5867 return buf_node;
5968 }
6069
61 fn alloc(self: *ArenaAllocator, n: usize, ptr_align: u29, len_align: u29, ra: usize) ![]u8 {
62 _ = len_align;
70 fn alloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 {
71 const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
6372 _ = ra;
6473
65 var cur_node = if (self.state.buffer_list.first) |first_node| first_node else try self.createNode(0, n + ptr_align);
74 const ptr_align = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align);
75 var cur_node = if (self.state.buffer_list.first) |first_node|
76 first_node
77 else
78 (self.createNode(0, n + ptr_align) orelse return null);
6679 while (true) {
6780 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
6881 const addr = @ptrToInt(cur_buf.ptr) + self.state.end_index;
......@@ -73,46 +86,48 @@ pub const ArenaAllocator = struct {
7386 if (new_end_index <= cur_buf.len) {
7487 const result = cur_buf[adjusted_index..new_end_index];
7588 self.state.end_index = new_end_index;
76 return result;
89 return result.ptr;
7790 }
7891
7992 const bigger_buf_size = @sizeOf(BufNode) + new_end_index;
80 // Try to grow the buffer in-place
81 cur_node.data = self.child_allocator.resize(cur_node.data, bigger_buf_size) orelse {
93 if (self.child_allocator.resize(cur_node.data, bigger_buf_size)) {
94 cur_node.data.len = bigger_buf_size;
95 } else {
8296 // Allocate a new node if that's not possible
83 cur_node = try self.createNode(cur_buf.len, n + ptr_align);
84 continue;
85 };
97 cur_node = self.createNode(cur_buf.len, n + ptr_align) orelse return null;
98 }
8699 }
87100 }
88101
89 fn resize(self: *ArenaAllocator, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize {
90 _ = buf_align;
91 _ = len_align;
102 fn resize(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, new_len: usize, ret_addr: usize) bool {
103 const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
104 _ = log2_buf_align;
92105 _ = ret_addr;
93106
94 const cur_node = self.state.buffer_list.first orelse return null;
107 const cur_node = self.state.buffer_list.first orelse return false;
95108 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
96109 if (@ptrToInt(cur_buf.ptr) + self.state.end_index != @ptrToInt(buf.ptr) + buf.len) {
97 if (new_len > buf.len) return null;
98 return new_len;
110 if (new_len > buf.len) return false;
111 return true;
99112 }
100113
101114 if (buf.len >= new_len) {
102115 self.state.end_index -= buf.len - new_len;
103 return new_len;
116 return true;
104117 } else if (cur_buf.len - self.state.end_index >= new_len - buf.len) {
105118 self.state.end_index += new_len - buf.len;
106 return new_len;
119 return true;
107120 } else {
108 return null;
121 return false;
109122 }
110123 }
111124
112 fn free(self: *ArenaAllocator, buf: []u8, buf_align: u29, ret_addr: usize) void {
113 _ = buf_align;
125 fn free(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, ret_addr: usize) void {
126 _ = log2_buf_align;
114127 _ = ret_addr;
115128
129 const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
130
116131 const cur_node = self.state.buffer_list.first orelse return;
117132 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
118133
lib/std/heap/general_purpose_allocator.zig+81-57
......@@ -199,7 +199,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
199199 requested_size: if (config.enable_memory_limit) usize else void,
200200 stack_addresses: [trace_n][stack_n]usize,
201201 freed: if (config.retain_metadata) bool else void,
202 ptr_align: if (config.never_unmap and config.retain_metadata) u29 else void,
202 log2_ptr_align: if (config.never_unmap and config.retain_metadata) u8 else void,
203203
204204 const trace_n = if (config.retain_metadata) traces_per_slot else 1;
205205
......@@ -271,7 +271,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
271271 };
272272
273273 pub fn allocator(self: *Self) Allocator {
274 return Allocator.init(self, alloc, resize, free);
274 return .{
275 .ptr = self,
276 .vtable = &.{
277 .alloc = alloc,
278 .resize = resize,
279 .free = free,
280 },
281 };
275282 }
276283
277284 fn bucketStackTrace(
......@@ -379,7 +386,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
379386 var it = self.large_allocations.iterator();
380387 while (it.next()) |large| {
381388 if (large.value_ptr.freed) {
382 self.backing_allocator.rawFree(large.value_ptr.bytes, large.value_ptr.ptr_align, @returnAddress());
389 self.backing_allocator.rawFree(large.value_ptr.bytes, large.value_ptr.log2_ptr_align, @returnAddress());
383390 }
384391 }
385392 }
......@@ -504,11 +511,10 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
504511 fn resizeLarge(
505512 self: *Self,
506513 old_mem: []u8,
507 old_align: u29,
514 log2_old_align: u8,
508515 new_size: usize,
509 len_align: u29,
510516 ret_addr: usize,
511 ) ?usize {
517 ) bool {
512518 const entry = self.large_allocations.getEntry(@ptrToInt(old_mem.ptr)) orelse {
513519 if (config.safety) {
514520 @panic("Invalid free");
......@@ -541,24 +547,26 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
541547 });
542548 }
543549
544 // Do memory limit accounting with requested sizes rather than what backing_allocator returns
545 // because if we want to return error.OutOfMemory, we have to leave allocation untouched, and
546 // that is impossible to guarantee after calling backing_allocator.rawResize.
550 // Do memory limit accounting with requested sizes rather than what
551 // backing_allocator returns because if we want to return
552 // error.OutOfMemory, we have to leave allocation untouched, and
553 // that is impossible to guarantee after calling
554 // backing_allocator.rawResize.
547555 const prev_req_bytes = self.total_requested_bytes;
548556 if (config.enable_memory_limit) {
549557 const new_req_bytes = prev_req_bytes + new_size - entry.value_ptr.requested_size;
550558 if (new_req_bytes > prev_req_bytes and new_req_bytes > self.requested_memory_limit) {
551 return null;
559 return false;
552560 }
553561 self.total_requested_bytes = new_req_bytes;
554562 }
555563
556 const result_len = self.backing_allocator.rawResize(old_mem, old_align, new_size, len_align, ret_addr) orelse {
564 if (!self.backing_allocator.rawResize(old_mem, log2_old_align, new_size, ret_addr)) {
557565 if (config.enable_memory_limit) {
558566 self.total_requested_bytes = prev_req_bytes;
559567 }
560 return null;
561 };
568 return false;
569 }
562570
563571 if (config.enable_memory_limit) {
564572 entry.value_ptr.requested_size = new_size;
......@@ -569,9 +577,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
569577 old_mem.len, old_mem.ptr, new_size,
570578 });
571579 }
572 entry.value_ptr.bytes = old_mem.ptr[0..result_len];
580 entry.value_ptr.bytes = old_mem.ptr[0..new_size];
573581 entry.value_ptr.captureStackTrace(ret_addr, .alloc);
574 return result_len;
582 return true;
575583 }
576584
577585 /// This function assumes the object is in the large object storage regardless
......@@ -579,7 +587,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
579587 fn freeLarge(
580588 self: *Self,
581589 old_mem: []u8,
582 old_align: u29,
590 log2_old_align: u8,
583591 ret_addr: usize,
584592 ) void {
585593 const entry = self.large_allocations.getEntry(@ptrToInt(old_mem.ptr)) orelse {
......@@ -615,7 +623,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
615623 }
616624
617625 if (!config.never_unmap) {
618 self.backing_allocator.rawFree(old_mem, old_align, ret_addr);
626 self.backing_allocator.rawFree(old_mem, log2_old_align, ret_addr);
619627 }
620628
621629 if (config.enable_memory_limit) {
......@@ -639,21 +647,22 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
639647 }
640648
641649 fn resize(
642 self: *Self,
650 ctx: *anyopaque,
643651 old_mem: []u8,
644 old_align: u29,
652 log2_old_align_u8: u8,
645653 new_size: usize,
646 len_align: u29,
647654 ret_addr: usize,
648 ) ?usize {
655 ) bool {
656 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
657 const log2_old_align = @intCast(Allocator.Log2Align, log2_old_align_u8);
649658 self.mutex.lock();
650659 defer self.mutex.unlock();
651660
652661 assert(old_mem.len != 0);
653662
654 const aligned_size = math.max(old_mem.len, old_align);
663 const aligned_size = @max(old_mem.len, @as(usize, 1) << log2_old_align);
655664 if (aligned_size > largest_bucket_object_size) {
656 return self.resizeLarge(old_mem, old_align, new_size, len_align, ret_addr);
665 return self.resizeLarge(old_mem, log2_old_align, new_size, ret_addr);
657666 }
658667 const size_class_hint = math.ceilPowerOfTwoAssert(usize, aligned_size);
659668
......@@ -678,7 +687,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
678687 }
679688 }
680689 }
681 return self.resizeLarge(old_mem, old_align, new_size, len_align, ret_addr);
690 return self.resizeLarge(old_mem, log2_old_align, new_size, ret_addr);
682691 };
683692 const byte_offset = @ptrToInt(old_mem.ptr) - @ptrToInt(bucket.page);
684693 const slot_index = @intCast(SlotIndex, byte_offset / size_class);
......@@ -700,12 +709,12 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
700709 if (config.enable_memory_limit) {
701710 const new_req_bytes = prev_req_bytes + new_size - old_mem.len;
702711 if (new_req_bytes > prev_req_bytes and new_req_bytes > self.requested_memory_limit) {
703 return null;
712 return false;
704713 }
705714 self.total_requested_bytes = new_req_bytes;
706715 }
707716
708 const new_aligned_size = math.max(new_size, old_align);
717 const new_aligned_size = @max(new_size, @as(usize, 1) << log2_old_align);
709718 const new_size_class = math.ceilPowerOfTwoAssert(usize, new_aligned_size);
710719 if (new_size_class <= size_class) {
711720 if (old_mem.len > new_size) {
......@@ -716,29 +725,31 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
716725 old_mem.len, old_mem.ptr, new_size,
717726 });
718727 }
719 return new_size;
728 return true;
720729 }
721730
722731 if (config.enable_memory_limit) {
723732 self.total_requested_bytes = prev_req_bytes;
724733 }
725 return null;
734 return false;
726735 }
727736
728737 fn free(
729 self: *Self,
738 ctx: *anyopaque,
730739 old_mem: []u8,
731 old_align: u29,
740 log2_old_align_u8: u8,
732741 ret_addr: usize,
733742 ) void {
743 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
744 const log2_old_align = @intCast(Allocator.Log2Align, log2_old_align_u8);
734745 self.mutex.lock();
735746 defer self.mutex.unlock();
736747
737748 assert(old_mem.len != 0);
738749
739 const aligned_size = math.max(old_mem.len, old_align);
750 const aligned_size = @max(old_mem.len, @as(usize, 1) << log2_old_align);
740751 if (aligned_size > largest_bucket_object_size) {
741 self.freeLarge(old_mem, old_align, ret_addr);
752 self.freeLarge(old_mem, log2_old_align, ret_addr);
742753 return;
743754 }
744755 const size_class_hint = math.ceilPowerOfTwoAssert(usize, aligned_size);
......@@ -764,7 +775,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
764775 }
765776 }
766777 }
767 self.freeLarge(old_mem, old_align, ret_addr);
778 self.freeLarge(old_mem, log2_old_align, ret_addr);
768779 return;
769780 };
770781 const byte_offset = @ptrToInt(old_mem.ptr) - @ptrToInt(bucket.page);
......@@ -846,18 +857,26 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
846857 return true;
847858 }
848859
849 fn alloc(self: *Self, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 {
860 fn alloc(ctx: *anyopaque, len: usize, log2_ptr_align: u8, ret_addr: usize) ?[*]u8 {
861 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
850862 self.mutex.lock();
851863 defer self.mutex.unlock();
864 if (!self.isAllocationAllowed(len)) return null;
865 return allocInner(self, len, @intCast(Allocator.Log2Align, log2_ptr_align), ret_addr) catch return null;
866 }
852867
853 if (!self.isAllocationAllowed(len)) {
854 return error.OutOfMemory;
855 }
856
857 const new_aligned_size = math.max(len, ptr_align);
868 fn allocInner(
869 self: *Self,
870 len: usize,
871 log2_ptr_align: Allocator.Log2Align,
872 ret_addr: usize,
873 ) Allocator.Error![*]u8 {
874 const new_aligned_size = @max(len, @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align));
858875 if (new_aligned_size > largest_bucket_object_size) {
859876 try self.large_allocations.ensureUnusedCapacity(self.backing_allocator, 1);
860 const slice = try self.backing_allocator.rawAlloc(len, ptr_align, len_align, ret_addr);
877 const ptr = self.backing_allocator.rawAlloc(len, log2_ptr_align, ret_addr) orelse
878 return error.OutOfMemory;
879 const slice = ptr[0..len];
861880
862881 const gop = self.large_allocations.getOrPutAssumeCapacity(@ptrToInt(slice.ptr));
863882 if (config.retain_metadata and !config.never_unmap) {
......@@ -873,14 +892,14 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
873892 if (config.retain_metadata) {
874893 gop.value_ptr.freed = false;
875894 if (config.never_unmap) {
876 gop.value_ptr.ptr_align = ptr_align;
895 gop.value_ptr.log2_ptr_align = log2_ptr_align;
877896 }
878897 }
879898
880899 if (config.verbose_log) {
881900 log.info("large alloc {d} bytes at {*}", .{ slice.len, slice.ptr });
882901 }
883 return slice;
902 return slice.ptr;
884903 }
885904
886905 const new_size_class = math.ceilPowerOfTwoAssert(usize, new_aligned_size);
......@@ -888,15 +907,15 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
888907 if (config.verbose_log) {
889908 log.info("small alloc {d} bytes at {*}", .{ len, ptr });
890909 }
891 return ptr[0..len];
910 return ptr;
892911 }
893912
894913 fn createBucket(self: *Self, size_class: usize, bucket_index: usize) Error!*BucketHeader {
895 const page = try self.backing_allocator.allocAdvanced(u8, page_size, page_size, .exact);
914 const page = try self.backing_allocator.alignedAlloc(u8, page_size, page_size);
896915 errdefer self.backing_allocator.free(page);
897916
898917 const bucket_size = bucketSize(size_class);
899 const bucket_bytes = try self.backing_allocator.allocAdvanced(u8, @alignOf(BucketHeader), bucket_size, .exact);
918 const bucket_bytes = try self.backing_allocator.alignedAlloc(u8, @alignOf(BucketHeader), bucket_size);
900919 const ptr = @ptrCast(*BucketHeader, bucket_bytes.ptr);
901920 ptr.* = BucketHeader{
902921 .prev = ptr,
......@@ -1011,13 +1030,15 @@ test "shrink" {
10111030
10121031 mem.set(u8, slice, 0x11);
10131032
1014 slice = allocator.shrink(slice, 17);
1033 try std.testing.expect(allocator.resize(slice, 17));
1034 slice = slice[0..17];
10151035
10161036 for (slice) |b| {
10171037 try std.testing.expect(b == 0x11);
10181038 }
10191039
1020 slice = allocator.shrink(slice, 16);
1040 try std.testing.expect(allocator.resize(slice, 16));
1041 slice = slice[0..16];
10211042
10221043 for (slice) |b| {
10231044 try std.testing.expect(b == 0x11);
......@@ -1069,11 +1090,13 @@ test "shrink large object to large object" {
10691090 slice[0] = 0x12;
10701091 slice[60] = 0x34;
10711092
1072 slice = allocator.resize(slice, page_size * 2 + 1) orelse return;
1093 if (!allocator.resize(slice, page_size * 2 + 1)) return;
1094 slice = slice.ptr[0 .. page_size * 2 + 1];
10731095 try std.testing.expect(slice[0] == 0x12);
10741096 try std.testing.expect(slice[60] == 0x34);
10751097
1076 slice = allocator.shrink(slice, page_size * 2 + 1);
1098 try std.testing.expect(allocator.resize(slice, page_size * 2 + 1));
1099 slice = slice[0 .. page_size * 2 + 1];
10771100 try std.testing.expect(slice[0] == 0x12);
10781101 try std.testing.expect(slice[60] == 0x34);
10791102
......@@ -1113,7 +1136,7 @@ test "shrink large object to large object with larger alignment" {
11131136 slice[0] = 0x12;
11141137 slice[60] = 0x34;
11151138
1116 slice = try allocator.reallocAdvanced(slice, big_alignment, alloc_size / 2, .exact);
1139 slice = try allocator.reallocAdvanced(slice, big_alignment, alloc_size / 2);
11171140 try std.testing.expect(slice[0] == 0x12);
11181141 try std.testing.expect(slice[60] == 0x34);
11191142}
......@@ -1182,15 +1205,15 @@ test "realloc large object to larger alignment" {
11821205 slice[0] = 0x12;
11831206 slice[16] = 0x34;
11841207
1185 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 100, .exact);
1208 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 100);
11861209 try std.testing.expect(slice[0] == 0x12);
11871210 try std.testing.expect(slice[16] == 0x34);
11881211
1189 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 25, .exact);
1212 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 25);
11901213 try std.testing.expect(slice[0] == 0x12);
11911214 try std.testing.expect(slice[16] == 0x34);
11921215
1193 slice = try allocator.reallocAdvanced(slice, big_alignment, page_size * 2 + 100, .exact);
1216 slice = try allocator.reallocAdvanced(slice, big_alignment, page_size * 2 + 100);
11941217 try std.testing.expect(slice[0] == 0x12);
11951218 try std.testing.expect(slice[16] == 0x34);
11961219}
......@@ -1208,7 +1231,8 @@ test "large object shrinks to small but allocation fails during shrink" {
12081231
12091232 // Next allocation will fail in the backing allocator of the GeneralPurposeAllocator
12101233
1211 slice = allocator.shrink(slice, 4);
1234 try std.testing.expect(allocator.resize(slice, 4));
1235 slice = slice[0..4];
12121236 try std.testing.expect(slice[0] == 0x12);
12131237 try std.testing.expect(slice[3] == 0x34);
12141238}
......@@ -1296,10 +1320,10 @@ test "bug 9995 fix, large allocs count requested size not backing size" {
12961320 var gpa = GeneralPurposeAllocator(.{ .enable_memory_limit = true }){};
12971321 const allocator = gpa.allocator();
12981322
1299 var buf = try allocator.allocAdvanced(u8, 1, page_size + 1, .at_least);
1323 var buf = try allocator.alignedAlloc(u8, 1, page_size + 1);
13001324 try std.testing.expect(gpa.total_requested_bytes == page_size + 1);
1301 buf = try allocator.reallocAtLeast(buf, 1);
1325 buf = try allocator.realloc(buf, 1);
13021326 try std.testing.expect(gpa.total_requested_bytes == 1);
1303 buf = try allocator.reallocAtLeast(buf, 2);
1327 buf = try allocator.realloc(buf, 2);
13041328 try std.testing.expect(gpa.total_requested_bytes == 2);
13051329}
lib/std/heap/log_to_writer_allocator.zig+29-21
......@@ -18,60 +18,68 @@ pub fn LogToWriterAllocator(comptime Writer: type) type {
1818 }
1919
2020 pub fn allocator(self: *Self) Allocator {
21 return Allocator.init(self, alloc, resize, free);
21 return .{
22 .ptr = self,
23 .vtable = &.{
24 .alloc = alloc,
25 .resize = resize,
26 .free = free,
27 },
28 };
2229 }
2330
2431 fn alloc(
25 self: *Self,
32 ctx: *anyopaque,
2633 len: usize,
27 ptr_align: u29,
28 len_align: u29,
34 log2_ptr_align: u8,
2935 ra: usize,
30 ) error{OutOfMemory}![]u8 {
36 ) ?[*]u8 {
37 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
3138 self.writer.print("alloc : {}", .{len}) catch {};
32 const result = self.parent_allocator.rawAlloc(len, ptr_align, len_align, ra);
33 if (result) |_| {
39 const result = self.parent_allocator.rawAlloc(len, log2_ptr_align, ra);
40 if (result != null) {
3441 self.writer.print(" success!\n", .{}) catch {};
35 } else |_| {
42 } else {
3643 self.writer.print(" failure!\n", .{}) catch {};
3744 }
3845 return result;
3946 }
4047
4148 fn resize(
42 self: *Self,
49 ctx: *anyopaque,
4350 buf: []u8,
44 buf_align: u29,
51 log2_buf_align: u8,
4552 new_len: usize,
46 len_align: u29,
4753 ra: usize,
48 ) ?usize {
54 ) bool {
55 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
4956 if (new_len <= buf.len) {
5057 self.writer.print("shrink: {} to {}\n", .{ buf.len, new_len }) catch {};
5158 } else {
5259 self.writer.print("expand: {} to {}", .{ buf.len, new_len }) catch {};
5360 }
5461
55 if (self.parent_allocator.rawResize(buf, buf_align, new_len, len_align, ra)) |resized_len| {
62 if (self.parent_allocator.rawResize(buf, log2_buf_align, new_len, ra)) {
5663 if (new_len > buf.len) {
5764 self.writer.print(" success!\n", .{}) catch {};
5865 }
59 return resized_len;
66 return true;
6067 }
6168
6269 std.debug.assert(new_len > buf.len);
6370 self.writer.print(" failure!\n", .{}) catch {};
64 return null;
71 return false;
6572 }
6673
6774 fn free(
68 self: *Self,
75 ctx: *anyopaque,
6976 buf: []u8,
70 buf_align: u29,
77 log2_buf_align: u8,
7178 ra: usize,
7279 ) void {
80 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
7381 self.writer.print("free : {}\n", .{buf.len}) catch {};
74 self.parent_allocator.rawFree(buf, buf_align, ra);
82 self.parent_allocator.rawFree(buf, log2_buf_align, ra);
7583 }
7684 };
7785}
......@@ -95,9 +103,9 @@ test "LogToWriterAllocator" {
95103 const allocator = allocator_state.allocator();
96104
97105 var a = try allocator.alloc(u8, 10);
98 a = allocator.shrink(a, 5);
99 try std.testing.expect(a.len == 5);
100 try std.testing.expect(allocator.resize(a, 20) == null);
106 try std.testing.expect(allocator.resize(a, 5));
107 a = a[0..5];
108 try std.testing.expect(!allocator.resize(a, 20));
101109 allocator.free(a);
102110
103111 try std.testing.expectEqualSlices(u8,
lib/std/heap/logging_allocator.zig+36-28
......@@ -33,7 +33,14 @@ pub fn ScopedLoggingAllocator(
3333 }
3434
3535 pub fn allocator(self: *Self) Allocator {
36 return Allocator.init(self, alloc, resize, free);
36 return .{
37 .ptr = self,
38 .vtable = &.{
39 .alloc = alloc,
40 .resize = resize,
41 .free = free,
42 },
43 };
3744 }
3845
3946 // This function is required as the `std.log.log` function is not public
......@@ -47,71 +54,72 @@ pub fn ScopedLoggingAllocator(
4754 }
4855
4956 fn alloc(
50 self: *Self,
57 ctx: *anyopaque,
5158 len: usize,
52 ptr_align: u29,
53 len_align: u29,
59 log2_ptr_align: u8,
5460 ra: usize,
55 ) error{OutOfMemory}![]u8 {
56 const result = self.parent_allocator.rawAlloc(len, ptr_align, len_align, ra);
57 if (result) |_| {
61 ) ?[*]u8 {
62 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
63 const result = self.parent_allocator.rawAlloc(len, log2_ptr_align, ra);
64 if (result != null) {
5865 logHelper(
5966 success_log_level,
60 "alloc - success - len: {}, ptr_align: {}, len_align: {}",
61 .{ len, ptr_align, len_align },
67 "alloc - success - len: {}, ptr_align: {}",
68 .{ len, log2_ptr_align },
6269 );
63 } else |err| {
70 } else {
6471 logHelper(
6572 failure_log_level,
66 "alloc - failure: {s} - len: {}, ptr_align: {}, len_align: {}",
67 .{ @errorName(err), len, ptr_align, len_align },
73 "alloc - failure: OutOfMemory - len: {}, ptr_align: {}",
74 .{ len, log2_ptr_align },
6875 );
6976 }
7077 return result;
7178 }
7279
7380 fn resize(
74 self: *Self,
81 ctx: *anyopaque,
7582 buf: []u8,
76 buf_align: u29,
83 log2_buf_align: u8,
7784 new_len: usize,
78 len_align: u29,
7985 ra: usize,
80 ) ?usize {
81 if (self.parent_allocator.rawResize(buf, buf_align, new_len, len_align, ra)) |resized_len| {
86 ) bool {
87 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
88 if (self.parent_allocator.rawResize(buf, log2_buf_align, new_len, ra)) {
8289 if (new_len <= buf.len) {
8390 logHelper(
8491 success_log_level,
85 "shrink - success - {} to {}, len_align: {}, buf_align: {}",
86 .{ buf.len, new_len, len_align, buf_align },
92 "shrink - success - {} to {}, buf_align: {}",
93 .{ buf.len, new_len, log2_buf_align },
8794 );
8895 } else {
8996 logHelper(
9097 success_log_level,
91 "expand - success - {} to {}, len_align: {}, buf_align: {}",
92 .{ buf.len, new_len, len_align, buf_align },
98 "expand - success - {} to {}, buf_align: {}",
99 .{ buf.len, new_len, log2_buf_align },
93100 );
94101 }
95102
96 return resized_len;
103 return true;
97104 }
98105
99106 std.debug.assert(new_len > buf.len);
100107 logHelper(
101108 failure_log_level,
102 "expand - failure - {} to {}, len_align: {}, buf_align: {}",
103 .{ buf.len, new_len, len_align, buf_align },
109 "expand - failure - {} to {}, buf_align: {}",
110 .{ buf.len, new_len, log2_buf_align },
104111 );
105 return null;
112 return false;
106113 }
107114
108115 fn free(
109 self: *Self,
116 ctx: *anyopaque,
110117 buf: []u8,
111 buf_align: u29,
118 log2_buf_align: u8,
112119 ra: usize,
113120 ) void {
114 self.parent_allocator.rawFree(buf, buf_align, ra);
121 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
122 self.parent_allocator.rawFree(buf, log2_buf_align, ra);
115123 logHelper(success_log_level, "free - len: {}", .{buf.len});
116124 }
117125 };
lib/std/io/reader.zig+2-2
......@@ -176,11 +176,11 @@ pub fn Reader(
176176 error.EndOfStream => if (array_list.items.len == 0) {
177177 return null;
178178 } else {
179 return array_list.toOwnedSlice();
179 return try array_list.toOwnedSlice();
180180 },
181181 else => |e| return e,
182182 };
183 return array_list.toOwnedSlice();
183 return try array_list.toOwnedSlice();
184184 }
185185
186186 /// Reads from the stream until specified byte is found. If the buffer is not
lib/std/json.zig+2-4
......@@ -1668,12 +1668,10 @@ fn parseInternal(
16681668
16691669 if (ptrInfo.sentinel) |some| {
16701670 const sentinel_value = @ptrCast(*align(1) const ptrInfo.child, some).*;
1671 try arraylist.append(sentinel_value);
1672 const output = arraylist.toOwnedSlice();
1673 return output[0 .. output.len - 1 :sentinel_value];
1671 return try arraylist.toOwnedSliceSentinel(sentinel_value);
16741672 }
16751673
1676 return arraylist.toOwnedSlice();
1674 return try arraylist.toOwnedSlice();
16771675 },
16781676 .String => |stringToken| {
16791677 if (ptrInfo.child != u8) return error.UnexpectedToken;
lib/std/math/big/int.zig+29-1
......@@ -2148,7 +2148,7 @@ pub const Const = struct {
21482148 const limbs = try allocator.alloc(Limb, calcToStringLimbsBufferLen(self.limbs.len, base));
21492149 defer allocator.free(limbs);
21502150
2151 return allocator.shrink(string, self.toString(string, base, case, limbs));
2151 return allocator.realloc(string, self.toString(string, base, case, limbs));
21522152 }
21532153
21542154 /// Converts self to a string in the requested base.
......@@ -2376,6 +2376,34 @@ pub const Const = struct {
23762376 pub fn eq(a: Const, b: Const) bool {
23772377 return order(a, b) == .eq;
23782378 }
2379
2380 pub fn clz(a: Const, bits: Limb) Limb {
2381 // Limbs are stored in little-endian order but we need
2382 // to iterate big-endian.
2383 var total_limb_lz: Limb = 0;
2384 var i: usize = a.limbs.len;
2385 const bits_per_limb = @sizeOf(Limb) * 8;
2386 while (i != 0) {
2387 i -= 1;
2388 const limb = a.limbs[i];
2389 const this_limb_lz = @clz(limb);
2390 total_limb_lz += this_limb_lz;
2391 if (this_limb_lz != bits_per_limb) break;
2392 }
2393 const total_limb_bits = a.limbs.len * bits_per_limb;
2394 return total_limb_lz + bits - total_limb_bits;
2395 }
2396
2397 pub fn ctz(a: Const) Limb {
2398 // Limbs are stored in little-endian order.
2399 var result: Limb = 0;
2400 for (a.limbs) |limb| {
2401 const limb_tz = @ctz(limb);
2402 result += limb_tz;
2403 if (limb_tz != @sizeOf(Limb) * 8) break;
2404 }
2405 return result;
2406 }
23792407};
23802408
23812409/// An arbitrary-precision big integer along with an allocator which manages the memory.
lib/std/mem.zig+50-57
......@@ -47,7 +47,14 @@ pub fn ValidationAllocator(comptime T: type) type {
4747 }
4848
4949 pub fn allocator(self: *Self) Allocator {
50 return Allocator.init(self, alloc, resize, free);
50 return .{
51 .ptr = self,
52 .vtable = &.{
53 .alloc = alloc,
54 .resize = resize,
55 .free = free,
56 },
57 };
5158 }
5259
5360 fn getUnderlyingAllocatorPtr(self: *Self) Allocator {
......@@ -56,72 +63,48 @@ pub fn ValidationAllocator(comptime T: type) type {
5663 }
5764
5865 pub fn alloc(
59 self: *Self,
66 ctx: *anyopaque,
6067 n: usize,
61 ptr_align: u29,
62 len_align: u29,
68 log2_ptr_align: u8,
6369 ret_addr: usize,
64 ) Allocator.Error![]u8 {
70 ) ?[*]u8 {
6571 assert(n > 0);
66 assert(mem.isValidAlign(ptr_align));
67 if (len_align != 0) {
68 assert(mem.isAlignedAnyAlign(n, len_align));
69 assert(n >= len_align);
70 }
71
72 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
7273 const underlying = self.getUnderlyingAllocatorPtr();
73 const result = try underlying.rawAlloc(n, ptr_align, len_align, ret_addr);
74 assert(mem.isAligned(@ptrToInt(result.ptr), ptr_align));
75 if (len_align == 0) {
76 assert(result.len == n);
77 } else {
78 assert(result.len >= n);
79 assert(mem.isAlignedAnyAlign(result.len, len_align));
80 }
74 const result = underlying.rawAlloc(n, log2_ptr_align, ret_addr) orelse
75 return null;
76 assert(mem.isAlignedLog2(@ptrToInt(result), log2_ptr_align));
8177 return result;
8278 }
8379
8480 pub fn resize(
85 self: *Self,
81 ctx: *anyopaque,
8682 buf: []u8,
87 buf_align: u29,
83 log2_buf_align: u8,
8884 new_len: usize,
89 len_align: u29,
9085 ret_addr: usize,
91 ) ?usize {
86 ) bool {
87 const self = @ptrCast(*Self, @alignCast(@alignOf(Self), ctx));
9288 assert(buf.len > 0);
93 if (len_align != 0) {
94 assert(mem.isAlignedAnyAlign(new_len, len_align));
95 assert(new_len >= len_align);
96 }
9789 const underlying = self.getUnderlyingAllocatorPtr();
98 const result = underlying.rawResize(buf, buf_align, new_len, len_align, ret_addr) orelse return null;
99 if (len_align == 0) {
100 assert(result == new_len);
101 } else {
102 assert(result >= new_len);
103 assert(mem.isAlignedAnyAlign(result, len_align));
104 }
105 return result;
90 return underlying.rawResize(buf, log2_buf_align, new_len, ret_addr);
10691 }
10792
10893 pub fn free(
109 self: *Self,
94 ctx: *anyopaque,
11095 buf: []u8,
111 buf_align: u29,
96 log2_buf_align: u8,
11297 ret_addr: usize,
11398 ) void {
114 _ = self;
115 _ = buf_align;
99 _ = ctx;
100 _ = log2_buf_align;
116101 _ = ret_addr;
117102 assert(buf.len > 0);
118103 }
119104
120 pub usingnamespace if (T == Allocator or !@hasDecl(T, "reset")) struct {} else struct {
121 pub fn reset(self: *Self) void {
122 self.underlying_allocator.reset();
123 }
124 };
105 pub fn reset(self: *Self) void {
106 self.underlying_allocator.reset();
107 }
125108 };
126109}
127110
......@@ -151,16 +134,15 @@ const fail_allocator = Allocator{
151134
152135const failAllocator_vtable = Allocator.VTable{
153136 .alloc = failAllocatorAlloc,
154 .resize = Allocator.NoResize(anyopaque).noResize,
155 .free = Allocator.NoOpFree(anyopaque).noOpFree,
137 .resize = Allocator.noResize,
138 .free = Allocator.noFree,
156139};
157140
158fn failAllocatorAlloc(_: *anyopaque, n: usize, alignment: u29, len_align: u29, ra: usize) Allocator.Error![]u8 {
141fn failAllocatorAlloc(_: *anyopaque, n: usize, log2_alignment: u8, ra: usize) ?[*]u8 {
159142 _ = n;
160 _ = alignment;
161 _ = len_align;
143 _ = log2_alignment;
162144 _ = ra;
163 return error.OutOfMemory;
145 return null;
164146}
165147
166148test "Allocator basics" {
......@@ -188,7 +170,8 @@ test "Allocator.resize" {
188170 defer testing.allocator.free(values);
189171
190172 for (values) |*v, i| v.* = @intCast(T, i);
191 values = testing.allocator.resize(values, values.len + 10) orelse return error.OutOfMemory;
173 if (!testing.allocator.resize(values, values.len + 10)) return error.OutOfMemory;
174 values = values.ptr[0 .. values.len + 10];
192175 try testing.expect(values.len == 110);
193176 }
194177
......@@ -203,7 +186,8 @@ test "Allocator.resize" {
203186 defer testing.allocator.free(values);
204187
205188 for (values) |*v, i| v.* = @intToFloat(T, i);
206 values = testing.allocator.resize(values, values.len + 10) orelse return error.OutOfMemory;
189 if (!testing.allocator.resize(values, values.len + 10)) return error.OutOfMemory;
190 values = values.ptr[0 .. values.len + 10];
207191 try testing.expect(values.len == 110);
208192 }
209193}
......@@ -3108,7 +3092,7 @@ pub fn nativeToBig(comptime T: type, x: T) T {
31083092/// - The aligned pointer would not fit the address space,
31093093/// - The delta required to align the pointer is not a multiple of the pointee's
31103094/// type.
3111pub fn alignPointerOffset(ptr: anytype, align_to: u29) ?usize {
3095pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize {
31123096 assert(align_to != 0 and @popCount(align_to) == 1);
31133097
31143098 const T = @TypeOf(ptr);
......@@ -3140,7 +3124,7 @@ pub fn alignPointerOffset(ptr: anytype, align_to: u29) ?usize {
31403124/// - The aligned pointer would not fit the address space,
31413125/// - The delta required to align the pointer is not a multiple of the pointee's
31423126/// type.
3143pub fn alignPointer(ptr: anytype, align_to: u29) ?@TypeOf(ptr) {
3127pub fn alignPointer(ptr: anytype, align_to: usize) ?@TypeOf(ptr) {
31443128 const adjust_off = alignPointerOffset(ptr, align_to) orelse return null;
31453129 const T = @TypeOf(ptr);
31463130 // Avoid the use of intToPtr to avoid losing the pointer provenance info.
......@@ -3149,7 +3133,7 @@ pub fn alignPointer(ptr: anytype, align_to: u29) ?@TypeOf(ptr) {
31493133
31503134test "alignPointer" {
31513135 const S = struct {
3152 fn checkAlign(comptime T: type, base: usize, align_to: u29, expected: usize) !void {
3136 fn checkAlign(comptime T: type, base: usize, align_to: usize, expected: usize) !void {
31533137 var ptr = @intToPtr(T, base);
31543138 var aligned = alignPointer(ptr, align_to);
31553139 try testing.expectEqual(expected, @ptrToInt(aligned));
......@@ -3566,6 +3550,11 @@ pub fn alignForward(addr: usize, alignment: usize) usize {
35663550 return alignForwardGeneric(usize, addr, alignment);
35673551}
35683552
3553pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize {
3554 const alignment = @as(usize, 1) << @intCast(math.Log2Int(usize), log2_alignment);
3555 return alignForward(addr, alignment);
3556}
3557
35693558/// Round an address up to the next (or current) aligned address.
35703559/// The alignment must be a power of 2 and greater than 0.
35713560/// Asserts that rounding up the address does not cause integer overflow.
......@@ -3626,7 +3615,7 @@ pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {
36263615
36273616/// Returns whether `alignment` is a valid alignment, meaning it is
36283617/// a positive power of 2.
3629pub fn isValidAlign(alignment: u29) bool {
3618pub fn isValidAlign(alignment: usize) bool {
36303619 return @popCount(alignment) == 1;
36313620}
36323621
......@@ -3637,6 +3626,10 @@ pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {
36373626 return 0 == @mod(i, alignment);
36383627}
36393628
3629pub fn isAlignedLog2(addr: usize, log2_alignment: u8) bool {
3630 return @ctz(addr) >= log2_alignment;
3631}
3632
36403633/// Given an address and an alignment, return true if the address is a multiple of the alignment
36413634/// The alignment must be a power of 2 and greater than 0.
36423635pub fn isAligned(addr: usize, alignment: usize) bool {
......@@ -3670,7 +3663,7 @@ test "freeing empty string with null-terminated sentinel" {
36703663
36713664/// Returns a slice with the given new alignment,
36723665/// all other pointer attributes copied from `AttributeSource`.
3673fn AlignedSlice(comptime AttributeSource: type, comptime new_alignment: u29) type {
3666fn AlignedSlice(comptime AttributeSource: type, comptime new_alignment: usize) type {
36743667 const info = @typeInfo(AttributeSource).Pointer;
36753668 return @Type(.{
36763669 .Pointer = .{
lib/std/mem/Allocator.zig+127-526
......@@ -8,167 +8,101 @@ const Allocator = @This();
88const builtin = @import("builtin");
99
1010pub const Error = error{OutOfMemory};
11pub const Log2Align = math.Log2Int(usize);
1112
1213// The type erased pointer to the allocator implementation
1314ptr: *anyopaque,
1415vtable: *const VTable,
1516
1617pub const VTable = struct {
17 /// Attempt to allocate at least `len` bytes aligned to `ptr_align`.
18 /// Attempt to allocate exactly `len` bytes aligned to `1 << ptr_align`.
1819 ///
19 /// If `len_align` is `0`, then the length returned MUST be exactly `len` bytes,
20 /// otherwise, the length must be aligned to `len_align`.
20 /// `ret_addr` is optionally provided as the first return address of the
21 /// allocation call stack. If the value is `0` it means no return address
22 /// has been provided.
23 alloc: std.meta.FnPtr(fn (ctx: *anyopaque, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8),
24
25 /// Attempt to expand or shrink memory in place. `buf.len` must equal the
26 /// length requested from the most recent successful call to `alloc` or
27 /// `resize`. `buf_align` must equal the same value that was passed as the
28 /// `ptr_align` parameter to the original `alloc` call.
2129 ///
22 /// `len` must be greater than or equal to `len_align` and must be aligned by `len_align`.
30 /// A result of `true` indicates the resize was successful and the
31 /// allocation now has the same address but a size of `new_len`. `false`
32 /// indicates the resize could not be completed without moving the
33 /// allocation to a different address.
2334 ///
24 /// `ret_addr` is optionally provided as the first return address of the allocation call stack.
25 /// If the value is `0` it means no return address has been provided.
26 alloc: std.meta.FnPtr(fn (ptr: *anyopaque, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8),
27
28 /// Attempt to expand or shrink memory in place. `buf.len` must equal the most recent
29 /// length returned by `alloc` or `resize`. `buf_align` must equal the same value
30 /// that was passed as the `ptr_align` parameter to the original `alloc` call.
35 /// `new_len` must be greater than zero.
3136 ///
32 /// `null` 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 `null` MUST be returned.
37 /// `ret_addr` is optionally provided as the first return address of the
38 /// allocation call stack. If the value is `0` it means no return address
39 /// has been provided.
40 resize: std.meta.FnPtr(fn (ctx: *anyopaque, buf: []u8, buf_align: u8, new_len: usize, ret_addr: usize) bool),
41
42 /// Free and invalidate a buffer.
3543 ///
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.
44 /// `buf.len` must equal the most recent length returned by `alloc` or
45 /// given to a successful `resize` call.
4046 ///
41 /// `new_len` must be greater than zero, greater than or equal to `len_align` and must be aligned by `len_align`.
47 /// `buf_align` must equal the same value that was passed as the
48 /// `ptr_align` parameter to the original `alloc` call.
4249 ///
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.
45 resize: std.meta.FnPtr(fn (ptr: *anyopaque, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize),
46
47 /// Free and invalidate a buffer. `buf.len` must equal the most recent length returned by `alloc` or `resize`.
48 /// `buf_align` must equal the same value that was passed as the `ptr_align` parameter to the original `alloc` call.
49 ///
50 /// `ret_addr` is optionally provided as the first return address of the allocation call stack.
51 /// If the value is `0` it means no return address has been provided.
52 free: std.meta.FnPtr(fn (ptr: *anyopaque, buf: []u8, buf_align: u29, ret_addr: usize) void),
50 /// `ret_addr` is optionally provided as the first return address of the
51 /// allocation call stack. If the value is `0` it means no return address
52 /// has been provided.
53 free: std.meta.FnPtr(fn (ctx: *anyopaque, buf: []u8, buf_align: u8, ret_addr: usize) void),
5354};
5455
55pub fn init(
56 pointer: anytype,
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) ?usize,
59 comptime freeFn: fn (ptr: @TypeOf(pointer), buf: []u8, buf_align: u29, ret_addr: usize) void,
60) Allocator {
61 const Ptr = @TypeOf(pointer);
62 const ptr_info = @typeInfo(Ptr);
63
64 assert(ptr_info == .Pointer); // Must be a pointer
65 assert(ptr_info.Pointer.size == .One); // Must be a single-item pointer
66
67 const alignment = ptr_info.Pointer.alignment;
68
69 const gen = struct {
70 fn allocImpl(ptr: *anyopaque, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 {
71 const self = @ptrCast(Ptr, @alignCast(alignment, ptr));
72 return @call(.{ .modifier = .always_inline }, allocFn, .{ self, len, ptr_align, len_align, ret_addr });
73 }
74 fn resizeImpl(ptr: *anyopaque, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize {
75 assert(new_len != 0);
76 const self = @ptrCast(Ptr, @alignCast(alignment, ptr));
77 return @call(.{ .modifier = .always_inline }, resizeFn, .{ self, buf, buf_align, new_len, len_align, ret_addr });
78 }
79 fn freeImpl(ptr: *anyopaque, buf: []u8, buf_align: u29, ret_addr: usize) void {
80 const self = @ptrCast(Ptr, @alignCast(alignment, ptr));
81 @call(.{ .modifier = .always_inline }, freeFn, .{ self, buf, buf_align, ret_addr });
82 }
83
84 const vtable = VTable{
85 .alloc = allocImpl,
86 .resize = resizeImpl,
87 .free = freeImpl,
88 };
89 };
90
91 return .{
92 .ptr = pointer,
93 .vtable = &gen.vtable,
94 };
95}
96
97/// Set resizeFn to `NoResize(AllocatorType).noResize` if in-place resize is not supported.
98pub fn NoResize(comptime AllocatorType: type) type {
99 return struct {
100 pub fn noResize(
101 self: *AllocatorType,
102 buf: []u8,
103 buf_align: u29,
104 new_len: usize,
105 len_align: u29,
106 ret_addr: usize,
107 ) ?usize {
108 _ = self;
109 _ = buf_align;
110 _ = len_align;
111 _ = ret_addr;
112 return if (new_len > buf.len) null else new_len;
113 }
114 };
115}
116
117/// Set freeFn to `NoOpFree(AllocatorType).noOpFree` if free is a no-op.
118pub fn NoOpFree(comptime AllocatorType: type) type {
119 return struct {
120 pub fn noOpFree(
121 self: *AllocatorType,
122 buf: []u8,
123 buf_align: u29,
124 ret_addr: usize,
125 ) void {
126 _ = self;
127 _ = buf;
128 _ = buf_align;
129 _ = ret_addr;
130 }
131 };
132}
133
134/// Set freeFn to `PanicFree(AllocatorType).panicFree` if free is not a supported operation.
135pub fn PanicFree(comptime AllocatorType: type) type {
136 return struct {
137 pub fn panicFree(
138 self: *AllocatorType,
139 buf: []u8,
140 buf_align: u29,
141 ret_addr: usize,
142 ) void {
143 _ = self;
144 _ = buf;
145 _ = buf_align;
146 _ = ret_addr;
147 @panic("free is not a supported operation for the allocator: " ++ @typeName(AllocatorType));
148 }
149 };
56pub fn noResize(
57 self: *anyopaque,
58 buf: []u8,
59 log2_buf_align: u8,
60 new_len: usize,
61 ret_addr: usize,
62) bool {
63 _ = self;
64 _ = buf;
65 _ = log2_buf_align;
66 _ = new_len;
67 _ = ret_addr;
68 return false;
69}
70
71pub fn noFree(
72 self: *anyopaque,
73 buf: []u8,
74 log2_buf_align: u8,
75 ret_addr: usize,
76) void {
77 _ = self;
78 _ = buf;
79 _ = log2_buf_align;
80 _ = ret_addr;
15081}
15182
152/// This function is not intended to be called except from within the implementation of an Allocator
153pub inline fn rawAlloc(self: Allocator, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 {
154 return self.vtable.alloc(self.ptr, len, ptr_align, len_align, ret_addr);
83/// This function is not intended to be called except from within the
84/// implementation of an Allocator
85pub inline fn rawAlloc(self: Allocator, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8 {
86 return self.vtable.alloc(self.ptr, len, ptr_align, ret_addr);
15587}
15688
157/// This function is not intended to be called except from within the implementation of an Allocator
158pub inline fn rawResize(self: Allocator, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize {
159 return self.vtable.resize(self.ptr, buf, buf_align, new_len, len_align, ret_addr);
89/// This function is not intended to be called except from within the
90/// implementation of an Allocator
91pub inline fn rawResize(self: Allocator, buf: []u8, log2_buf_align: u8, new_len: usize, ret_addr: usize) bool {
92 return self.vtable.resize(self.ptr, buf, log2_buf_align, new_len, ret_addr);
16093}
16194
162/// This function is not intended to be called except from within the implementation of an Allocator
163pub inline fn rawFree(self: Allocator, buf: []u8, buf_align: u29, ret_addr: usize) void {
164 return self.vtable.free(self.ptr, buf, buf_align, ret_addr);
95/// This function is not intended to be called except from within the
96/// implementation of an Allocator
97pub inline fn rawFree(self: Allocator, buf: []u8, log2_buf_align: u8, ret_addr: usize) void {
98 return self.vtable.free(self.ptr, buf, log2_buf_align, ret_addr);
16599}
166100
167101/// Returns a pointer to undefined memory.
168102/// Call `destroy` with the result to free the memory.
169103pub fn create(self: Allocator, comptime T: type) Error!*T {
170 if (@sizeOf(T) == 0) return @intToPtr(*T, std.math.maxInt(usize));
171 const slice = try self.allocAdvancedWithRetAddr(T, null, 1, .exact, @returnAddress());
104 if (@sizeOf(T) == 0) return @intToPtr(*T, math.maxInt(usize));
105 const slice = try self.allocAdvancedWithRetAddr(T, null, 1, @returnAddress());
172106 return &slice[0];
173107}
174108
......@@ -179,7 +113,7 @@ pub fn destroy(self: Allocator, ptr: anytype) void {
179113 const T = info.child;
180114 if (@sizeOf(T) == 0) return;
181115 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
182 self.rawFree(non_const_ptr[0..@sizeOf(T)], info.alignment, @returnAddress());
116 self.rawFree(non_const_ptr[0..@sizeOf(T)], math.log2(info.alignment), @returnAddress());
183117}
184118
185119/// Allocates an array of `n` items of type `T` and sets all the
......@@ -191,7 +125,7 @@ pub fn destroy(self: Allocator, ptr: anytype) void {
191125///
192126/// For allocating a single item, see `create`.
193127pub fn alloc(self: Allocator, comptime T: type, n: usize) Error![]T {
194 return self.allocAdvancedWithRetAddr(T, null, n, .exact, @returnAddress());
128 return self.allocAdvancedWithRetAddr(T, null, n, @returnAddress());
195129}
196130
197131pub fn allocWithOptions(
......@@ -215,11 +149,11 @@ pub fn allocWithOptionsRetAddr(
215149 return_address: usize,
216150) Error!AllocWithOptionsPayload(Elem, optional_alignment, optional_sentinel) {
217151 if (optional_sentinel) |sentinel| {
218 const ptr = try self.allocAdvancedWithRetAddr(Elem, optional_alignment, n + 1, .exact, return_address);
152 const ptr = try self.allocAdvancedWithRetAddr(Elem, optional_alignment, n + 1, return_address);
219153 ptr[n] = sentinel;
220154 return ptr[0..n :sentinel];
221155 } else {
222 return self.allocAdvancedWithRetAddr(Elem, optional_alignment, n, .exact, return_address);
156 return self.allocAdvancedWithRetAddr(Elem, optional_alignment, n, return_address);
223157 }
224158}
225159
......@@ -255,231 +189,108 @@ pub fn alignedAlloc(
255189 comptime alignment: ?u29,
256190 n: usize,
257191) Error![]align(alignment orelse @alignOf(T)) T {
258 return self.allocAdvancedWithRetAddr(T, alignment, n, .exact, @returnAddress());
259}
260
261pub fn allocAdvanced(
262 self: Allocator,
263 comptime T: type,
264 /// null means naturally aligned
265 comptime alignment: ?u29,
266 n: usize,
267 exact: Exact,
268) Error![]align(alignment orelse @alignOf(T)) T {
269 return self.allocAdvancedWithRetAddr(T, alignment, n, exact, @returnAddress());
192 return self.allocAdvancedWithRetAddr(T, alignment, n, @returnAddress());
270193}
271194
272pub const Exact = enum { exact, at_least };
273
274195pub fn allocAdvancedWithRetAddr(
275196 self: Allocator,
276197 comptime T: type,
277198 /// null means naturally aligned
278199 comptime alignment: ?u29,
279200 n: usize,
280 exact: Exact,
281201 return_address: usize,
282202) Error![]align(alignment orelse @alignOf(T)) T {
283203 const a = if (alignment) |a| blk: {
284 if (a == @alignOf(T)) return allocAdvancedWithRetAddr(self, T, null, n, exact, return_address);
204 if (a == @alignOf(T)) return allocAdvancedWithRetAddr(self, T, null, n, return_address);
285205 break :blk a;
286206 } else @alignOf(T);
287207
208 // The Zig Allocator interface is not intended to solve allocations beyond
209 // the minimum OS page size. For these use cases, the caller must use OS
210 // APIs directly.
211 comptime assert(a <= mem.page_size);
212
288213 if (n == 0) {
289 const ptr = comptime std.mem.alignBackward(std.math.maxInt(usize), a);
214 const ptr = comptime std.mem.alignBackward(math.maxInt(usize), a);
290215 return @intToPtr([*]align(a) T, ptr)[0..0];
291216 }
292217
293218 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
294 // TODO The `if (alignment == null)` blocks are workarounds for zig not being able to
295 // access certain type information about T without creating a circular dependency in async
296 // functions that heap-allocate their own frame with @Frame(func).
297 const size_of_T: usize = if (alignment == null) @divExact(byte_count, n) else @sizeOf(T);
298 const len_align: u29 = switch (exact) {
299 .exact => 0,
300 .at_least => math.cast(u29, size_of_T) orelse 0,
301 };
302 const byte_slice = try self.rawAlloc(byte_count, a, len_align, return_address);
303 switch (exact) {
304 .exact => assert(byte_slice.len == byte_count),
305 .at_least => assert(byte_slice.len >= byte_count),
306 }
219 const byte_ptr = self.rawAlloc(byte_count, log2a(a), return_address) orelse return Error.OutOfMemory;
307220 // TODO: https://github.com/ziglang/zig/issues/4298
308 @memset(byte_slice.ptr, undefined, byte_slice.len);
309 if (alignment == null) {
310 // This if block is a workaround (see comment above)
311 return @intToPtr([*]T, @ptrToInt(byte_slice.ptr))[0..@divExact(byte_slice.len, @sizeOf(T))];
312 } else {
313 return mem.bytesAsSlice(T, @alignCast(a, byte_slice));
314 }
221 @memset(byte_ptr, undefined, byte_count);
222 const byte_slice = byte_ptr[0..byte_count];
223 return mem.bytesAsSlice(T, @alignCast(a, byte_slice));
315224}
316225
317/// Increases or decreases the size of an allocation. It is guaranteed to not move the pointer.
318pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) ?@TypeOf(old_mem) {
226/// Requests to modify the size of an allocation. It is guaranteed to not move
227/// the pointer, however the allocator implementation may refuse the resize
228/// request by returning `false`.
229pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {
319230 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
320231 const T = Slice.child;
321232 if (new_n == 0) {
322233 self.free(old_mem);
323 return &[0]T{};
234 return true;
235 }
236 if (old_mem.len == 0) {
237 return false;
324238 }
325239 const old_byte_slice = mem.sliceAsBytes(old_mem);
326 const new_byte_count = math.mul(usize, @sizeOf(T), new_n) catch return null;
327 const rc = self.rawResize(old_byte_slice, Slice.alignment, new_byte_count, 0, @returnAddress()) orelse return null;
328 assert(rc == new_byte_count);
329 const new_byte_slice = old_byte_slice.ptr[0..new_byte_count];
330 return mem.bytesAsSlice(T, new_byte_slice);
240 // I would like to use saturating multiplication here, but LLVM cannot lower it
241 // on WebAssembly: https://github.com/ziglang/zig/issues/9660
242 //const new_byte_count = new_n *| @sizeOf(T);
243 const new_byte_count = math.mul(usize, @sizeOf(T), new_n) catch return false;
244 return self.rawResize(old_byte_slice, log2a(Slice.alignment), new_byte_count, @returnAddress());
331245}
332246
333/// This function requests a new byte size for an existing allocation,
334/// which can be larger, smaller, or the same size as the old memory
335/// allocation.
336/// This function is preferred over `shrink`, because it can fail, even
337/// when shrinking. This gives the allocator a chance to perform a
338/// cheap shrink operation if possible, or otherwise return OutOfMemory,
339/// indicating that the caller should keep their capacity, for example
340/// in `std.ArrayList.shrink`.
341/// If you need guaranteed success, call `shrink`.
247/// This function requests a new byte size for an existing allocation, which
248/// can be larger, smaller, or the same size as the old memory allocation.
342249/// If `new_n` is 0, this is the same as `free` and it always succeeds.
343250pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) t: {
344251 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
345252 break :t Error![]align(Slice.alignment) Slice.child;
346253} {
347 const old_alignment = @typeInfo(@TypeOf(old_mem)).Pointer.alignment;
348 return self.reallocAdvancedWithRetAddr(old_mem, old_alignment, new_n, .exact, @returnAddress());
254 return self.reallocAdvanced(old_mem, new_n, @returnAddress());
349255}
350256
351pub fn reallocAtLeast(self: Allocator, old_mem: anytype, new_n: usize) t: {
352 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
353 break :t Error![]align(Slice.alignment) Slice.child;
354} {
355 const old_alignment = @typeInfo(@TypeOf(old_mem)).Pointer.alignment;
356 return self.reallocAdvancedWithRetAddr(old_mem, old_alignment, new_n, .at_least, @returnAddress());
357}
358
359/// This is the same as `realloc`, except caller may additionally request
360/// a new alignment, which can be larger, smaller, or the same as the old
361/// allocation.
362257pub fn reallocAdvanced(
363258 self: Allocator,
364259 old_mem: anytype,
365 comptime new_alignment: u29,
366 new_n: usize,
367 exact: Exact,
368) Error![]align(new_alignment) @typeInfo(@TypeOf(old_mem)).Pointer.child {
369 return self.reallocAdvancedWithRetAddr(old_mem, new_alignment, new_n, exact, @returnAddress());
370}
371
372pub fn reallocAdvancedWithRetAddr(
373 self: Allocator,
374 old_mem: anytype,
375 comptime new_alignment: u29,
376260 new_n: usize,
377 exact: Exact,
378261 return_address: usize,
379) Error![]align(new_alignment) @typeInfo(@TypeOf(old_mem)).Pointer.child {
262) t: {
263 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
264 break :t Error![]align(Slice.alignment) Slice.child;
265} {
380266 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
381267 const T = Slice.child;
382268 if (old_mem.len == 0) {
383 return self.allocAdvancedWithRetAddr(T, new_alignment, new_n, exact, return_address);
269 return self.allocAdvancedWithRetAddr(T, Slice.alignment, new_n, return_address);
384270 }
385271 if (new_n == 0) {
386272 self.free(old_mem);
387 const ptr = comptime std.mem.alignBackward(std.math.maxInt(usize), new_alignment);
388 return @intToPtr([*]align(new_alignment) T, ptr)[0..0];
273 const ptr = comptime std.mem.alignBackward(math.maxInt(usize), Slice.alignment);
274 return @intToPtr([*]align(Slice.alignment) T, ptr)[0..0];
389275 }
390276
391277 const old_byte_slice = mem.sliceAsBytes(old_mem);
392278 const byte_count = math.mul(usize, @sizeOf(T), new_n) catch return Error.OutOfMemory;
393279 // Note: can't set shrunk memory to undefined as memory shouldn't be modified on realloc failure
394 const len_align: u29 = switch (exact) {
395 .exact => 0,
396 .at_least => math.cast(u29, @as(usize, @sizeOf(T))) orelse 0,
397 };
398
399 if (mem.isAligned(@ptrToInt(old_byte_slice.ptr), new_alignment)) {
400 if (byte_count <= old_byte_slice.len) {
401 const shrunk_len = self.shrinkBytes(old_byte_slice, Slice.alignment, byte_count, len_align, return_address);
402 return mem.bytesAsSlice(T, @alignCast(new_alignment, old_byte_slice.ptr[0..shrunk_len]));
403 }
404
405 if (self.rawResize(old_byte_slice, Slice.alignment, byte_count, len_align, return_address)) |resized_len| {
406 // TODO: https://github.com/ziglang/zig/issues/4298
407 @memset(old_byte_slice.ptr + byte_count, undefined, resized_len - byte_count);
408 return mem.bytesAsSlice(T, @alignCast(new_alignment, old_byte_slice.ptr[0..resized_len]));
280 if (mem.isAligned(@ptrToInt(old_byte_slice.ptr), Slice.alignment)) {
281 if (self.rawResize(old_byte_slice, log2a(Slice.alignment), byte_count, return_address)) {
282 return mem.bytesAsSlice(T, @alignCast(Slice.alignment, old_byte_slice.ptr[0..byte_count]));
409283 }
410284 }
411285
412 if (byte_count <= old_byte_slice.len and new_alignment <= Slice.alignment) {
286 const new_mem = self.rawAlloc(byte_count, log2a(Slice.alignment), return_address) orelse
413287 return error.OutOfMemory;
414 }
415
416 const new_mem = try self.rawAlloc(byte_count, new_alignment, len_align, return_address);
417 @memcpy(new_mem.ptr, old_byte_slice.ptr, math.min(byte_count, old_byte_slice.len));
288 @memcpy(new_mem, old_byte_slice.ptr, @min(byte_count, old_byte_slice.len));
418289 // TODO https://github.com/ziglang/zig/issues/4298
419290 @memset(old_byte_slice.ptr, undefined, old_byte_slice.len);
420 self.rawFree(old_byte_slice, Slice.alignment, return_address);
421
422 return mem.bytesAsSlice(T, @alignCast(new_alignment, new_mem));
423}
291 self.rawFree(old_byte_slice, log2a(Slice.alignment), return_address);
424292
425/// Prefer calling realloc to shrink if you can tolerate failure, such as
426/// in an ArrayList data structure with a storage capacity.
427/// Shrink always succeeds, and `new_n` must be <= `old_mem.len`.
428/// Returned slice has same alignment as old_mem.
429/// Shrinking to 0 is the same as calling `free`.
430pub fn shrink(self: Allocator, old_mem: anytype, new_n: usize) t: {
431 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
432 break :t []align(Slice.alignment) Slice.child;
433} {
434 const old_alignment = @typeInfo(@TypeOf(old_mem)).Pointer.alignment;
435 return self.alignedShrinkWithRetAddr(old_mem, old_alignment, new_n, @returnAddress());
436}
437
438/// This is the same as `shrink`, except caller may additionally request
439/// a new alignment, which must be smaller or the same as the old
440/// allocation.
441pub fn alignedShrink(
442 self: Allocator,
443 old_mem: anytype,
444 comptime new_alignment: u29,
445 new_n: usize,
446) []align(new_alignment) @typeInfo(@TypeOf(old_mem)).Pointer.child {
447 return self.alignedShrinkWithRetAddr(old_mem, new_alignment, new_n, @returnAddress());
448}
449
450/// This is the same as `alignedShrink`, except caller may additionally pass
451/// the return address of the first stack frame, which may be relevant for
452/// allocators which collect stack traces.
453pub fn alignedShrinkWithRetAddr(
454 self: Allocator,
455 old_mem: anytype,
456 comptime new_alignment: u29,
457 new_n: usize,
458 return_address: usize,
459) []align(new_alignment) @typeInfo(@TypeOf(old_mem)).Pointer.child {
460 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
461 const T = Slice.child;
462
463 if (new_n == old_mem.len)
464 return old_mem;
465 if (new_n == 0) {
466 self.free(old_mem);
467 const ptr = comptime std.mem.alignBackward(std.math.maxInt(usize), new_alignment);
468 return @intToPtr([*]align(new_alignment) T, ptr)[0..0];
469 }
470
471 assert(new_n < old_mem.len);
472 assert(new_alignment <= Slice.alignment);
473
474 // Here we skip the overflow checking on the multiplication because
475 // new_n <= old_mem.len and the multiplication didn't overflow for that operation.
476 const byte_count = @sizeOf(T) * new_n;
477
478 const old_byte_slice = mem.sliceAsBytes(old_mem);
479 // TODO: https://github.com/ziglang/zig/issues/4298
480 @memset(old_byte_slice.ptr + byte_count, undefined, old_byte_slice.len - byte_count);
481 _ = self.shrinkBytes(old_byte_slice, Slice.alignment, byte_count, 0, return_address);
482 return old_mem[0..new_n];
293 return mem.bytesAsSlice(T, @alignCast(Slice.alignment, new_mem[0..byte_count]));
483294}
484295
485296/// Free an array allocated with `alloc`. To free a single item,
......@@ -492,7 +303,7 @@ pub fn free(self: Allocator, memory: anytype) void {
492303 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
493304 // TODO: https://github.com/ziglang/zig/issues/4298
494305 @memset(non_const_ptr, undefined, bytes_len);
495 self.rawFree(non_const_ptr[0..bytes_len], Slice.alignment, @returnAddress());
306 self.rawFree(non_const_ptr[0..bytes_len], log2a(Slice.alignment), @returnAddress());
496307}
497308
498309/// Copies `m` to newly allocated memory. Caller owns the memory.
......@@ -510,226 +321,16 @@ pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) ![:0]T {
510321 return new_buf[0..m.len :0];
511322}
512323
513/// This function allows a runtime `alignment` value. Callers should generally prefer
514/// to call the `alloc*` functions.
515pub fn allocBytes(
516 self: Allocator,
517 /// Must be >= 1.
518 /// Must be a power of 2.
519 /// Returned slice's pointer will have this alignment.
520 alignment: u29,
521 byte_count: usize,
522 /// 0 indicates the length of the slice returned MUST match `byte_count` exactly
523 /// non-zero means the length of the returned slice must be aligned by `len_align`
524 /// `byte_count` must be aligned by `len_align`
525 len_align: u29,
526 return_address: usize,
527) Error![]u8 {
528 const new_mem = try self.rawAlloc(byte_count, alignment, len_align, return_address);
529 // TODO: https://github.com/ziglang/zig/issues/4298
530 @memset(new_mem.ptr, undefined, new_mem.len);
531 return new_mem;
532}
533
534test "allocBytes" {
535 const number_of_bytes: usize = 10;
536 var runtime_alignment: u29 = 2;
537
538 {
539 const new_mem = try std.testing.allocator.allocBytes(runtime_alignment, number_of_bytes, 0, @returnAddress());
540 defer std.testing.allocator.free(new_mem);
541
542 try std.testing.expectEqual(number_of_bytes, new_mem.len);
543 try std.testing.expect(mem.isAligned(@ptrToInt(new_mem.ptr), runtime_alignment));
544 }
545
546 runtime_alignment = 8;
547
548 {
549 const new_mem = try std.testing.allocator.allocBytes(runtime_alignment, number_of_bytes, 0, @returnAddress());
550 defer std.testing.allocator.free(new_mem);
551
552 try std.testing.expectEqual(number_of_bytes, new_mem.len);
553 try std.testing.expect(mem.isAligned(@ptrToInt(new_mem.ptr), runtime_alignment));
554 }
555}
556
557test "allocBytes non-zero len_align" {
558 const number_of_bytes: usize = 10;
559 var runtime_alignment: u29 = 1;
560 var len_align: u29 = 2;
561
562 {
563 const new_mem = try std.testing.allocator.allocBytes(runtime_alignment, number_of_bytes, len_align, @returnAddress());
564 defer std.testing.allocator.free(new_mem);
565
566 try std.testing.expect(new_mem.len >= number_of_bytes);
567 try std.testing.expect(new_mem.len % len_align == 0);
568 try std.testing.expect(mem.isAligned(@ptrToInt(new_mem.ptr), runtime_alignment));
569 }
570
571 runtime_alignment = 16;
572 len_align = 5;
573
574 {
575 const new_mem = try std.testing.allocator.allocBytes(runtime_alignment, number_of_bytes, len_align, @returnAddress());
576 defer std.testing.allocator.free(new_mem);
577
578 try std.testing.expect(new_mem.len >= number_of_bytes);
579 try std.testing.expect(new_mem.len % len_align == 0);
580 try std.testing.expect(mem.isAligned(@ptrToInt(new_mem.ptr), runtime_alignment));
581 }
582}
583
584/// Realloc is used to modify the size or alignment of an existing allocation,
585/// as well as to provide the allocator with an opportunity to move an allocation
586/// to a better location.
587/// The returned slice will have its pointer aligned at least to `new_alignment` bytes.
588///
589/// This function allows a runtime `alignment` value. Callers should generally prefer
590/// to call the `realloc*` functions.
591///
592/// If the size/alignment is greater than the previous allocation, and the requested new
593/// allocation could not be granted this function returns `error.OutOfMemory`.
594/// When the size/alignment is less than or equal to the previous allocation,
595/// this function returns `error.OutOfMemory` when the allocator decides the client
596/// would be better off keeping the extra alignment/size.
597/// Clients will call `resizeFn` when they require the allocator to track a new alignment/size,
598/// and so this function should only return success when the allocator considers
599/// the reallocation desirable from the allocator's perspective.
600///
601/// As an example, `std.ArrayList` tracks a "capacity", and therefore can handle
602/// reallocation failure, even when `new_n` <= `old_mem.len`. A `FixedBufferAllocator`
603/// would always return `error.OutOfMemory` for `reallocFn` when the size/alignment
604/// is less than or equal to the old allocation, because it cannot reclaim the memory,
605/// and thus the `std.ArrayList` would be better off retaining its capacity.
606pub fn reallocBytes(
607 self: Allocator,
608 /// Must be the same as what was returned from most recent call to `allocFn` or `resizeFn`.
609 /// If `old_mem.len == 0` then this is a new allocation and `new_byte_count` must be >= 1.
610 old_mem: []u8,
611 /// If `old_mem.len == 0` then this is `undefined`, otherwise:
612 /// Must be the same as what was passed to `allocFn`.
613 /// Must be >= 1.
614 /// Must be a power of 2.
615 old_alignment: u29,
616 /// If `new_byte_count` is 0 then this is a free and it is required that `old_mem.len != 0`.
617 new_byte_count: usize,
618 /// Must be >= 1.
619 /// Must be a power of 2.
620 /// Returned slice's pointer will have this alignment.
621 new_alignment: u29,
622 /// 0 indicates the length of the slice returned MUST match `new_byte_count` exactly
623 /// non-zero means the length of the returned slice must be aligned by `len_align`
624 /// `new_byte_count` must be aligned by `len_align`
625 len_align: u29,
626 return_address: usize,
627) Error![]u8 {
628 if (old_mem.len == 0) {
629 return self.allocBytes(new_alignment, new_byte_count, len_align, return_address);
630 }
631 if (new_byte_count == 0) {
632 // TODO https://github.com/ziglang/zig/issues/4298
633 @memset(old_mem.ptr, undefined, old_mem.len);
634 self.rawFree(old_mem, old_alignment, return_address);
635 return &[0]u8{};
636 }
637
638 if (mem.isAligned(@ptrToInt(old_mem.ptr), new_alignment)) {
639 if (new_byte_count <= old_mem.len) {
640 const shrunk_len = self.shrinkBytes(old_mem, old_alignment, new_byte_count, len_align, return_address);
641 return old_mem.ptr[0..shrunk_len];
642 }
643
644 if (self.rawResize(old_mem, old_alignment, new_byte_count, len_align, return_address)) |resized_len| {
645 assert(resized_len >= new_byte_count);
646 // TODO: https://github.com/ziglang/zig/issues/4298
647 @memset(old_mem.ptr + new_byte_count, undefined, resized_len - new_byte_count);
648 return old_mem.ptr[0..resized_len];
649 }
650 }
651
652 if (new_byte_count <= old_mem.len and new_alignment <= old_alignment) {
653 return error.OutOfMemory;
654 }
655
656 const new_mem = try self.rawAlloc(new_byte_count, new_alignment, len_align, return_address);
657 @memcpy(new_mem.ptr, old_mem.ptr, math.min(new_byte_count, old_mem.len));
658
659 // TODO https://github.com/ziglang/zig/issues/4298
660 @memset(old_mem.ptr, undefined, old_mem.len);
661 self.rawFree(old_mem, old_alignment, return_address);
662
663 return new_mem;
664}
665
666test "reallocBytes" {
667 var new_mem: []u8 = &.{};
668
669 var new_byte_count: usize = 16;
670 var runtime_alignment: u29 = 4;
671
672 // `new_mem.len == 0`, this is a new allocation
673 {
674 new_mem = try std.testing.allocator.reallocBytes(new_mem, undefined, new_byte_count, runtime_alignment, 0, @returnAddress());
675 try std.testing.expectEqual(new_byte_count, new_mem.len);
676 try std.testing.expect(mem.isAligned(@ptrToInt(new_mem.ptr), runtime_alignment));
677 }
678
679 // `new_byte_count < new_mem.len`, this is a shrink, alignment is unmodified
680 new_byte_count = 14;
681 {
682 new_mem = try std.testing.allocator.reallocBytes(new_mem, runtime_alignment, new_byte_count, runtime_alignment, 0, @returnAddress());
683 try std.testing.expectEqual(new_byte_count, new_mem.len);
684 try std.testing.expect(mem.isAligned(@ptrToInt(new_mem.ptr), runtime_alignment));
685 }
686
687 // `new_byte_count < new_mem.len`, this is a shrink, alignment is decreased from 4 to 2
688 runtime_alignment = 2;
689 new_byte_count = 12;
690 {
691 new_mem = try std.testing.allocator.reallocBytes(new_mem, 4, new_byte_count, runtime_alignment, 0, @returnAddress());
692 try std.testing.expectEqual(new_byte_count, new_mem.len);
693 try std.testing.expect(mem.isAligned(@ptrToInt(new_mem.ptr), runtime_alignment));
694 }
695
696 // `new_byte_count > new_mem.len`, this is a growth, alignment is increased from 2 to 8
697 runtime_alignment = 8;
698 new_byte_count = 32;
699 {
700 new_mem = try std.testing.allocator.reallocBytes(new_mem, 2, new_byte_count, runtime_alignment, 0, @returnAddress());
701 try std.testing.expectEqual(new_byte_count, new_mem.len);
702 try std.testing.expect(mem.isAligned(@ptrToInt(new_mem.ptr), runtime_alignment));
703 }
704
705 // `new_byte_count == 0`, this is a free
706 new_byte_count = 0;
707 {
708 new_mem = try std.testing.allocator.reallocBytes(new_mem, runtime_alignment, new_byte_count, runtime_alignment, 0, @returnAddress());
709 try std.testing.expectEqual(new_byte_count, new_mem.len);
324/// TODO replace callsites with `@log2` after this proposal is implemented:
325/// https://github.com/ziglang/zig/issues/13642
326inline fn log2a(x: anytype) switch (@typeInfo(@TypeOf(x))) {
327 .Int => math.Log2Int(@TypeOf(x)),
328 .ComptimeInt => comptime_int,
329 else => @compileError("int please"),
330} {
331 switch (@typeInfo(@TypeOf(x))) {
332 .Int => return math.log2_int(@TypeOf(x), x),
333 .ComptimeInt => return math.log2(x),
334 else => @compileError("bad"),
710335 }
711336}
712
713/// Call `vtable.resize`, but caller guarantees that `new_len` <= `buf.len` meaning
714/// than a `null` return value should be impossible.
715/// This function allows a runtime `buf_align` value. Callers should generally prefer
716/// to call `shrink`.
717pub fn shrinkBytes(
718 self: Allocator,
719 /// Must be the same as what was returned from most recent call to `allocFn` or `resizeFn`.
720 buf: []u8,
721 /// Must be the same as what was passed to `allocFn`.
722 /// Must be >= 1.
723 /// Must be a power of 2.
724 buf_align: u29,
725 /// Must be >= 1.
726 new_len: usize,
727 /// 0 indicates the length of the slice returned MUST match `new_len` exactly
728 /// non-zero means the length of the returned slice must be aligned by `len_align`
729 /// `new_len` must be aligned by `len_align`
730 len_align: u29,
731 return_address: usize,
732) usize {
733 assert(new_len <= buf.len);
734 return self.rawResize(buf, buf_align, new_len, len_align, return_address) orelse unreachable;
735}
lib/std/meta/trailer_flags.zig+1-1
......@@ -144,7 +144,7 @@ test "TrailerFlags" {
144144 .b = true,
145145 .c = true,
146146 });
147 const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact);
147 const slice = try testing.allocator.alignedAlloc(u8, 8, flags.sizeInBytes());
148148 defer testing.allocator.free(slice);
149149
150150 flags.set(slice.ptr, .b, false);
lib/std/multi_array_list.zig+2-4
......@@ -288,11 +288,10 @@ pub fn MultiArrayList(comptime S: type) type {
288288 assert(new_len <= self.capacity);
289289 assert(new_len <= self.len);
290290
291 const other_bytes = gpa.allocAdvanced(
291 const other_bytes = gpa.alignedAlloc(
292292 u8,
293293 @alignOf(S),
294294 capacityInBytes(new_len),
295 .exact,
296295 ) catch {
297296 const self_slice = self.slice();
298297 inline for (fields) |field_info, i| {
......@@ -360,11 +359,10 @@ pub fn MultiArrayList(comptime S: type) type {
360359 /// `new_capacity` must be greater or equal to `len`.
361360 pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) !void {
362361 assert(new_capacity >= self.len);
363 const new_bytes = try gpa.allocAdvanced(
362 const new_bytes = try gpa.alignedAlloc(
364363 u8,
365364 @alignOf(S),
366365 capacityInBytes(new_capacity),
367 .exact,
368366 );
369367 if (self.len == 0) {
370368 gpa.free(self.allocatedBytes());
lib/std/net.zig+1-1
......@@ -825,7 +825,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A
825825
826826 result.addrs = try arena.alloc(Address, lookup_addrs.items.len);
827827 if (canon.items.len != 0) {
828 result.canon_name = canon.toOwnedSlice();
828 result.canon_name = try canon.toOwnedSlice();
829829 }
830830
831831 for (lookup_addrs.items) |lookup_addr, i| {
lib/std/pdb.zig+3-3
......@@ -478,7 +478,7 @@ fn readSparseBitVector(stream: anytype, allocator: mem.Allocator) ![]u32 {
478478 if (bit_i == std.math.maxInt(u5)) break;
479479 }
480480 }
481 return list.toOwnedSlice();
481 return try list.toOwnedSlice();
482482}
483483
484484pub const Pdb = struct {
......@@ -615,8 +615,8 @@ pub const Pdb = struct {
615615 return error.InvalidDebugInfo;
616616 }
617617
618 self.modules = modules.toOwnedSlice();
619 self.sect_contribs = sect_contribs.toOwnedSlice();
618 self.modules = try modules.toOwnedSlice();
619 self.sect_contribs = try sect_contribs.toOwnedSlice();
620620 }
621621
622622 pub fn parseInfoStream(self: *Pdb) !void {
lib/std/segmented_list.zig+44-23
......@@ -1,6 +1,7 @@
11const std = @import("std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
4const mem = std.mem;
45const Allocator = std.mem.Allocator;
56
67// Imagine that `fn at(self: *Self, index: usize) &T` is a customer asking for a box
......@@ -177,24 +178,32 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
177178 return self.growCapacity(allocator, new_capacity);
178179 }
179180
180 /// Only grows capacity, or retains current capacity
181 /// Only grows capacity, or retains current capacity.
181182 pub fn growCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Allocator.Error!void {
182183 const new_cap_shelf_count = shelfCount(new_capacity);
183184 const old_shelf_count = @intCast(ShelfIndex, self.dynamic_segments.len);
184 if (new_cap_shelf_count > old_shelf_count) {
185 self.dynamic_segments = try allocator.realloc(self.dynamic_segments, new_cap_shelf_count);
186 var i = old_shelf_count;
187 errdefer {
188 self.freeShelves(allocator, i, old_shelf_count);
189 self.dynamic_segments = allocator.shrink(self.dynamic_segments, old_shelf_count);
190 }
191 while (i < new_cap_shelf_count) : (i += 1) {
192 self.dynamic_segments[i] = (try allocator.alloc(T, shelfSize(i))).ptr;
193 }
185 if (new_cap_shelf_count <= old_shelf_count) return;
186
187 const new_dynamic_segments = try allocator.alloc([*]T, new_cap_shelf_count);
188 errdefer allocator.free(new_dynamic_segments);
189
190 var i: ShelfIndex = 0;
191 while (i < old_shelf_count) : (i += 1) {
192 new_dynamic_segments[i] = self.dynamic_segments[i];
194193 }
194 errdefer while (i > old_shelf_count) : (i -= 1) {
195 allocator.free(new_dynamic_segments[i][0..shelfSize(i)]);
196 };
197 while (i < new_cap_shelf_count) : (i += 1) {
198 new_dynamic_segments[i] = (try allocator.alloc(T, shelfSize(i))).ptr;
199 }
200
201 allocator.free(self.dynamic_segments);
202 self.dynamic_segments = new_dynamic_segments;
195203 }
196204
197 /// Only shrinks capacity or retains current capacity
205 /// Only shrinks capacity or retains current capacity.
206 /// It may fail to reduce the capacity in which case the capacity will remain unchanged.
198207 pub fn shrinkCapacity(self: *Self, allocator: Allocator, new_capacity: usize) void {
199208 if (new_capacity <= prealloc_item_count) {
200209 const len = @intCast(ShelfIndex, self.dynamic_segments.len);
......@@ -207,12 +216,24 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
207216 const new_cap_shelf_count = shelfCount(new_capacity);
208217 const old_shelf_count = @intCast(ShelfIndex, self.dynamic_segments.len);
209218 assert(new_cap_shelf_count <= old_shelf_count);
210 if (new_cap_shelf_count == old_shelf_count) {
211 return;
212 }
219 if (new_cap_shelf_count == old_shelf_count) return;
213220
221 // freeShelves() must be called before resizing the dynamic
222 // segments, but we don't know if resizing the dynamic segments
223 // will work until we try it. So we must allocate a fresh memory
224 // buffer in order to reduce capacity.
225 const new_dynamic_segments = allocator.alloc([*]T, new_cap_shelf_count) catch return;
214226 self.freeShelves(allocator, old_shelf_count, new_cap_shelf_count);
215 self.dynamic_segments = allocator.shrink(self.dynamic_segments, new_cap_shelf_count);
227 if (allocator.resize(self.dynamic_segments, new_cap_shelf_count)) {
228 // We didn't need the new memory allocation after all.
229 self.dynamic_segments = self.dynamic_segments[0..new_cap_shelf_count];
230 allocator.free(new_dynamic_segments);
231 } else {
232 // Good thing we allocated that new memory slice.
233 mem.copy([*]T, new_dynamic_segments, self.dynamic_segments[0..new_cap_shelf_count]);
234 allocator.free(self.dynamic_segments);
235 self.dynamic_segments = new_dynamic_segments;
236 }
216237 }
217238
218239 pub fn shrink(self: *Self, new_len: usize) void {
......@@ -227,10 +248,10 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
227248
228249 var i = start;
229250 if (end <= prealloc_item_count) {
230 std.mem.copy(T, dest[i - start ..], self.prealloc_segment[i..end]);
251 mem.copy(T, dest[i - start ..], self.prealloc_segment[i..end]);
231252 return;
232253 } else if (i < prealloc_item_count) {
233 std.mem.copy(T, dest[i - start ..], self.prealloc_segment[i..]);
254 mem.copy(T, dest[i - start ..], self.prealloc_segment[i..]);
234255 i = prealloc_item_count;
235256 }
236257
......@@ -239,7 +260,7 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
239260 const copy_start = boxIndex(i, shelf_index);
240261 const copy_end = std.math.min(shelfSize(shelf_index), copy_start + end - i);
241262
242 std.mem.copy(
263 mem.copy(
243264 T,
244265 dest[i - start ..],
245266 self.dynamic_segments[shelf_index][copy_start..copy_end],
......@@ -480,13 +501,13 @@ fn testSegmentedList(comptime prealloc: usize) !void {
480501 control[@intCast(usize, i)] = i + 1;
481502 }
482503
483 std.mem.set(i32, dest[0..], 0);
504 mem.set(i32, dest[0..], 0);
484505 list.writeToSlice(dest[0..], 0);
485 try testing.expect(std.mem.eql(i32, control[0..], dest[0..]));
506 try testing.expect(mem.eql(i32, control[0..], dest[0..]));
486507
487 std.mem.set(i32, dest[0..], 0);
508 mem.set(i32, dest[0..], 0);
488509 list.writeToSlice(dest[50..], 50);
489 try testing.expect(std.mem.eql(i32, control[50..], dest[50..]));
510 try testing.expect(mem.eql(i32, control[50..], dest[50..]));
490511 }
491512
492513 try list.setCapacity(testing.allocator, 0);
lib/std/testing/failing_allocator.zig+30-20
......@@ -47,16 +47,23 @@ pub const FailingAllocator = struct {
4747 }
4848
4949 pub fn allocator(self: *FailingAllocator) mem.Allocator {
50 return mem.Allocator.init(self, alloc, resize, free);
50 return .{
51 .ptr = self,
52 .vtable = &.{
53 .alloc = alloc,
54 .resize = resize,
55 .free = free,
56 },
57 };
5158 }
5259
5360 fn alloc(
54 self: *FailingAllocator,
61 ctx: *anyopaque,
5562 len: usize,
56 ptr_align: u29,
57 len_align: u29,
63 log2_ptr_align: u8,
5864 return_address: usize,
59 ) error{OutOfMemory}![]u8 {
65 ) ?[*]u8 {
66 const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
6067 if (self.index == self.fail_index) {
6168 if (!self.has_induced_failure) {
6269 mem.set(usize, &self.stack_addresses, 0);
......@@ -67,39 +74,42 @@ pub const FailingAllocator = struct {
6774 std.debug.captureStackTrace(return_address, &stack_trace);
6875 self.has_induced_failure = true;
6976 }
70 return error.OutOfMemory;
77 return null;
7178 }
72 const result = try self.internal_allocator.rawAlloc(len, ptr_align, len_align, return_address);
73 self.allocated_bytes += result.len;
79 const result = self.internal_allocator.rawAlloc(len, log2_ptr_align, return_address) orelse
80 return null;
81 self.allocated_bytes += len;
7482 self.allocations += 1;
7583 self.index += 1;
7684 return result;
7785 }
7886
7987 fn resize(
80 self: *FailingAllocator,
88 ctx: *anyopaque,
8189 old_mem: []u8,
82 old_align: u29,
90 log2_old_align: u8,
8391 new_len: usize,
84 len_align: u29,
8592 ra: usize,
86 ) ?usize {
87 const r = self.internal_allocator.rawResize(old_mem, old_align, new_len, len_align, ra) orelse return null;
88 if (r < old_mem.len) {
89 self.freed_bytes += old_mem.len - r;
93 ) bool {
94 const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
95 if (!self.internal_allocator.rawResize(old_mem, log2_old_align, new_len, ra))
96 return false;
97 if (new_len < old_mem.len) {
98 self.freed_bytes += old_mem.len - new_len;
9099 } else {
91 self.allocated_bytes += r - old_mem.len;
100 self.allocated_bytes += new_len - old_mem.len;
92101 }
93 return r;
102 return true;
94103 }
95104
96105 fn free(
97 self: *FailingAllocator,
106 ctx: *anyopaque,
98107 old_mem: []u8,
99 old_align: u29,
108 log2_old_align: u8,
100109 ra: usize,
101110 ) void {
102 self.internal_allocator.rawFree(old_mem, old_align, ra);
111 const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
112 self.internal_allocator.rawFree(old_mem, log2_old_align, ra);
103113 self.deallocations += 1;
104114 self.freed_bytes += old_mem.len;
105115 }
lib/std/unicode.zig+2-9
......@@ -611,12 +611,7 @@ pub fn utf16leToUtf8AllocZ(allocator: mem.Allocator, utf16le: []const u16) ![:0]
611611 assert((utf8Encode(codepoint, result.items[out_index..]) catch unreachable) == utf8_len);
612612 out_index += utf8_len;
613613 }
614
615 const len = result.items.len;
616
617 try result.append(0);
618
619 return result.toOwnedSlice()[0..len :0];
614 return result.toOwnedSliceSentinel(0);
620615}
621616
622617/// Asserts that the output buffer is big enough.
......@@ -714,9 +709,7 @@ pub fn utf8ToUtf16LeWithNull(allocator: mem.Allocator, utf8: []const u8) ![:0]u1
714709 }
715710 }
716711
717 const len = result.items.len;
718 try result.append(0);
719 return result.toOwnedSlice()[0..len :0];
712 return result.toOwnedSliceSentinel(0);
720713}
721714
722715/// Returns index of next character. If exact fit, returned index equals output slice length.
lib/std/zig/parse.zig+2-2
......@@ -72,8 +72,8 @@ pub fn parse(gpa: Allocator, source: [:0]const u8) Allocator.Error!Ast {
7272 .source = source,
7373 .tokens = tokens.toOwnedSlice(),
7474 .nodes = parser.nodes.toOwnedSlice(),
75 .extra_data = parser.extra_data.toOwnedSlice(gpa),
76 .errors = parser.errors.toOwnedSlice(gpa),
75 .extra_data = try parser.extra_data.toOwnedSlice(gpa),
76 .errors = try parser.errors.toOwnedSlice(gpa),
7777 };
7878}
7979
src/AstGen.zig+2-2
......@@ -199,8 +199,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
199199
200200 return Zir{
201201 .instructions = astgen.instructions.toOwnedSlice(),
202 .string_bytes = astgen.string_bytes.toOwnedSlice(gpa),
203 .extra = astgen.extra.toOwnedSlice(gpa),
202 .string_bytes = try astgen.string_bytes.toOwnedSlice(gpa),
203 .extra = try astgen.extra.toOwnedSlice(gpa),
204204 };
205205}
206206
src/Autodoc.zig+12-12
......@@ -146,46 +146,46 @@ pub fn generateZirData(self: *Autodoc) !void {
146146 .c_ulonglong_type,
147147 .c_longdouble_type,
148148 => .{
149 .Int = .{ .name = tmpbuf.toOwnedSlice() },
149 .Int = .{ .name = try tmpbuf.toOwnedSlice() },
150150 },
151151 .f16_type,
152152 .f32_type,
153153 .f64_type,
154154 .f128_type,
155155 => .{
156 .Float = .{ .name = tmpbuf.toOwnedSlice() },
156 .Float = .{ .name = try tmpbuf.toOwnedSlice() },
157157 },
158158 .comptime_int_type => .{
159 .ComptimeInt = .{ .name = tmpbuf.toOwnedSlice() },
159 .ComptimeInt = .{ .name = try tmpbuf.toOwnedSlice() },
160160 },
161161 .comptime_float_type => .{
162 .ComptimeFloat = .{ .name = tmpbuf.toOwnedSlice() },
162 .ComptimeFloat = .{ .name = try tmpbuf.toOwnedSlice() },
163163 },
164164
165165 .anyopaque_type => .{
166 .ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() },
166 .ComptimeExpr = .{ .name = try tmpbuf.toOwnedSlice() },
167167 },
168168 .bool_type => .{
169 .Bool = .{ .name = tmpbuf.toOwnedSlice() },
169 .Bool = .{ .name = try tmpbuf.toOwnedSlice() },
170170 },
171171
172172 .noreturn_type => .{
173 .NoReturn = .{ .name = tmpbuf.toOwnedSlice() },
173 .NoReturn = .{ .name = try tmpbuf.toOwnedSlice() },
174174 },
175175 .void_type => .{
176 .Void = .{ .name = tmpbuf.toOwnedSlice() },
176 .Void = .{ .name = try tmpbuf.toOwnedSlice() },
177177 },
178178 .type_info_type => .{
179 .ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() },
179 .ComptimeExpr = .{ .name = try tmpbuf.toOwnedSlice() },
180180 },
181181 .type_type => .{
182 .Type = .{ .name = tmpbuf.toOwnedSlice() },
182 .Type = .{ .name = try tmpbuf.toOwnedSlice() },
183183 },
184184 .anyerror_type => .{
185 .ErrorSet = .{ .name = tmpbuf.toOwnedSlice() },
185 .ErrorSet = .{ .name = try tmpbuf.toOwnedSlice() },
186186 },
187187 .calling_convention_inline, .calling_convention_c, .calling_convention_type => .{
188 .EnumLiteral = .{ .name = tmpbuf.toOwnedSlice() },
188 .EnumLiteral = .{ .name = try tmpbuf.toOwnedSlice() },
189189 },
190190 },
191191 );
src/Compilation.zig+2-2
......@@ -5052,7 +5052,7 @@ fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []con
50525052 while (lines.next()) |line| {
50535053 if (mem.startsWith(u8, line, prefix ++ ":")) {
50545054 if (current_err) |err| {
5055 err.context_lines = context_lines.toOwnedSlice();
5055 err.context_lines = try context_lines.toOwnedSlice();
50565056 }
50575057
50585058 var split = std.mem.split(u8, line, "error: ");
......@@ -5078,7 +5078,7 @@ fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []con
50785078 }
50795079
50805080 if (current_err) |err| {
5081 err.context_lines = context_lines.toOwnedSlice();
5081 err.context_lines = try context_lines.toOwnedSlice();
50825082 }
50835083}
50845084
src/Liveness.zig+2-2
......@@ -79,7 +79,7 @@ pub fn analyze(gpa: Allocator, air: Air) Allocator.Error!Liveness {
7979 return Liveness{
8080 .tomb_bits = a.tomb_bits,
8181 .special = a.special,
82 .extra = a.extra.toOwnedSlice(gpa),
82 .extra = try a.extra.toOwnedSlice(gpa),
8383 };
8484}
8585
......@@ -594,7 +594,7 @@ pub fn getSwitchBr(l: Liveness, gpa: Allocator, inst: Air.Inst.Index, cases_len:
594594 deaths.appendAssumeCapacity(else_deaths);
595595 }
596596 return SwitchBrTable{
597 .deaths = deaths.toOwnedSlice(),
597 .deaths = try deaths.toOwnedSlice(),
598598 };
599599}
600600
src/Module.zig+34-26
......@@ -53,12 +53,12 @@ local_zir_cache: Compilation.Directory,
5353/// map of Decl indexes to details about them being exported.
5454/// The Export memory is owned by the `export_owners` table; the slice itself
5555/// is owned by this table. The slice is guaranteed to not be empty.
56decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, []*Export) = .{},
56decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
5757/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
5858/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
5959/// is performing the export of another Decl.
6060/// This table owns the Export memory.
61export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, []*Export) = .{},
61export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
6262/// The set of all the Zig source files in the Module. We keep track of this in order
6363/// to iterate over it and check which source files have been modified on the file system when
6464/// an update is requested, as well as to cache `@import` results.
......@@ -80,7 +80,7 @@ embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{},
8080/// This table uses an optional index so that when a Decl is destroyed, the string literal
8181/// is still reclaimable by a future Decl.
8282string_literal_table: std.HashMapUnmanaged(StringLiteralContext.Key, Decl.OptionalIndex, StringLiteralContext, std.hash_map.default_max_load_percentage) = .{},
83string_literal_bytes: std.ArrayListUnmanaged(u8) = .{},
83string_literal_bytes: ArrayListUnmanaged(u8) = .{},
8484
8585/// The set of all the generic function instantiations. This is used so that when a generic
8686/// function is called twice with the same comptime parameter arguments, both calls dispatch
......@@ -163,7 +163,7 @@ test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
163163/// multi-threaded contention on an atomic counter.
164164allocated_decls: std.SegmentedList(Decl, 0) = .{},
165165/// When a Decl object is freed from `allocated_decls`, it is pushed into this stack.
166decls_free_list: std.ArrayListUnmanaged(Decl.Index) = .{},
166decls_free_list: ArrayListUnmanaged(Decl.Index) = .{},
167167
168168global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{},
169169
......@@ -173,7 +173,7 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct {
173173}) = .{},
174174
175175pub const StringLiteralContext = struct {
176 bytes: *std.ArrayListUnmanaged(u8),
176 bytes: *ArrayListUnmanaged(u8),
177177
178178 pub const Key = struct {
179179 index: u32,
......@@ -192,7 +192,7 @@ pub const StringLiteralContext = struct {
192192};
193193
194194pub const StringLiteralAdapter = struct {
195 bytes: *std.ArrayListUnmanaged(u8),
195 bytes: *ArrayListUnmanaged(u8),
196196
197197 pub fn eql(self: @This(), a_slice: []const u8, b: StringLiteralContext.Key) bool {
198198 const b_slice = self.bytes.items[b.index..][0..b.len];
......@@ -1896,11 +1896,11 @@ pub const File = struct {
18961896
18971897 /// Used by change detection algorithm, after astgen, contains the
18981898 /// set of decls that existed in the previous ZIR but not in the new one.
1899 deleted_decls: std.ArrayListUnmanaged(Decl.Index) = .{},
1899 deleted_decls: ArrayListUnmanaged(Decl.Index) = .{},
19001900 /// Used by change detection algorithm, after astgen, contains the
19011901 /// set of decls that existed both in the previous ZIR and in the new one,
19021902 /// but their source code has been modified.
1903 outdated_decls: std.ArrayListUnmanaged(Decl.Index) = .{},
1903 outdated_decls: ArrayListUnmanaged(Decl.Index) = .{},
19041904
19051905 /// The most recent successful ZIR for this file, with no errors.
19061906 /// This is only populated when a previously successful ZIR
......@@ -3438,12 +3438,12 @@ pub fn deinit(mod: *Module) void {
34383438
34393439 mod.compile_log_decls.deinit(gpa);
34403440
3441 for (mod.decl_exports.values()) |export_list| {
3442 gpa.free(export_list);
3441 for (mod.decl_exports.values()) |*export_list| {
3442 export_list.deinit(gpa);
34433443 }
34443444 mod.decl_exports.deinit(gpa);
34453445
3446 for (mod.export_owners.values()) |value| {
3446 for (mod.export_owners.values()) |*value| {
34473447 freeExportList(gpa, value);
34483448 }
34493449 mod.export_owners.deinit(gpa);
......@@ -3533,13 +3533,13 @@ pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
35333533 return decl_index == decl.src_namespace.getDeclIndex();
35343534}
35353535
3536fn freeExportList(gpa: Allocator, export_list: []*Export) void {
3537 for (export_list) |exp| {
3536fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void {
3537 for (export_list.items) |exp| {
35383538 gpa.free(exp.options.name);
35393539 if (exp.options.section) |s| gpa.free(s);
35403540 gpa.destroy(exp);
35413541 }
3542 gpa.free(export_list);
3542 export_list.deinit(gpa);
35433543}
35443544
35453545const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
......@@ -3822,7 +3822,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
38223822 .byte_abs = token_starts[parse_err.token] + extra_offset,
38233823 },
38243824 },
3825 .msg = msg.toOwnedSlice(),
3825 .msg = try msg.toOwnedSlice(),
38263826 };
38273827 if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
38283828 const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
......@@ -3845,7 +3845,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
38453845 .parent_decl_node = 0,
38463846 .lazy = .{ .token_abs = note.token },
38473847 },
3848 .msg = msg.toOwnedSlice(),
3848 .msg = try msg.toOwnedSlice(),
38493849 };
38503850 }
38513851
......@@ -3981,7 +3981,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
39813981 // Walk the Decl graph, updating ZIR indexes, strings, and populating
39823982 // the deleted and outdated lists.
39833983
3984 var decl_stack: std.ArrayListUnmanaged(Decl.Index) = .{};
3984 var decl_stack: ArrayListUnmanaged(Decl.Index) = .{};
39853985 defer decl_stack.deinit(gpa);
39863986
39873987 const root_decl = file.root_decl.unwrap().?;
......@@ -4146,7 +4146,7 @@ pub fn mapOldZirToNew(
41464146 old_inst: Zir.Inst.Index,
41474147 new_inst: Zir.Inst.Index,
41484148 };
4149 var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{};
4149 var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{};
41504150 defer match_stack.deinit(gpa);
41514151
41524152 // Main struct inst is always the same
......@@ -5488,12 +5488,12 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {
54885488/// Delete all the Export objects that are caused by this Decl. Re-analysis of
54895489/// this Decl will cause them to be re-created (or not).
54905490fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {
5491 const kv = mod.export_owners.fetchSwapRemove(decl_index) orelse return;
5491 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
54925492
5493 for (kv.value) |exp| {
5493 for (export_owners.items) |exp| {
54945494 if (mod.decl_exports.getPtr(exp.exported_decl)) |value_ptr| {
54955495 // Remove exports with owner_decl matching the regenerating decl.
5496 const list = value_ptr.*;
5496 const list = value_ptr.items;
54975497 var i: usize = 0;
54985498 var new_len = list.len;
54995499 while (i < new_len) {
......@@ -5504,7 +5504,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {
55045504 i += 1;
55055505 }
55065506 }
5507 value_ptr.* = mod.gpa.shrink(list, new_len);
5507 value_ptr.shrinkAndFree(mod.gpa, new_len);
55085508 if (new_len == 0) {
55095509 assert(mod.decl_exports.swapRemove(exp.exported_decl));
55105510 }
......@@ -5527,7 +5527,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {
55275527 mod.gpa.free(exp.options.name);
55285528 mod.gpa.destroy(exp);
55295529 }
5530 mod.gpa.free(kv.value);
5530 export_owners.deinit(mod.gpa);
55315531}
55325532
55335533pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
......@@ -5745,8 +5745,8 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
57455745
57465746 return Air{
57475747 .instructions = sema.air_instructions.toOwnedSlice(),
5748 .extra = sema.air_extra.toOwnedSlice(gpa),
5749 .values = sema.air_values.toOwnedSlice(gpa),
5748 .extra = try sema.air_extra.toOwnedSlice(gpa),
5749 .values = try sema.air_values.toOwnedSlice(gpa),
57505750 };
57515751}
57525752
......@@ -6415,7 +6415,7 @@ pub fn processExports(mod: *Module) !void {
64156415 var it = mod.decl_exports.iterator();
64166416 while (it.next()) |entry| {
64176417 const exported_decl = entry.key_ptr.*;
6418 const exports = entry.value_ptr.*;
6418 const exports = entry.value_ptr.items;
64196419 for (exports) |new_export| {
64206420 const gop = try symbol_exports.getOrPut(gpa, new_export.options.name);
64216421 if (gop.found_existing) {
......@@ -6695,3 +6695,11 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u
66956695pub fn wantDllExports(mod: Module) bool {
66966696 return mod.comp.bin_file.options.dll_export_fns and mod.getTarget().os.tag == .windows;
66976697}
6698
6699pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export {
6700 if (mod.decl_exports.get(decl_index)) |l| {
6701 return l.items;
6702 } else {
6703 return &[0]*Export{};
6704 }
6705}
src/Sema.zig+11-12
......@@ -2244,7 +2244,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
22442244 .hidden = cur_reference_trace - max_references,
22452245 });
22462246 }
2247 err_msg.reference_trace = reference_stack.toOwnedSlice();
2247 err_msg.reference_trace = try reference_stack.toOwnedSlice();
22482248 }
22492249 if (sema.owner_func) |func| {
22502250 func.state = .sema_failure;
......@@ -5500,20 +5500,18 @@ pub fn analyzeExport(
55005500 // Add to export_owners table.
55015501 const eo_gop = mod.export_owners.getOrPutAssumeCapacity(sema.owner_decl_index);
55025502 if (!eo_gop.found_existing) {
5503 eo_gop.value_ptr.* = &[0]*Export{};
5503 eo_gop.value_ptr.* = .{};
55045504 }
5505 eo_gop.value_ptr.* = try gpa.realloc(eo_gop.value_ptr.*, eo_gop.value_ptr.len + 1);
5506 eo_gop.value_ptr.*[eo_gop.value_ptr.len - 1] = new_export;
5507 errdefer eo_gop.value_ptr.* = gpa.shrink(eo_gop.value_ptr.*, eo_gop.value_ptr.len - 1);
5505 try eo_gop.value_ptr.append(gpa, new_export);
5506 errdefer _ = eo_gop.value_ptr.pop();
55085507
55095508 // Add to exported_decl table.
55105509 const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl_index);
55115510 if (!de_gop.found_existing) {
5512 de_gop.value_ptr.* = &[0]*Export{};
5511 de_gop.value_ptr.* = .{};
55135512 }
5514 de_gop.value_ptr.* = try gpa.realloc(de_gop.value_ptr.*, de_gop.value_ptr.len + 1);
5515 de_gop.value_ptr.*[de_gop.value_ptr.len - 1] = new_export;
5516 errdefer de_gop.value_ptr.* = gpa.shrink(de_gop.value_ptr.*, de_gop.value_ptr.len - 1);
5513 try de_gop.value_ptr.append(gpa, new_export);
5514 errdefer _ = de_gop.value_ptr.pop();
55175515}
55185516
55195517fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
......@@ -10762,7 +10760,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1076210760 .payload = undefined,
1076310761 },
1076410762 } });
10765 var cond_body = case_block.instructions.toOwnedSlice(gpa);
10763 var cond_body = try case_block.instructions.toOwnedSlice(gpa);
1076610764 defer gpa.free(cond_body);
1076710765
1076810766 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
......@@ -10800,7 +10798,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1080010798 sema.air_extra.appendSliceAssumeCapacity(cond_body);
1080110799 }
1080210800 gpa.free(prev_then_body);
10803 prev_then_body = case_block.instructions.toOwnedSlice(gpa);
10801 prev_then_body = try case_block.instructions.toOwnedSlice(gpa);
1080410802 prev_cond_br = new_cond_br;
1080510803 }
1080610804 }
......@@ -16318,7 +16316,7 @@ fn zirCondbr(
1631816316 defer sub_block.instructions.deinit(gpa);
1631916317
1632016318 try sema.analyzeBodyRuntimeBreak(&sub_block, then_body);
16321 const true_instructions = sub_block.instructions.toOwnedSlice(gpa);
16319 const true_instructions = try sub_block.instructions.toOwnedSlice(gpa);
1632216320 defer gpa.free(true_instructions);
1632316321
1632416322 const err_cond = blk: {
......@@ -19301,6 +19299,7 @@ fn zirBitCount(
1930119299 .Int => {
1930219300 if (try sema.resolveMaybeUndefVal(operand)) |val| {
1930319301 if (val.isUndef()) return sema.addConstUndef(result_scalar_ty);
19302 try sema.resolveLazyValue(val);
1930419303 return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, target));
1930519304 } else {
1930619305 try sema.requireRuntimeBlock(block, src, operand_src);
src/arch/aarch64/CodeGen.zig+1-1
......@@ -531,7 +531,7 @@ pub fn generate(
531531
532532 var mir = Mir{
533533 .instructions = function.mir_instructions.toOwnedSlice(),
534 .extra = function.mir_extra.toOwnedSlice(bin_file.allocator),
534 .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator),
535535 };
536536 defer mir.deinit(bin_file.allocator);
537537
src/arch/arm/CodeGen.zig+1-1
......@@ -328,7 +328,7 @@ pub fn generate(
328328
329329 var mir = Mir{
330330 .instructions = function.mir_instructions.toOwnedSlice(),
331 .extra = function.mir_extra.toOwnedSlice(bin_file.allocator),
331 .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator),
332332 };
333333 defer mir.deinit(bin_file.allocator);
334334
src/arch/riscv64/CodeGen.zig+1-1
......@@ -291,7 +291,7 @@ pub fn generate(
291291
292292 var mir = Mir{
293293 .instructions = function.mir_instructions.toOwnedSlice(),
294 .extra = function.mir_extra.toOwnedSlice(bin_file.allocator),
294 .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator),
295295 };
296296 defer mir.deinit(bin_file.allocator);
297297
src/arch/sparc64/CodeGen.zig+1-1
......@@ -330,7 +330,7 @@ pub fn generate(
330330
331331 var mir = Mir{
332332 .instructions = function.mir_instructions.toOwnedSlice(),
333 .extra = function.mir_extra.toOwnedSlice(bin_file.allocator),
333 .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator),
334334 };
335335 defer mir.deinit(bin_file.allocator);
336336
src/arch/wasm/CodeGen.zig+4-4
......@@ -1064,8 +1064,8 @@ fn genFunctype(gpa: Allocator, cc: std.builtin.CallingConvention, params: []cons
10641064 }
10651065
10661066 return wasm.Type{
1067 .params = temp_params.toOwnedSlice(),
1068 .returns = returns.toOwnedSlice(),
1067 .params = try temp_params.toOwnedSlice(),
1068 .returns = try returns.toOwnedSlice(),
10691069 };
10701070}
10711071
......@@ -1176,7 +1176,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
11761176
11771177 var mir: Mir = .{
11781178 .instructions = func.mir_instructions.toOwnedSlice(),
1179 .extra = func.mir_extra.toOwnedSlice(func.gpa),
1179 .extra = try func.mir_extra.toOwnedSlice(func.gpa),
11801180 };
11811181 defer mir.deinit(func.gpa);
11821182
......@@ -1258,7 +1258,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV
12581258 },
12591259 else => return func.fail("calling convention '{s}' not supported for Wasm", .{@tagName(cc)}),
12601260 }
1261 result.args = args.toOwnedSlice();
1261 result.args = try args.toOwnedSlice();
12621262 return result;
12631263}
12641264
src/arch/x86_64/CodeGen.zig+1-1
......@@ -331,7 +331,7 @@ pub fn generate(
331331
332332 var mir = Mir{
333333 .instructions = function.mir_instructions.toOwnedSlice(),
334 .extra = function.mir_extra.toOwnedSlice(bin_file.allocator),
334 .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator),
335335 };
336336 defer mir.deinit(bin_file.allocator);
337337
src/codegen/c.zig+12-12
......@@ -1286,7 +1286,7 @@ pub const DeclGen = struct {
12861286 }
12871287 try bw.writeAll(");\n");
12881288
1289 const rendered = buffer.toOwnedSlice();
1289 const rendered = try buffer.toOwnedSlice();
12901290 errdefer dg.typedefs.allocator.free(rendered);
12911291 const name = rendered[name_begin..name_end];
12921292
......@@ -1326,7 +1326,7 @@ pub const DeclGen = struct {
13261326 const name_end = buffer.items.len;
13271327 try bw.writeAll(";\n");
13281328
1329 const rendered = buffer.toOwnedSlice();
1329 const rendered = try buffer.toOwnedSlice();
13301330 errdefer dg.typedefs.allocator.free(rendered);
13311331 const name = rendered[name_begin..name_end];
13321332
......@@ -1369,7 +1369,7 @@ pub const DeclGen = struct {
13691369 buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);
13701370 buffer.appendSliceAssumeCapacity(";\n");
13711371
1372 const rendered = buffer.toOwnedSlice();
1372 const rendered = try buffer.toOwnedSlice();
13731373 errdefer dg.typedefs.allocator.free(rendered);
13741374 const name = rendered[name_begin..name_end];
13751375
......@@ -1413,7 +1413,7 @@ pub const DeclGen = struct {
14131413 }
14141414 try buffer.appendSlice("};\n");
14151415
1416 const rendered = buffer.toOwnedSlice();
1416 const rendered = try buffer.toOwnedSlice();
14171417 errdefer dg.typedefs.allocator.free(rendered);
14181418
14191419 try dg.typedefs.ensureUnusedCapacity(1);
......@@ -1448,7 +1448,7 @@ pub const DeclGen = struct {
14481448 try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)});
14491449 const name_end = buffer.items.len - ";\n".len;
14501450
1451 const rendered = buffer.toOwnedSlice();
1451 const rendered = try buffer.toOwnedSlice();
14521452 errdefer dg.typedefs.allocator.free(rendered);
14531453 const name = rendered[name_begin..name_end];
14541454
......@@ -1510,7 +1510,7 @@ pub const DeclGen = struct {
15101510 if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n");
15111511 try buffer.appendSlice("};\n");
15121512
1513 const rendered = buffer.toOwnedSlice();
1513 const rendered = try buffer.toOwnedSlice();
15141514 errdefer dg.typedefs.allocator.free(rendered);
15151515
15161516 try dg.typedefs.ensureUnusedCapacity(1);
......@@ -1553,7 +1553,7 @@ pub const DeclGen = struct {
15531553 const name_end = buffer.items.len;
15541554 try bw.writeAll(";\n");
15551555
1556 const rendered = buffer.toOwnedSlice();
1556 const rendered = try buffer.toOwnedSlice();
15571557 errdefer dg.typedefs.allocator.free(rendered);
15581558 const name = rendered[name_begin..name_end];
15591559
......@@ -1586,7 +1586,7 @@ pub const DeclGen = struct {
15861586 const c_len_val = Value.initPayload(&c_len_pl.base);
15871587 try bw.print("[{}];\n", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
15881588
1589 const rendered = buffer.toOwnedSlice();
1589 const rendered = try buffer.toOwnedSlice();
15901590 errdefer dg.typedefs.allocator.free(rendered);
15911591 const name = rendered[name_begin..name_end];
15921592
......@@ -1614,7 +1614,7 @@ pub const DeclGen = struct {
16141614 const name_end = buffer.items.len;
16151615 try bw.writeAll(";\n");
16161616
1617 const rendered = buffer.toOwnedSlice();
1617 const rendered = try buffer.toOwnedSlice();
16181618 errdefer dg.typedefs.allocator.free(rendered);
16191619 const name = rendered[name_begin..name_end];
16201620
......@@ -1643,7 +1643,7 @@ pub const DeclGen = struct {
16431643 const name_end = buffer.items.len;
16441644 try buffer.appendSlice(";\n");
16451645
1646 const rendered = buffer.toOwnedSlice();
1646 const rendered = try buffer.toOwnedSlice();
16471647 errdefer dg.typedefs.allocator.free(rendered);
16481648 const name = rendered[name_begin..name_end];
16491649
......@@ -2006,7 +2006,7 @@ pub const DeclGen = struct {
20062006 _ = try airBreakpoint(bw);
20072007 try buffer.appendSlice("}\n");
20082008
2009 const rendered = buffer.toOwnedSlice();
2009 const rendered = try buffer.toOwnedSlice();
20102010 errdefer dg.typedefs.allocator.free(rendered);
20112011 const name = rendered[name_begin..name_end];
20122012
......@@ -2108,7 +2108,7 @@ pub const DeclGen = struct {
21082108 dg.module.markDeclAlive(decl);
21092109
21102110 if (dg.module.decl_exports.get(decl_index)) |exports| {
2111 return writer.writeAll(exports[0].options.name);
2111 return writer.writeAll(exports.items[0].options.name);
21122112 } else if (decl.isExtern()) {
21132113 return writer.writeAll(mem.sliceTo(decl.name, 0));
21142114 } else {
src/codegen/llvm.zig+3-5
......@@ -693,7 +693,7 @@ pub const Object = struct {
693693 for (mod.decl_exports.values()) |export_list, i| {
694694 const decl_index = export_keys[i];
695695 const llvm_global = object.decl_map.get(decl_index) orelse continue;
696 for (export_list) |exp| {
696 for (export_list.items) |exp| {
697697 // Detect if the LLVM global has already been created as an extern. In such
698698 // case, we need to replace all uses of it with this exported global.
699699 // TODO update std.builtin.ExportOptions to have the name be a
......@@ -1215,8 +1215,7 @@ pub const Object = struct {
12151215 else => |e| return e,
12161216 };
12171217
1218 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
1219 try o.updateDeclExports(module, decl_index, decl_exports);
1218 try o.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
12201219 }
12211220
12221221 pub fn updateDecl(self: *Object, module: *Module, decl_index: Module.Decl.Index) !void {
......@@ -1239,8 +1238,7 @@ pub const Object = struct {
12391238 },
12401239 else => |e| return e,
12411240 };
1242 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
1243 try self.updateDeclExports(module, decl_index, decl_exports);
1241 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
12441242 }
12451243
12461244 /// TODO replace this with a call to `Module::getNamedValue`. This will require adding
src/libc_installation.zig+3-3
......@@ -387,7 +387,7 @@ pub const LibCInstallation = struct {
387387 else => return error.FileSystem,
388388 };
389389
390 self.include_dir = result_buf.toOwnedSlice();
390 self.include_dir = try result_buf.toOwnedSlice();
391391 return;
392392 }
393393
......@@ -434,7 +434,7 @@ pub const LibCInstallation = struct {
434434 else => return error.FileSystem,
435435 };
436436
437 self.crt_dir = result_buf.toOwnedSlice();
437 self.crt_dir = try result_buf.toOwnedSlice();
438438 return;
439439 }
440440 return error.LibCRuntimeNotFound;
......@@ -499,7 +499,7 @@ pub const LibCInstallation = struct {
499499 else => return error.FileSystem,
500500 };
501501
502 self.kernel32_lib_dir = result_buf.toOwnedSlice();
502 self.kernel32_lib_dir = try result_buf.toOwnedSlice();
503503 return;
504504 }
505505 return error.LibCKernel32LibNotFound;
src/link/Coff.zig+6-6
......@@ -938,9 +938,9 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
938938
939939 try self.updateDeclCode(decl_index, code, .FUNCTION);
940940
941 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
942 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
943 return self.updateDeclExports(module, decl_index, decl_exports);
941 // Since we updated the vaddr and the size, each corresponding export
942 // symbol also needs to be updated.
943 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
944944}
945945
946946pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {
......@@ -1053,9 +1053,9 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
10531053
10541054 try self.updateDeclCode(decl_index, code, .NULL);
10551055
1056 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
1057 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
1058 return self.updateDeclExports(module, decl_index, decl_exports);
1056 // Since we updated the vaddr and the size, each corresponding export
1057 // symbol also needs to be updated.
1058 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
10591059}
10601060
10611061fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 {
src/link/Elf.zig+6-6
......@@ -2450,9 +2450,9 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24502450 );
24512451 }
24522452
2453 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
2454 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
2455 return self.updateDeclExports(module, decl_index, decl_exports);
2453 // Since we updated the vaddr and the size, each corresponding export
2454 // symbol also needs to be updated.
2455 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
24562456}
24572457
24582458pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !void {
......@@ -2527,9 +2527,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
25272527 );
25282528 }
25292529
2530 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
2531 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
2532 return self.updateDeclExports(module, decl_index, decl_exports);
2530 // Since we updated the vaddr and the size, each corresponding export
2531 // symbol also needs to be updated.
2532 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
25332533}
25342534
25352535pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
src/link/MachO.zig+2-4
......@@ -2225,8 +2225,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
22252225
22262226 // Since we updated the vaddr and the size, each corresponding export symbol also
22272227 // needs to be updated.
2228 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
2229 try self.updateDeclExports(module, decl_index, decl_exports);
2228 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
22302229}
22312230
22322231pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
......@@ -2377,8 +2376,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
23772376
23782377 // Since we updated the vaddr and the size, each corresponding export symbol also
23792378 // needs to be updated.
2380 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
2381 try self.updateDeclExports(module, decl_index, decl_exports);
2379 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
23822380}
23832381
23842382fn getDeclOutputSection(self: *MachO, decl: *Module.Decl) u8 {
src/link/MachO/Trie.zig+1-1
......@@ -165,7 +165,7 @@ pub const Node = struct {
165165 break;
166166 try label_buf.append(next);
167167 }
168 break :blk label_buf.toOwnedSlice();
168 break :blk try label_buf.toOwnedSlice();
169169 };
170170
171171 const seek_to = try leb.readULEB128(u64, reader);
src/link/Plan9.zig+8-8
......@@ -230,7 +230,7 @@ fn putFn(self: *Plan9, decl_index: Module.Decl.Index, out: FnDeclOutput) !void {
230230
231231 // null terminate
232232 try a.append(0);
233 const final = a.toOwnedSlice();
233 const final = try a.toOwnedSlice();
234234 self.syms.items[fn_map_res.value_ptr.sym_index - 1] = .{
235235 .type = .z,
236236 .value = 1,
......@@ -296,7 +296,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
296296 },
297297 );
298298 const code = switch (res) {
299 .appended => code_buffer.toOwnedSlice(),
299 .appended => try code_buffer.toOwnedSlice(),
300300 .fail => |em| {
301301 decl.analysis = .codegen_failure;
302302 try module.failed_decls.put(module.gpa, decl_index, em);
......@@ -305,7 +305,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
305305 };
306306 const out: FnDeclOutput = .{
307307 .code = code,
308 .lineinfo = dbg_line_buffer.toOwnedSlice(),
308 .lineinfo = try dbg_line_buffer.toOwnedSlice(),
309309 .start_line = start_line.?,
310310 .end_line = end_line,
311311 };
......@@ -574,7 +574,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
574574 }
575575 self.syms.items[decl.link.plan9.sym_index.?].value = off;
576576 if (mod.decl_exports.get(decl_index)) |exports| {
577 try self.addDeclExports(mod, decl, exports);
577 try self.addDeclExports(mod, decl, exports.items);
578578 }
579579 }
580580 }
......@@ -611,7 +611,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
611611 }
612612 self.syms.items[decl.link.plan9.sym_index.?].value = off;
613613 if (mod.decl_exports.get(decl_index)) |exports| {
614 try self.addDeclExports(mod, decl, exports);
614 try self.addDeclExports(mod, decl, exports.items);
615615 }
616616 }
617617 // write the unnamed constants after the other data decls
......@@ -641,7 +641,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
641641 self.syms.items[1].value = self.getAddr(0x0, .b);
642642 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
643643 try self.writeSyms(&sym_buf);
644 const syms = sym_buf.toOwnedSlice();
644 const syms = try sym_buf.toOwnedSlice();
645645 defer self.base.allocator.free(syms);
646646 assert(2 + self.atomCount() == iovecs_i); // we didn't write all the decls
647647 iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };
......@@ -914,7 +914,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
914914 const sym = self.syms.items[decl.link.plan9.sym_index.?];
915915 try self.writeSym(writer, sym);
916916 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
917 for (exports) |e| {
917 for (exports.items) |e| {
918918 try self.writeSym(writer, self.syms.items[e.link.plan9.?]);
919919 }
920920 }
......@@ -939,7 +939,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
939939 const sym = self.syms.items[decl.link.plan9.sym_index.?];
940940 try self.writeSym(writer, sym);
941941 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
942 for (exports) |e| {
942 for (exports.items) |e| {
943943 const s = self.syms.items[e.link.plan9.?];
944944 if (mem.eql(u8, s.name, "_start"))
945945 self.entry_val = s.value;
src/link/Wasm.zig+1-1
......@@ -3206,7 +3206,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
32063206 const skip_export_non_fn = target.os.tag == .wasi and
32073207 wasm.base.options.wasi_exec_model == .command;
32083208 for (mod.decl_exports.values()) |exports| {
3209 for (exports) |exprt| {
3209 for (exports.items) |exprt| {
32103210 const exported_decl = mod.declPtr(exprt.exported_decl);
32113211 if (skip_export_non_fn and exported_decl.ty.zigTypeTag() != .Fn) {
32123212 // skip exporting symbols when we're building a WASI command
src/link/Wasm/Object.zig+2-2
......@@ -557,7 +557,7 @@ fn Parser(comptime ReaderType: type) type {
557557 error.EndOfStream => {}, // finished parsing the file
558558 else => |e| return e,
559559 }
560 parser.object.relocatable_data = relocatable_data.toOwnedSlice();
560 parser.object.relocatable_data = try relocatable_data.toOwnedSlice();
561561 }
562562
563563 /// Based on the "features" custom section, parses it into a list of
......@@ -742,7 +742,7 @@ fn Parser(comptime ReaderType: type) type {
742742 log.debug("Found legacy indirect function table. Created symbol", .{});
743743 }
744744
745 parser.object.symtable = symbols.toOwnedSlice();
745 parser.object.symtable = try symbols.toOwnedSlice();
746746 },
747747 }
748748 }
src/link/tapi/parse.zig+1-1
......@@ -262,7 +262,7 @@ pub const Tree = struct {
262262 }
263263
264264 self.source = source;
265 self.tokens = tokens.toOwnedSlice();
265 self.tokens = try tokens.toOwnedSlice();
266266
267267 var it = TokenIterator{ .buffer = self.tokens };
268268 var parser = Parser{
src/link/tapi/yaml.zig+1-1
......@@ -193,7 +193,7 @@ pub const Value = union(ValueType) {
193193 }
194194 }
195195
196 return Value{ .list = out_list.toOwnedSlice() };
196 return Value{ .list = try out_list.toOwnedSlice() };
197197 } else if (node.cast(Node.Value)) |value| {
198198 const start = tree.tokens[value.start.?];
199199 const end = tree.tokens[value.end.?];
src/main.zig+1-1
......@@ -4803,7 +4803,7 @@ pub const ClangArgIterator = struct {
48034803 };
48044804 self.root_args = args;
48054805 }
4806 const resp_arg_slice = resp_arg_list.toOwnedSlice();
4806 const resp_arg_slice = try resp_arg_list.toOwnedSlice();
48074807 self.next_index = 0;
48084808 self.argv = resp_arg_slice;
48094809
src/test.zig+3-3
......@@ -338,7 +338,7 @@ const TestManifest = struct {
338338 while (try it.next()) |item| {
339339 try out.append(item);
340340 }
341 return out.toOwnedSlice();
341 return try out.toOwnedSlice();
342342 }
343343
344344 fn getConfigForKeyAssertSingle(self: TestManifest, key: []const u8, comptime T: type) !T {
......@@ -361,7 +361,7 @@ const TestManifest = struct {
361361 while (it.next()) |line| {
362362 try out.append(line);
363363 }
364 return out.toOwnedSlice();
364 return try out.toOwnedSlice();
365365 }
366366
367367 fn ParseFn(comptime T: type) type {
......@@ -1179,7 +1179,7 @@ pub const TestContext = struct {
11791179 if (output.items.len > 0) {
11801180 try output.resize(output.items.len - 1);
11811181 }
1182 case.addCompareOutput(src, output.toOwnedSlice());
1182 case.addCompareOutput(src, try output.toOwnedSlice());
11831183 },
11841184 .cli => @panic("TODO cli tests"),
11851185 }
src/translate_c/ast.zig+1-1
......@@ -788,7 +788,7 @@ pub fn render(gpa: Allocator, zig_is_stage1: bool, nodes: []const Node) !std.zig
788788 .source = try ctx.buf.toOwnedSliceSentinel(0),
789789 .tokens = ctx.tokens.toOwnedSlice(),
790790 .nodes = ctx.nodes.toOwnedSlice(),
791 .extra_data = ctx.extra_data.toOwnedSlice(gpa),
791 .extra_data = try ctx.extra_data.toOwnedSlice(gpa),
792792 .errors = &.{},
793793 };
794794}
src/value.zig+14-24
......@@ -1677,22 +1677,8 @@ pub const Value = extern union {
16771677 @panic("TODO implement i64 Value clz");
16781678 },
16791679 .int_big_positive => {
1680 // TODO: move this code into std lib big ints
16811680 const bigint = val.castTag(.int_big_positive).?.asBigInt();
1682 // Limbs are stored in little-endian order but we need
1683 // to iterate big-endian.
1684 var total_limb_lz: u64 = 0;
1685 var i: usize = bigint.limbs.len;
1686 const bits_per_limb = @sizeOf(std.math.big.Limb) * 8;
1687 while (i != 0) {
1688 i -= 1;
1689 const limb = bigint.limbs[i];
1690 const this_limb_lz = @clz(limb);
1691 total_limb_lz += this_limb_lz;
1692 if (this_limb_lz != bits_per_limb) break;
1693 }
1694 const total_limb_bits = bigint.limbs.len * bits_per_limb;
1695 return total_limb_lz + ty_bits - total_limb_bits;
1681 return bigint.clz(ty_bits);
16961682 },
16971683 .int_big_negative => {
16981684 @panic("TODO implement int_big_negative Value clz");
......@@ -1703,6 +1689,12 @@ pub const Value = extern union {
17031689 return ty_bits;
17041690 },
17051691
1692 .lazy_align, .lazy_size => {
1693 var bigint_buf: BigIntSpace = undefined;
1694 const bigint = val.toBigIntAdvanced(&bigint_buf, target, null) catch unreachable;
1695 return bigint.clz(ty_bits);
1696 },
1697
17061698 else => unreachable,
17071699 }
17081700 }
......@@ -1721,16 +1713,8 @@ pub const Value = extern union {
17211713 @panic("TODO implement i64 Value ctz");
17221714 },
17231715 .int_big_positive => {
1724 // TODO: move this code into std lib big ints
17251716 const bigint = val.castTag(.int_big_positive).?.asBigInt();
1726 // Limbs are stored in little-endian order.
1727 var result: u64 = 0;
1728 for (bigint.limbs) |limb| {
1729 const limb_tz = @ctz(limb);
1730 result += limb_tz;
1731 if (limb_tz != @sizeOf(std.math.big.Limb) * 8) break;
1732 }
1733 return result;
1717 return bigint.ctz();
17341718 },
17351719 .int_big_negative => {
17361720 @panic("TODO implement int_big_negative Value ctz");
......@@ -1741,6 +1725,12 @@ pub const Value = extern union {
17411725 return ty_bits;
17421726 },
17431727
1728 .lazy_align, .lazy_size => {
1729 var bigint_buf: BigIntSpace = undefined;
1730 const bigint = val.toBigIntAdvanced(&bigint_buf, target, null) catch unreachable;
1731 return bigint.ctz();
1732 },
1733
17441734 else => unreachable,
17451735 }
17461736 }
test/cases/compile_errors/dereference_anyopaque.zig+6-6
......@@ -47,9 +47,9 @@ pub export fn entry() void {
4747// :11:22: error: comparison of 'void' with null
4848// :25:51: error: values of type 'anyopaque' must be comptime-known, but operand value is runtime-known
4949// :25:51: note: opaque type 'anyopaque' has undefined size
50// :25:51: error: values of type 'fn(*anyopaque, usize, u29, u29, usize) error{OutOfMemory}![]u8' must be comptime-known, but operand value is runtime-known
51// :25:51: note: use '*const fn(*anyopaque, usize, u29, u29, usize) error{OutOfMemory}![]u8' for a function pointer type
52// :25:51: error: values of type 'fn(*anyopaque, []u8, u29, usize, u29, usize) ?usize' must be comptime-known, but operand value is runtime-known
53// :25:51: note: use '*const fn(*anyopaque, []u8, u29, usize, u29, usize) ?usize' for a function pointer type
54// :25:51: error: values of type 'fn(*anyopaque, []u8, u29, usize) void' must be comptime-known, but operand value is runtime-known
55// :25:51: note: use '*const fn(*anyopaque, []u8, u29, usize) void' for a function pointer type
50// :25:51: error: values of type 'fn(*anyopaque, usize, u8, usize) ?[*]u8' must be comptime-known, but operand value is runtime-known
51// :25:51: note: use '*const fn(*anyopaque, usize, u8, usize) ?[*]u8' for a function pointer type
52// :25:51: error: values of type 'fn(*anyopaque, []u8, u8, usize, usize) bool' must be comptime-known, but operand value is runtime-known
53// :25:51: note: use '*const fn(*anyopaque, []u8, u8, usize, usize) bool' for a function pointer type
54// :25:51: error: values of type 'fn(*anyopaque, []u8, u8, usize) void' must be comptime-known, but operand value is runtime-known
55// :25:51: note: use '*const fn(*anyopaque, []u8, u8, usize) void' for a function pointer type
test/compare_output.zig+6-5
......@@ -504,9 +504,10 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
504504 \\ const allocator = logging_allocator.allocator();
505505 \\
506506 \\ var a = try allocator.alloc(u8, 10);
507 \\ a = allocator.shrink(a, 5);
507 \\ try std.testing.expect(allocator.resize(a, 5));
508 \\ a = a[0..5];
508509 \\ try std.testing.expect(a.len == 5);
509 \\ try std.testing.expect(allocator.resize(a, 20) == null);
510 \\ try std.testing.expect(!allocator.resize(a, 20));
510511 \\ allocator.free(a);
511512 \\}
512513 \\
......@@ -522,9 +523,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
522523 \\ nosuspend stdout.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
523524 \\}
524525 ,
525 \\debug: alloc - success - len: 10, ptr_align: 1, len_align: 0
526 \\debug: shrink - success - 10 to 5, len_align: 0, buf_align: 1
527 \\error: expand - failure - 5 to 20, len_align: 0, buf_align: 1
526 \\debug: alloc - success - len: 10, ptr_align: 0
527 \\debug: shrink - success - 10 to 5, buf_align: 0
528 \\error: expand - failure - 5 to 20, buf_align: 0
528529 \\debug: free - len: 5
529530 \\
530531 );
test/tests.zig+1-1
......@@ -992,7 +992,7 @@ pub const StackTracesContext = struct {
992992 }
993993 try buf.appendSlice("\n");
994994 }
995 break :got_result buf.toOwnedSlice();
995 break :got_result try buf.toOwnedSlice();
996996 };
997997
998998 if (!mem.eql(u8, self.expect_output, got)) {