@@ -327,6 +327,97 @@ pub const FixedBufferAllocator = struct {
327
327
}
328
328
};
329
329
330
+ // FIXME: Exposed LLVM intrinsics is a bug
331
+ // See: https://github.com/ziglang/zig/issues/2291
332
+ extern fn @"llvm.wasm.memory.size.i32" (u32 ) u32 ;
333
+ extern fn @"llvm.wasm.memory.grow.i32" (u32 , u32 ) i32 ;
334
+
335
+ pub const wasm_allocator = & wasm_allocator_state .allocator ;
336
+ var wasm_allocator_state = WasmAllocator {
337
+ .allocator = Allocator {
338
+ .reallocFn = WasmAllocator .realloc ,
339
+ .shrinkFn = WasmAllocator .shrink ,
340
+ },
341
+ .start_ptr = undefined ,
342
+ .num_pages = 0 ,
343
+ .end_index = 0 ,
344
+ };
345
+
346
+ const WasmAllocator = struct {
347
+ allocator : Allocator ,
348
+ start_ptr : [* ]u8 ,
349
+ num_pages : usize ,
350
+ end_index : usize ,
351
+
352
+ fn alloc (allocator : * Allocator , size : usize , alignment : u29 ) ! []u8 {
353
+ const self = @fieldParentPtr (WasmAllocator , "allocator" , allocator );
354
+
355
+ const addr = @ptrToInt (self .start_ptr ) + self .end_index ;
356
+ const adjusted_addr = mem .alignForward (addr , alignment );
357
+ const adjusted_index = self .end_index + (adjusted_addr - addr );
358
+ const new_end_index = adjusted_index + size ;
359
+
360
+ if (new_end_index > self .num_pages * os .page_size ) {
361
+ const required_memory = new_end_index - (self .num_pages * os .page_size );
362
+
363
+ var num_pages : u32 = required_memory / os .page_size ;
364
+ if (required_memory % os .page_size != 0 ) {
365
+ num_pages += 1 ;
366
+ }
367
+
368
+ const prev_page = @"llvm.wasm.memory.grow.i32" (0 , num_pages );
369
+ if (prev_page == -1 ) {
370
+ return error .OutOfMemory ;
371
+ }
372
+
373
+ self .num_pages += num_pages ;
374
+ }
375
+
376
+ const result = self .start_ptr [adjusted_index .. new_end_index ];
377
+ self .end_index = new_end_index ;
378
+
379
+ return result ;
380
+ }
381
+
382
+ // Check if memory is the last "item" and is aligned correctly
383
+ fn is_last_item (allocator : * Allocator , memory : []u8 , alignment : u29 ) bool {
384
+ const self = @fieldParentPtr (WasmAllocator , "allocator" , allocator );
385
+ return memory .ptr == self .start_ptr + self .end_index - memory .len and mem .alignForward (@ptrToInt (memory .ptr ), alignment ) == @ptrToInt (memory .ptr );
386
+ }
387
+
388
+ fn realloc (allocator : * Allocator , old_mem : []u8 , old_align : u29 , new_size : usize , new_align : u29 ) ! []u8 {
389
+ const self = @fieldParentPtr (WasmAllocator , "allocator" , allocator );
390
+
391
+ // Initialize start_ptr at the first realloc
392
+ if (self .num_pages == 0 ) {
393
+ self .start_ptr = @intToPtr ([* ]u8 , @intCast (usize , @"llvm.wasm.memory.size.i32" (0 )) * os .page_size );
394
+ }
395
+
396
+ if (is_last_item (allocator , old_mem , new_align )) {
397
+ const start_index = self .end_index - old_mem .len ;
398
+ const new_end_index = start_index + new_size ;
399
+
400
+ if (new_end_index > self .num_pages * os .page_size ) {
401
+ _ = try alloc (allocator , new_end_index - self .end_index , new_align );
402
+ }
403
+ const result = self .start_ptr [start_index .. new_end_index ];
404
+
405
+ self .end_index = new_end_index ;
406
+ return result ;
407
+ } else if (new_size <= old_mem .len and new_align <= old_align ) {
408
+ return error .OutOfMemory ;
409
+ } else {
410
+ const result = try alloc (allocator , new_size , new_align );
411
+ mem .copy (u8 , result , old_mem );
412
+ return result ;
413
+ }
414
+ }
415
+
416
+ fn shrink (allocator : * Allocator , old_mem : []u8 , old_align : u29 , new_size : usize , new_align : u29 ) []u8 {
417
+ return old_mem [0.. new_size ];
418
+ }
419
+ };
420
+
330
421
pub const ThreadSafeFixedBufferAllocator = blk : {
331
422
if (builtin .single_threaded ) {
332
423
break :blk FixedBufferAllocator ;
0 commit comments