| ... | @@ -252,10 +252,6 @@ extern const __heap_base: [*]u8; | ... | @@ -252,10 +252,6 @@ extern const __heap_base: [*]u8; |
| 252 | extern fn @"llvm.wasm.memory.size.i32"(u32) u32; | 252 | extern fn @"llvm.wasm.memory.size.i32"(u32) u32; |
| 253 | extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32; | 253 | extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32; |
| 254 | | 254 | |
| 255 | test "" { | | |
| 256 | _ = WasmPageAllocator.realloc; | | |
| 257 | } | | |
| 258 | | | |
| 259 | const WasmPageAllocator = struct { | 255 | const WasmPageAllocator = struct { |
| 260 | // TODO: figure out why __heap_base cannot be found | 256 | // TODO: figure out why __heap_base cannot be found |
| 261 | var heap_base_wannabe: [256]u8 = undefined; | 257 | var heap_base_wannabe: [256]u8 = undefined; |
| ... | @@ -275,7 +271,7 @@ const WasmPageAllocator = struct { | ... | @@ -275,7 +271,7 @@ const WasmPageAllocator = struct { |
| 275 | } | 271 | } |
| 276 | | 272 | |
| 277 | // TODO: optimize this terribleness | 273 | // TODO: optimize this terribleness |
| 278 | fn alloc(self: *FreeBlock, num_pages: usize) ?[]u8 { | 274 | fn useRecycled(self: *FreeBlock, num_pages: usize) ?[*]u8 { |
| 279 | var found_idx: usize = 0; | 275 | var found_idx: usize = 0; |
| 280 | var found_size: usize = 0; | 276 | var found_size: usize = 0; |
| 281 | | 277 | |
| ... | @@ -290,15 +286,18 @@ const WasmPageAllocator = struct { | ... | @@ -290,15 +286,18 @@ const WasmPageAllocator = struct { |
| 290 | found_size += 1; | 286 | found_size += 1; |
| 291 | | 287 | |
| 292 | if (found_size >= num_pages) { | 288 | if (found_size >= num_pages) { |
| 293 | const page_ptr = @intToPtr([*]u8, (found_idx + self.offset) * std.mem.page_size); | 289 | while (found_size > 0) { |
| 294 | return page_ptr[0 .. found_size * std.mem.page_size]; | 290 | found_size -= 1; |
| | 291 | self.packed_data.set(found_idx + found_size, 0); |
| | 292 | } |
| | 293 | return @intToPtr([*]u8, (found_idx + self.offset) * std.mem.page_size); |
| 295 | } | 294 | } |
| 296 | } | 295 | } |
| 297 | } | 296 | } |
| 298 | return null; | 297 | return null; |
| 299 | } | 298 | } |
| 300 | | 299 | |
| 301 | fn reclaim(self: *FreeBlock, start_index: usize, end_index: usize) void { | 300 | fn recycle(self: *FreeBlock, start_index: usize, end_index: usize) void { |
| 302 | var i = start_index - self.offset; | 301 | var i = start_index - self.offset; |
| 303 | while (i < end_index - self.offset) : (i += 1) { | 302 | while (i < end_index - self.offset) : (i += 1) { |
| 304 | std.debug.assert(self.packed_data.get(i) == 0); | 303 | std.debug.assert(self.packed_data.get(i) == 0); |
| ... | @@ -315,23 +314,24 @@ const WasmPageAllocator = struct { | ... | @@ -315,23 +314,24 @@ const WasmPageAllocator = struct { |
| 315 | } | 314 | } |
| 316 | | 315 | |
| 317 | fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 { | 316 | fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 { |
| 318 | if (alignment > std.mem.page_size) { | | |
| 319 | return error.OutOfMemory; | | |
| 320 | } | | |
| 321 | | | |
| 322 | const n_pages = nPages(n); | 317 | const n_pages = nPages(n); |
| 323 | return conventional.alloc(n_pages) orelse extended.alloc(n_pages) orelse { | 318 | const page = conventional.useRecycled(n_pages) orelse extended.useRecycled(n_pages) orelse blk: { |
| 324 | const prev_page_count = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, n_pages)); | 319 | const prev_page_count = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, n_pages)); |
| 325 | if (prev_page_count < 0) { | 320 | if (prev_page_count < 0) { |
| 326 | return error.OutOfMemory; | 321 | return error.OutOfMemory; |
| 327 | } | 322 | } |
| 328 | | 323 | |
| 329 | const start_ptr = @intToPtr([*]u8, @intCast(usize, prev_page_count) * std.mem.page_size); | 324 | break :blk @intToPtr([*]u8, @intCast(usize, prev_page_count) * std.mem.page_size); |
| 330 | return start_ptr[0..n]; | | |
| 331 | }; | 325 | }; |
| | 326 | |
| | 327 | return page[0..n]; |
| 332 | } | 328 | } |
| 333 | | 329 | |
| 334 | pub fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) Allocator.Error![]u8 { | 330 | pub fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) Allocator.Error![]u8 { |
| | 331 | if (new_align > std.mem.page_size) { |
| | 332 | return error.OutOfMemory; |
| | 333 | } |
| | 334 | |
| 335 | if (old_mem.len == 0) { | 335 | if (old_mem.len == 0) { |
| 336 | return alloc(allocator, new_size, new_align); | 336 | return alloc(allocator, new_size, new_align); |
| 337 | } else if (new_size < old_mem.len) { | 337 | } else if (new_size < old_mem.len) { |
| ... | @@ -352,21 +352,22 @@ const WasmPageAllocator = struct { | ... | @@ -352,21 +352,22 @@ const WasmPageAllocator = struct { |
| 352 | | 352 | |
| 353 | if (free_end > free_start) { | 353 | if (free_end > free_start) { |
| 354 | if (conventional.totalPages() == 0) { | 354 | if (conventional.totalPages() == 0) { |
| | 355 | conventional.offset = 0; |
| 355 | //conventional.initData(__heap_base[0..@intCast(usize, @"llvm.wasm.memory.size.i32"(0) * std.mem.page_size)]); | 356 | //conventional.initData(__heap_base[0..@intCast(usize, @"llvm.wasm.memory.size.i32"(0) * std.mem.page_size)]); |
| 356 | conventional.initData(heap_base_wannabe[0..]); | 357 | conventional.initData(heap_base_wannabe[0..]); |
| 357 | } | 358 | } |
| 358 | | 359 | |
| 359 | if (free_start < conventional.totalPages()) { | 360 | if (free_start < conventional.totalPages()) { |
| 360 | conventional.reclaim(free_start, free_end); | 361 | conventional.recycle(free_start, free_end); |
| 361 | } else { | 362 | } else { |
| 362 | if (extended.totalPages() == 0) { | 363 | if (extended.totalPages() == 0) { |
| 363 | extended.offset = conventional.totalPages(); | 364 | extended.offset = conventional.offset + conventional.totalPages(); |
| 364 | | 365 | |
| 365 | // Steal the last page from the memory currently being reclaimed | 366 | // Steal the last page from the memory currently being recycled |
| 366 | free_end -= 1; | 367 | free_end -= 1; |
| 367 | extended.initData(@intToPtr([*]u8, free_end)[0..std.mem.page_size]); | 368 | extended.initData(@intToPtr([*]u8, free_end * std.mem.page_size)[0..std.mem.page_size]); |
| 368 | } | 369 | } |
| 369 | conventional.reclaim(free_start, free_end); | 370 | extended.recycle(free_start, free_end); |
| 370 | } | 371 | } |
| 371 | } | 372 | } |
| 372 | | 373 | |
| ... | @@ -932,7 +933,8 @@ fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !voi | ... | @@ -932,7 +933,8 @@ fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !voi |
| 932 | fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void { | 933 | fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void { |
| 933 | //Maybe a platform's page_size is actually the same as or | 934 | //Maybe a platform's page_size is actually the same as or |
| 934 | // very near usize? | 935 | // very near usize? |
| 935 | if (mem.page_size << 2 > maxInt(usize)) return; | 936 | //if (mem.page_size << 2 > maxInt(usize)) return; |
| | 937 | if (mem.page_size << 2 > 32768) return; |
| 936 | | 938 | |
| 937 | const USizeShift = @IntType(false, std.math.log2(usize.bit_count)); | 939 | const USizeShift = @IntType(false, std.math.log2(usize.bit_count)); |
| 938 | const large_align = @as(u29, mem.page_size << 2); | 940 | const large_align = @as(u29, mem.page_size << 2); |