authorgravatar for contact@fengb.meBenjamin Feng <contact@fengb.me> 2019-11-27 18:46:42-06:00
committergravatar for contact@fengb.meBenjamin Feng <contact@fengb.me> 2019-12-02 09:59:20-06:00
logeff926b4545fea9f87559d2e1d7372d6cbeba780
tree8d40211ce69ef934c0133a03be063efbf5f1015a
parentfc1373a85d55698575f361100f0867e15d6ec1d3

Brain dump new wasm allocator


1 files changed, 46 insertions(+), 58 deletions(-)

lib/std/heap.zig+46-58
...@@ -246,84 +246,72 @@ const PageAllocator = struct {...@@ -246,84 +246,72 @@ const PageAllocator = struct {
246 }246 }
247};247};
248248
249extern const __heap_base: [*]u8;
249// TODO Exposed LLVM intrinsics is a bug250// TODO Exposed LLVM intrinsics is a bug
250// See: https://github.com/ziglang/zig/issues/2291251// See: https://github.com/ziglang/zig/issues/2291
251extern fn @"llvm.wasm.memory.size.i32"(u32) u32;252extern fn @"llvm.wasm.memory.size.i32"(u32) u32;
252extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32;253extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32;
253254
254/// TODO: make this re-use freed pages, and cooperate with other callers of these global intrinsics255test "" {
255/// by better utilizing the return value of grow()256 _ = WasmPageAllocator.alloc;
257}
258
256const WasmPageAllocator = struct {259const WasmPageAllocator = struct {
257 var start_ptr: [*]u8 = undefined;260 const FreeBlock = struct {
258 var num_pages: usize = 0;261 offset: usize = 0,
259 var end_index: usize = 0;262 data: []u8 = &[_]u8{},
260263
261 comptime {264 fn alloc(self: FreeBlock, num_pages: usize) ?[]u8 {
262 if (builtin.arch != .wasm32) {265 return null;
263 @compileError("WasmPageAllocator is only available for wasm32 arch");
264 }266 }
265 }267 };
266268 var base = FreeBlock{};
267 fn alloc(allocator: *Allocator, size: usize, alignment: u29) ![]u8 {269 var additional = FreeBlock{};
268 const addr = @ptrToInt(start_ptr) + end_index;
269 const adjusted_addr = mem.alignForward(addr, alignment);
270 const adjusted_index = end_index + (adjusted_addr - addr);
271 const new_end_index = adjusted_index + size;
272270
273 if (new_end_index > num_pages * mem.page_size) {271 fn nPages(memsize: usize) usize {
274 const required_memory = new_end_index - (num_pages * mem.page_size);272 return std.mem.alignForward(memsize, std.mem.page_size) / std.mem.page_size;
273 }
275274
276 var inner_num_pages: usize = required_memory / mem.page_size;275 fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 {
277 if (required_memory % mem.page_size != 0) {276 if (alignment > std.mem.page_size) {
278 inner_num_pages += 1;277 return error.OutOfMemory;
279 }278 }
280279
281 const prev_page = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, inner_num_pages));280 const n_pages = nPages(n);
282 if (prev_page == -1) {281 return base.alloc(n_pages) orelse additional.alloc(n_pages) orelse {
282 const prev_page_count = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, n_pages));
283 if (prev_page_count < 0) {
283 return error.OutOfMemory;284 return error.OutOfMemory;
284 }285 }
285286
286 num_pages += inner_num_pages;287 const start_ptr = @intToPtr([*]u8, @intCast(usize, prev_page_count) * std.mem.page_size);
287 }288 return start_ptr[0..n];
288289 };
289 const result = start_ptr[adjusted_index..new_end_index];
290 end_index = new_end_index;
291
292 return result;
293 }
294
295 // Check if memory is the last "item" and is aligned correctly
296 fn is_last_item(memory: []u8, alignment: u29) bool {
297 return memory.ptr == start_ptr + end_index - memory.len and mem.alignForward(@ptrToInt(memory.ptr), alignment) == @ptrToInt(memory.ptr);
298 }290 }
299291
300 fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {292 pub fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) Allocator.Error![]u8 {
301 // Initialize start_ptr at the first realloc293 if (old_mem.len == 0) {
302 if (num_pages == 0) {294 return alloc(allocator, new_size, new_align);
303 start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * mem.page_size);295 } else if (new_size < old_mem.len) {
304 }296 return shrink(allocator, old_mem, old_align, new_size, new_align);
305297 } else if (nPages(new_size) == nPages(old_mem.len)) {
306 if (is_last_item(old_mem, new_align)) {298 return old_mem.ptr[0..new_size];
307 const start_index = end_index - old_mem.len;
308 const new_end_index = start_index + new_size;
309
310 if (new_end_index > num_pages * mem.page_size) {
311 _ = try alloc(allocator, new_end_index - end_index, new_align);
312 }
313 const result = start_ptr[start_index..new_end_index];
314
315 end_index = new_end_index;
316 return result;
317 } else if (new_size <= old_mem.len and new_align <= old_align) {
318 return error.OutOfMemory;
319 } else {299 } else {
320 const result = try alloc(allocator, new_size, new_align);300 const new_mem = try alloc(allocator, new_size, new_align);
321 mem.copy(u8, result, old_mem);301 std.mem.copy(u8, new_mem, old_mem);
322 return result;302 _ = shrink(allocator, old_mem, old_align, 0, 0);
303 return new_mem[0..new_size];
323 }304 }
324 }305 }
325306
326 fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {307 pub fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
308 var shrinkage = nPages(old_mem.len) - nPages(new_size);
309 if (shrinkage > 0) {
310 const success = base.recycle(old_mem[new_size..old_mem.len]);
311 if (!success) {
312 std.debug.assert(additional.recycle(old_mem[new_size..old_mem.len]));
313 }
314 }
327 return old_mem[0..new_size];315 return old_mem[0..new_size];
328 }316 }
329};317};