| ... | ... | @@ -256,7 +256,7 @@ const WasmPageAllocator = struct { |
| 256 | 256 | used = 0, |
| 257 | 257 | free = 1, |
| 258 | 258 | |
| 259 | | pub const all_used: u8 = 0; |
| 259 | pub const none_free: u8 = 0; |
| 260 | 260 | }; |
| 261 | 261 | |
| 262 | 262 | const FreeBlock = struct { |
| ... | ... | @@ -265,7 +265,11 @@ const WasmPageAllocator = struct { |
| 265 | 265 | const Io = std.packed_int_array.PackedIntIo(u1, .Little); |
| 266 | 266 | |
| 267 | 267 | fn totalPages(self: FreeBlock) usize { |
| 268 | | return self.data.len * 8; |
| 268 | return self.data.len * 128; |
| 269 | } |
| 270 | |
| 271 | fn isInitialized(self: FreeBlock) bool { |
| 272 | return self.data.len > 0; |
| 269 | 273 | } |
| 270 | 274 | |
| 271 | 275 | fn getBit(self: FreeBlock, idx: usize) PageStatus { |
| ... | ... | @@ -319,7 +323,9 @@ const WasmPageAllocator = struct { |
| 319 | 323 | } |
| 320 | 324 | }; |
| 321 | 325 | |
| 322 | | const conventional = FreeBlock{ .data = &[_]u128{ 0, 0 } }; |
| 326 | var _conventional_data = [_]u128{0} ** 16; |
| 327 | // Marking `conventional` as const saves ~40 bytes |
| 328 | var conventional = FreeBlock{ .data = &_conventional_data }; |
| 323 | 329 | var extended = FreeBlock{ .data = &[_]u128{} }; |
| 324 | 330 | |
| 325 | 331 | fn extendedOffset() usize { |
| ... | ... | @@ -379,14 +385,14 @@ const WasmPageAllocator = struct { |
| 379 | 385 | } |
| 380 | 386 | |
| 381 | 387 | if (free_end > extendedOffset()) { |
| 382 | | if (extended.totalPages() == 0) { |
| 388 | if (!extended.isInitialized()) { |
| 383 | 389 | // Steal the last page from the memory currently being recycled |
| 384 | 390 | // TODO: would it be better if we use the first page instead? |
| 385 | 391 | free_end -= 1; |
| 386 | 392 | |
| 387 | 393 | extended.data = @intToPtr([*]u128, free_end * std.mem.page_size)[0 .. std.mem.page_size / @sizeOf(u128)]; |
| 388 | 394 | // Since this is the first page being freed and we consume it, assume *nothing* is free. |
| 389 | | std.mem.set(u128, extended.data, PageStatus.all_used); |
| 395 | std.mem.set(u128, extended.data, PageStatus.none_free); |
| 390 | 396 | } |
| 391 | 397 | const clamped_start = std.math.max(extendedOffset(), free_start); |
| 392 | 398 | extended.recycle(clamped_start - extendedOffset(), free_end - clamped_start); |
| ... | ... | @@ -790,6 +796,38 @@ test "c_allocator" { |
| 790 | 796 | } |
| 791 | 797 | } |
| 792 | 798 | |
| 799 | test "WasmPageAllocator internals" { |
| 800 | if (std.Target.current.isWasm()) { |
| 801 | const none_free = WasmPageAllocator.PageStatus.none_free; |
| 802 | std.debug.assert(none_free == WasmPageAllocator.conventional.data[0]); // Passes if this test runs first |
| 803 | std.debug.assert(!WasmPageAllocator.extended.isInitialized()); // Passes if this test runs first |
| 804 | |
| 805 | const tmp = try page_allocator.alloc(u8, 1); |
| 806 | testing.expect(none_free == WasmPageAllocator.conventional.data[0]); |
| 807 | page_allocator.free(tmp); |
| 808 | testing.expect(none_free < WasmPageAllocator.conventional.data[0]); |
| 809 | |
| 810 | const a_little_free = WasmPageAllocator.conventional.data[0]; |
| 811 | const tmp_large = try page_allocator.alloc(u8, std.mem.page_size + 1); |
| 812 | testing.expect(a_little_free == WasmPageAllocator.conventional.data[0]); |
| 813 | const tmp_small = try page_allocator.alloc(u8, 1); |
| 814 | testing.expect(none_free == WasmPageAllocator.conventional.data[0]); |
| 815 | |
| 816 | page_allocator.free(tmp_small); |
| 817 | testing.expect(a_little_free == WasmPageAllocator.conventional.data[0]); |
| 818 | page_allocator.free(tmp_large); |
| 819 | testing.expect(a_little_free < WasmPageAllocator.conventional.data[0]); |
| 820 | |
| 821 | const more_free = WasmPageAllocator.conventional.data[0]; |
| 822 | const supersize = try page_allocator.alloc(u8, std.mem.page_size * (WasmPageAllocator.conventional.totalPages() + 1)); |
| 823 | testing.expect(more_free == WasmPageAllocator.conventional.data[0]); |
| 824 | testing.expect(!WasmPageAllocator.extended.isInitialized()); |
| 825 | page_allocator.free(supersize); |
| 826 | testing.expect(WasmPageAllocator.extended.isInitialized()); |
| 827 | testing.expect(more_free < WasmPageAllocator.conventional.data[0]); |
| 828 | } |
| 829 | } |
| 830 | |
| 793 | 831 | test "PageAllocator" { |
| 794 | 832 | const allocator = page_allocator; |
| 795 | 833 | try testAllocator(allocator); |