| ... | @@ -256,7 +256,7 @@ const WasmPageAllocator = struct { | ... | @@ -256,7 +256,7 @@ const WasmPageAllocator = struct { |
| 256 | used = 0, | 256 | used = 0, |
| 257 | free = 1, | 257 | free = 1, |
| 258 | | 258 | |
| 259 | pub const all_used: u8 = 0; | 259 | pub const none_free: u8 = 0; |
| 260 | }; | 260 | }; |
| 261 | | 261 | |
| 262 | const FreeBlock = struct { | 262 | const FreeBlock = struct { |
| ... | @@ -265,7 +265,11 @@ const WasmPageAllocator = struct { | ... | @@ -265,7 +265,11 @@ const WasmPageAllocator = struct { |
| 265 | const Io = std.packed_int_array.PackedIntIo(u1, .Little); | 265 | const Io = std.packed_int_array.PackedIntIo(u1, .Little); |
| 266 | | 266 | |
| 267 | fn totalPages(self: FreeBlock) usize { | 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 | fn getBit(self: FreeBlock, idx: usize) PageStatus { | 275 | fn getBit(self: FreeBlock, idx: usize) PageStatus { |
| ... | @@ -319,7 +323,9 @@ const WasmPageAllocator = struct { | ... | @@ -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 | var extended = FreeBlock{ .data = &[_]u128{} }; | 329 | var extended = FreeBlock{ .data = &[_]u128{} }; |
| 324 | | 330 | |
| 325 | fn extendedOffset() usize { | 331 | fn extendedOffset() usize { |
| ... | @@ -379,14 +385,14 @@ const WasmPageAllocator = struct { | ... | @@ -379,14 +385,14 @@ const WasmPageAllocator = struct { |
| 379 | } | 385 | } |
| 380 | | 386 | |
| 381 | if (free_end > extendedOffset()) { | 387 | if (free_end > extendedOffset()) { |
| 382 | if (extended.totalPages() == 0) { | 388 | if (!extended.isInitialized()) { |
| 383 | // Steal the last page from the memory currently being recycled | 389 | // Steal the last page from the memory currently being recycled |
| 384 | // TODO: would it be better if we use the first page instead? | 390 | // TODO: would it be better if we use the first page instead? |
| 385 | free_end -= 1; | 391 | free_end -= 1; |
| 386 | | 392 | |
| 387 | extended.data = @intToPtr([*]u128, free_end * std.mem.page_size)[0 .. std.mem.page_size / @sizeOf(u128)]; | 393 | extended.data = @intToPtr([*]u128, free_end * std.mem.page_size)[0 .. std.mem.page_size / @sizeOf(u128)]; |
| 388 | // Since this is the first page being freed and we consume it, assume *nothing* is free. | 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 | const clamped_start = std.math.max(extendedOffset(), free_start); | 397 | const clamped_start = std.math.max(extendedOffset(), free_start); |
| 392 | extended.recycle(clamped_start - extendedOffset(), free_end - clamped_start); | 398 | extended.recycle(clamped_start - extendedOffset(), free_end - clamped_start); |
| ... | @@ -790,6 +796,38 @@ test "c_allocator" { | ... | @@ -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 | test "PageAllocator" { | 831 | test "PageAllocator" { |
| 794 | const allocator = page_allocator; | 832 | const allocator = page_allocator; |
| 795 | try testAllocator(allocator); | 833 | try testAllocator(allocator); |