| ... | ... | @@ -246,16 +246,12 @@ const PageAllocator = struct { |
| 246 | 246 | } |
| 247 | 247 | }; |
| 248 | 248 | |
| 249 | | extern const __heap_base: [*]u8; |
| 250 | 249 | // TODO Exposed LLVM intrinsics is a bug |
| 251 | 250 | // See: https://github.com/ziglang/zig/issues/2291 |
| 252 | 251 | extern fn @"llvm.wasm.memory.size.i32"(u32) u32; |
| 253 | 252 | extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32; |
| 254 | 253 | |
| 255 | 254 | const WasmPageAllocator = struct { |
| 256 | | // TODO: figure out why __heap_base cannot be found |
| 257 | | var heap_base_wannabe align(16) = [_]u8{0} ** 256; |
| 258 | | |
| 259 | 255 | const PageStatus = enum(u1) { |
| 260 | 256 | used = 0, |
| 261 | 257 | free = 1, |
| ... | ... | @@ -264,24 +260,24 @@ const WasmPageAllocator = struct { |
| 264 | 260 | }; |
| 265 | 261 | |
| 266 | 262 | const FreeBlock = struct { |
| 267 | | bytes: []align(16) u8, |
| 263 | data: []u128, |
| 268 | 264 | |
| 269 | 265 | const Io = std.packed_int_array.PackedIntIo(u1, .Little); |
| 270 | 266 | |
| 271 | 267 | fn totalPages(self: FreeBlock) usize { |
| 272 | | return self.bytes.len * 8; |
| 268 | return self.data.len * 8; |
| 273 | 269 | } |
| 274 | 270 | |
| 275 | | fn getBit(self: *FreeBlock, idx: usize) PageStatus { |
| 271 | fn getBit(self: FreeBlock, idx: usize) PageStatus { |
| 276 | 272 | const bit_offset = 0; |
| 277 | | return @intToEnum(PageStatus, Io.get(self.bytes, idx, bit_offset)); |
| 273 | return @intToEnum(PageStatus, Io.get(@sliceToBytes(self.data), idx, bit_offset)); |
| 278 | 274 | } |
| 279 | 275 | |
| 280 | | fn setBits(self: *FreeBlock, start_idx: usize, len: usize, val: PageStatus) void { |
| 276 | fn setBits(self: FreeBlock, start_idx: usize, len: usize, val: PageStatus) void { |
| 281 | 277 | const bit_offset = 0; |
| 282 | 278 | var i: usize = 0; |
| 283 | 279 | while (i < len) : (i += 1) { |
| 284 | | Io.set(self.bytes, start_idx + i, bit_offset, @enumToInt(val)); |
| 280 | Io.set(@sliceToBytes(self.data), start_idx + i, bit_offset, @enumToInt(val)); |
| 285 | 281 | } |
| 286 | 282 | } |
| 287 | 283 | |
| ... | ... | @@ -294,10 +290,9 @@ const WasmPageAllocator = struct { |
| 294 | 290 | // Revisit if this is settled: https://github.com/ziglang/zig/issues/3806 |
| 295 | 291 | const not_found = std.math.maxInt(usize); |
| 296 | 292 | |
| 297 | | fn useRecycled(self: *FreeBlock, num_pages: usize) usize { |
| 293 | fn useRecycled(self: FreeBlock, num_pages: usize) usize { |
| 298 | 294 | @setCold(true); |
| 299 | | const segments = @bytesToSlice(u128, self.bytes); |
| 300 | | for (segments) |segment, i| { |
| 295 | for (self.data) |segment, i| { |
| 301 | 296 | const spills_into_next = @bitCast(i128, segment) < 0; |
| 302 | 297 | const has_enough_bits = @popCount(u128, segment) >= num_pages; |
| 303 | 298 | |
| ... | ... | @@ -319,13 +314,13 @@ const WasmPageAllocator = struct { |
| 319 | 314 | return not_found; |
| 320 | 315 | } |
| 321 | 316 | |
| 322 | | fn recycle(self: *FreeBlock, start_idx: usize, len: usize) void { |
| 317 | fn recycle(self: FreeBlock, start_idx: usize, len: usize) void { |
| 323 | 318 | self.setBits(start_idx, len, .free); |
| 324 | 319 | } |
| 325 | 320 | }; |
| 326 | 321 | |
| 327 | | var conventional = FreeBlock{ .bytes = &[_]u8{} }; |
| 328 | | var extended = FreeBlock{ .bytes = &[_]u8{} }; |
| 322 | const conventional = FreeBlock{ .data = &[_]u128{ 0, 0 } }; |
| 323 | var extended = FreeBlock{ .data = &[_]u128{} }; |
| 329 | 324 | |
| 330 | 325 | fn extendedOffset() usize { |
| 331 | 326 | return conventional.totalPages(); |
| ... | ... | @@ -373,15 +368,11 @@ const WasmPageAllocator = struct { |
| 373 | 368 | } |
| 374 | 369 | |
| 375 | 370 | pub fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { |
| 371 | @setCold(true); |
| 376 | 372 | const free_start = nPages(@ptrToInt(old_mem.ptr) + new_size); |
| 377 | 373 | var free_end = nPages(@ptrToInt(old_mem.ptr) + old_mem.len); |
| 378 | 374 | |
| 379 | 375 | if (free_end > free_start) { |
| 380 | | if (conventional.totalPages() == 0) { |
| 381 | | //conventional.bytes = __heap_base[0..@intCast(usize, @"llvm.wasm.memory.size.i32"(0) * std.mem.page_size)]; |
| 382 | | conventional.bytes = heap_base_wannabe[0..]; |
| 383 | | } |
| 384 | | |
| 385 | 376 | if (free_start < extendedOffset()) { |
| 386 | 377 | const clamped_end = std.math.min(extendedOffset(), free_end); |
| 387 | 378 | conventional.recycle(free_start, clamped_end - free_start); |
| ... | ... | @@ -393,9 +384,9 @@ const WasmPageAllocator = struct { |
| 393 | 384 | // TODO: would it be better if we use the first page instead? |
| 394 | 385 | free_end -= 1; |
| 395 | 386 | |
| 396 | | extended.bytes = @intToPtr([*]align(16) u8, free_end * std.mem.page_size)[0..std.mem.page_size]; |
| 387 | extended.data = @intToPtr([*]u128, free_end * std.mem.page_size)[0 .. std.mem.page_size / @sizeOf(u128)]; |
| 397 | 388 | // Since this is the first page being freed and we consume it, assume *nothing* is free. |
| 398 | | std.mem.set(u8, extended.bytes, PageStatus.all_used); |
| 389 | std.mem.set(u128, extended.data, PageStatus.all_used); |
| 399 | 390 | } |
| 400 | 391 | const clamped_start = std.math.max(extendedOffset(), free_start); |
| 401 | 392 | extended.recycle(clamped_start - extendedOffset(), free_end - clamped_start); |