authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-10 21:40:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-29 23:46:02-07:00
log3dcea95ffe97ee93af50bf8906e53c7c7a7ec84e
tree4820fee3936c1679e59825f65fd4030525b01910
parentd4a1ae474a7d4607ec8ac306963872eb48cfd731

std.heap.WasmAllocator: implement resizing


1 files changed, 85 insertions(+), 6 deletions(-)

lib/std/heap/WasmAllocator.zig+85-6
...@@ -67,6 +67,7 @@ fn alloc(ctx: *anyopaque, len: usize, alignment: u29, len_align: u29, ra: usize)...@@ -67,6 +67,7 @@ fn alloc(ctx: *anyopaque, len: usize, alignment: u29, len_align: u29, ra: usize)
67 _ = ctx;67 _ = ctx;
68 _ = len_align;68 _ = len_align;
69 _ = ra;69 _ = ra;
70 if (alignment > wasm.page_size) return error.OutOfMemory; // calm down
70 const aligned_len = @max(len, alignment);71 const aligned_len = @max(len, alignment);
71 const slot_size = math.ceilPowerOfTwo(usize, aligned_len) catch return error.OutOfMemory;72 const slot_size = math.ceilPowerOfTwo(usize, aligned_len) catch return error.OutOfMemory;
72 const class = math.log2(slot_size);73 const class = math.log2(slot_size);
...@@ -110,11 +111,8 @@ fn resize(...@@ -110,11 +111,8 @@ fn resize(
110 buf_align: u29,111 buf_align: u29,
111 new_len: usize,112 new_len: usize,
112 len_align: u29,113 len_align: u29,
113 return_address: usize,114 ra: usize,
114) ?usize {115) ?usize {
115 _ = ctx;
116 _ = return_address;
117 _ = len_align;
118 // We don't want to move anything from one size class to another. But we can recover bytes116 // We don't want to move anything from one size class to another. But we can recover bytes
119 // in between powers of two.117 // in between powers of two.
120 const old_aligned_len = @max(buf.len, buf_align);118 const old_aligned_len = @max(buf.len, buf_align);
...@@ -126,13 +124,29 @@ fn resize(...@@ -126,13 +124,29 @@ fn resize(
126 //std.debug.print("resize: old_small_slot_size={d} new_small_slot_size={d}\n", .{124 //std.debug.print("resize: old_small_slot_size={d} new_small_slot_size={d}\n", .{
127 // old_small_slot_size, new_small_slot_size,125 // old_small_slot_size, new_small_slot_size,
128 //});126 //});
129 if (old_small_slot_size != new_small_slot_size) return null;127 if (old_small_slot_size != new_small_slot_size) {
128 if (new_aligned_len >= old_aligned_len) {
129 return null;
130 }
131 // TODO this panic is a design flaw in the Allocator interface that
132 // should be addressed.
133 const new = alloc(ctx, new_len, buf_align, len_align, ra) catch @panic("out of memory");
134 @memcpy(new.ptr, buf.ptr, buf.len);
135 }
130 } else {136 } else {
131 const old_bigpages_needed = (old_aligned_len + (bigpage_size - 1)) / bigpage_size;137 const old_bigpages_needed = (old_aligned_len + (bigpage_size - 1)) / bigpage_size;
132 const old_big_slot_size = math.ceilPowerOfTwoAssert(usize, old_bigpages_needed);138 const old_big_slot_size = math.ceilPowerOfTwoAssert(usize, old_bigpages_needed);
133 const new_bigpages_needed = (new_aligned_len + (bigpage_size - 1)) / bigpage_size;139 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;140 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;141 if (old_big_slot_size != new_big_slot_size) {
142 if (new_aligned_len >= old_aligned_len) {
143 return null;
144 }
145 // TODO this panic is a design flaw in the Allocator interface that
146 // should be addressed.
147 const new = alloc(ctx, new_len, buf_align, len_align, ra) catch @panic("out of memory");
148 @memcpy(new.ptr, buf.ptr, buf.len);
149 }
136 }150 }
137 return new_len;151 return new_len;
138}152}
...@@ -291,3 +305,68 @@ test "shrink" {...@@ -291,3 +305,68 @@ test "shrink" {
291 try std.testing.expect(b == 0x11);305 try std.testing.expect(b == 0x11);
292 }306 }
293}307}
308
309test "large object - grow" {
310 var slice1 = try test_ally.alloc(u8, bigpage_size * 2 - 20);
311 defer test_ally.free(slice1);
312
313 const old = slice1;
314 slice1 = try test_ally.realloc(slice1, bigpage_size * 2 - 10);
315 try std.testing.expect(slice1.ptr == old.ptr);
316
317 slice1 = try test_ally.realloc(slice1, bigpage_size * 2);
318 try std.testing.expect(slice1.ptr == old.ptr);
319
320 slice1 = try test_ally.realloc(slice1, bigpage_size * 2 + 1);
321}
322
323test "realloc small object to large object" {
324 var slice = try test_ally.alloc(u8, 70);
325 defer test_ally.free(slice);
326 slice[0] = 0x12;
327 slice[60] = 0x34;
328
329 // This requires upgrading to a large object
330 const large_object_size = bigpage_size * 2 + 50;
331 slice = try test_ally.realloc(slice, large_object_size);
332 try std.testing.expect(slice[0] == 0x12);
333 try std.testing.expect(slice[60] == 0x34);
334}
335
336test "shrink large object to large object" {
337 var slice = try test_ally.alloc(u8, bigpage_size * 2 + 50);
338 defer test_ally.free(slice);
339 slice[0] = 0x12;
340 slice[60] = 0x34;
341
342 slice = test_ally.resize(slice, bigpage_size * 2 + 1) orelse return;
343 try std.testing.expect(slice[0] == 0x12);
344 try std.testing.expect(slice[60] == 0x34);
345
346 slice = test_ally.shrink(slice, bigpage_size * 2 + 1);
347 try std.testing.expect(slice[0] == 0x12);
348 try std.testing.expect(slice[60] == 0x34);
349
350 slice = try test_ally.realloc(slice, bigpage_size * 2);
351 try std.testing.expect(slice[0] == 0x12);
352 try std.testing.expect(slice[60] == 0x34);
353}
354
355test "realloc large object to small object" {
356 var slice = try test_ally.alloc(u8, bigpage_size * 2 + 50);
357 defer test_ally.free(slice);
358 slice[0] = 0x12;
359 slice[16] = 0x34;
360
361 slice = try test_ally.realloc(slice, 19);
362 try std.testing.expect(slice[0] == 0x12);
363 try std.testing.expect(slice[16] == 0x34);
364}
365
366test "objects of size 1024 and 2048" {
367 const slice = try test_ally.alloc(u8, 1025);
368 const slice2 = try test_ally.alloc(u8, 3000);
369
370 test_ally.free(slice);
371 test_ally.free(slice2);
372}