authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-10 21:24:27-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-29 23:46:02-07:00
logd4a1ae474a7d4607ec8ac306963872eb48cfd731
tree1bc61b33cb757454bb1f75486be331b86ca641d3
parent0c0c70ee82df6e727dd488318e6d44d5010eef79

std.heap.WasmAllocator: resize in place without force shrinking


1 files changed, 62 insertions(+), 5 deletions(-)

lib/std/heap/WasmAllocator.zig+62-5
......@@ -68,7 +68,7 @@ fn alloc(ctx: *anyopaque, len: usize, alignment: u29, len_align: u29, ra: usize)
6868 _ = len_align;
6969 _ = ra;
7070 const aligned_len = @max(len, alignment);
71 const slot_size = math.ceilPowerOfTwoAssert(usize, aligned_len);
71 const slot_size = math.ceilPowerOfTwo(usize, aligned_len) catch return error.OutOfMemory;
7272 const class = math.log2(slot_size);
7373 if (class < size_class_count) {
7474 const addr = a: {
......@@ -113,12 +113,28 @@ fn resize(
113113 return_address: usize,
114114) ?usize {
115115 _ = ctx;
116 _ = buf_align;
117116 _ = return_address;
118117 _ = len_align;
119 _ = new_len;
120 _ = buf;
121 @panic("handle resize");
118 // We don't want to move anything from one size class to another. But we can recover bytes
119 // in between powers of two.
120 const old_aligned_len = @max(buf.len, buf_align);
121 const new_aligned_len = @max(new_len, buf_align);
122 const old_small_slot_size = math.ceilPowerOfTwoAssert(usize, old_aligned_len);
123 const old_small_class = math.log2(old_small_slot_size);
124 if (old_small_class < size_class_count) {
125 const new_small_slot_size = math.ceilPowerOfTwo(usize, new_aligned_len) catch return null;
126 //std.debug.print("resize: old_small_slot_size={d} new_small_slot_size={d}\n", .{
127 // old_small_slot_size, new_small_slot_size,
128 //});
129 if (old_small_slot_size != new_small_slot_size) return null;
130 } else {
131 const old_bigpages_needed = (old_aligned_len + (bigpage_size - 1)) / bigpage_size;
132 const old_big_slot_size = math.ceilPowerOfTwoAssert(usize, old_bigpages_needed);
133 const new_bigpages_needed = (new_aligned_len + (bigpage_size - 1)) / bigpage_size;
134 const new_big_slot_size = math.ceilPowerOfTwo(usize, new_bigpages_needed) catch return null;
135 if (old_big_slot_size != new_big_slot_size) return null;
136 }
137 return new_len;
122138}
123139
124140fn free(
......@@ -234,3 +250,44 @@ test "large allocations" {
234250 test_ally.free(ptr3);
235251 test_ally.free(ptr2);
236252}
253
254test "very large allocation" {
255 try std.testing.expectError(error.OutOfMemory, test_ally.alloc(u8, math.maxInt(usize)));
256}
257
258test "realloc" {
259 var slice = try test_ally.alignedAlloc(u8, @alignOf(u32), 1);
260 defer test_ally.free(slice);
261 slice[0] = 0x12;
262
263 // This reallocation should keep its pointer address.
264 const old_slice = slice;
265 slice = try test_ally.realloc(slice, 2);
266 try std.testing.expect(old_slice.ptr == slice.ptr);
267 try std.testing.expect(slice[0] == 0x12);
268 slice[1] = 0x34;
269
270 // This requires upgrading to a larger size class
271 slice = try test_ally.realloc(slice, 17);
272 try std.testing.expect(slice[0] == 0x12);
273 try std.testing.expect(slice[1] == 0x34);
274}
275
276test "shrink" {
277 var slice = try test_ally.alloc(u8, 20);
278 defer test_ally.free(slice);
279
280 mem.set(u8, slice, 0x11);
281
282 slice = test_ally.shrink(slice, 17);
283
284 for (slice) |b| {
285 try std.testing.expect(b == 0x11);
286 }
287
288 slice = test_ally.shrink(slice, 16);
289
290 for (slice) |b| {
291 try std.testing.expect(b == 0x11);
292 }
293}