Created
November 28, 2023 17:12
-
-
Save bryanburgers/2b0f08fd583cf0401a958d7e8edc7552 to your computer and use it in GitHub Desktop.
Companion code to https://burgers.io/complete-novice-wasm-allocator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module | |
(export "main" (func $main)) | |
;; Create memory with at least 1 page of 64k of memory | |
(memory $mem 1) | |
(func $main (result i32 i32) | |
;; write some data to an arbitrary memory location | |
i32.const 0xcafe ;; address | |
i32.const 42 ;; memory to write | |
i32.store | |
;; write some data to the last available byte | |
i32.const 0xffff | |
i32.const 43 | |
i32.store8 | |
;; read data from our arbitrary memory location | |
i32.const 0xcafe | |
i32.load | |
;; read data from the last available byte | |
i32.const 0xffff | |
i32.load8_u | |
) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module | |
(export "main" (func $main)) | |
;; Create memory with at least 1 page of 64k of memory | |
(memory $mem 1) | |
(func $main (result i32 i32 i32) | |
;; write some data to an arbitrary memory location | |
i32.const 0xcafe ;; address | |
i32.const 42 ;; memory to write | |
i32.store | |
;; ask for ten more pages of memory | |
i32.const 10 | |
memory.grow $mem | |
drop ;; ignore whatever memory.grow returned | |
;; write some data past the last byte of the first page | |
i32.const 0x10000 | |
i32.const 43 | |
i32.store8 | |
;; read data from our arbitrary memory location | |
i32.const 0xcafe | |
i32.load | |
;; read data from past the last byte of the first page | |
i32.const 0x10000 | |
i32.load8_u | |
;; get how much memory we have | |
memory.size | |
) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module | |
(export "main" (func $main)) | |
;; Create memory with at least 1 page of 64k of memory | |
(memory $mem 1) | |
(func $main (result i32) | |
(local $point1 i32) | |
(local $point2 i32) | |
i32.const 0x10 ;; Choose an arbitrary memory address | |
local.set $point1 | |
i32.const 0x20 ;; Choose another; hope it doesn't overlap! | |
local.set $point2 | |
local.get $point1 | |
i32.const 3 | |
i32.const 4 | |
call $point_initialize | |
local.get $point2 | |
i32.const 5 | |
i32.const 7 | |
call $point_initialize | |
local.get $point1 | |
local.get $point2 | |
call $point_manhattan_distance | |
) | |
;; Point | |
;; n n+8 n+16 | |
;; +--------+--------+ | |
;; | x: i32 | y: i32 | | |
;; +--------+--------+ | |
(func $point_initialize (param $ptr i32) (param $x i32) (param $y i32) | |
local.get $ptr | |
local.get $x | |
i32.store | |
local.get $ptr | |
i32.const 8 | |
i32.add | |
local.get $y | |
i32.store | |
) | |
(func $point_x (param $ptr i32) (result i32) | |
local.get $ptr | |
i32.load | |
) | |
(func $point_y (param $ptr i32) (result i32) | |
local.get $ptr | |
i32.const 8 | |
i32.add | |
i32.load | |
) | |
(func $point_vertical_distance (param $ptr1 i32) (param $ptr2 i32) (result i32) | |
(local $y1 i32) | |
(local $y2 i32) | |
local.get $ptr1 | |
call $point_y | |
local.set $y1 | |
local.get $ptr2 | |
call $point_y | |
local.set $y2 | |
local.get $y1 | |
local.get $y2 | |
i32.ge_s | |
(if (result i32) | |
(then | |
local.get $y1 | |
local.get $y2 | |
i32.sub | |
) | |
(else | |
local.get $y2 | |
local.get $y1 | |
i32.sub | |
) | |
) | |
) | |
(func $point_horizontal_distance (param $ptr1 i32) (param $ptr2 i32) (result i32) | |
(local $x1 i32) | |
(local $x2 i32) | |
local.get $ptr1 | |
call $point_x | |
local.set $x1 | |
local.get $ptr2 | |
call $point_x | |
local.set $x2 | |
local.get $x1 | |
local.get $x2 | |
i32.ge_s | |
(if (result i32) | |
(then | |
local.get $x1 | |
local.get $x2 | |
i32.sub | |
) | |
(else | |
local.get $x2 | |
local.get $x1 | |
i32.sub | |
) | |
) | |
) | |
(func $point_manhattan_distance (param $ptr1 i32) (param $ptr2 i32) (result i32) | |
local.get $ptr1 | |
local.get $ptr2 | |
call $point_vertical_distance | |
local.get $ptr1 | |
local.get $ptr2 | |
call $point_horizontal_distance | |
i32.add | |
) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module | |
(export "main" (func $main)) | |
;; Create memory with at least 1 page of 64k of memory | |
(memory $mem 1) | |
(func $main (result i32) | |
(local $point1 i32) | |
(local $point2 i32) | |
i32.const 3 | |
i32.const 4 | |
call $point_create | |
local.set $point1 | |
i32.const 5 | |
i32.const 7 | |
call $point_create | |
local.set $point2 | |
local.get $point1 | |
local.get $point2 | |
call $point_manhattan_distance | |
) | |
;; Point | |
;; n n+8 n+16 | |
;; +--------+--------+ | |
;; | x: i32 | y: i32 | | |
;; +--------+--------+ | |
(func $point_create (param $x i32) (param $y i32) (result i32) | |
(local $ptr i32) | |
;; A point is 16 bytes of data, so please, magic | |
;; function, give us 16 bytes of unused memory. | |
i32.const 16 | |
call $alloc | |
local.set $ptr | |
;; initialize $x at $ptr + 0 | |
local.get $ptr | |
local.get $x | |
i32.store | |
;; initialize $y at $ptr + 8 | |
local.get $ptr | |
i32.const 8 | |
i32.add | |
local.get $y | |
i32.store | |
;; return ptr | |
local.get $ptr | |
) | |
(func $point_x (param $ptr i32) (result i32) | |
local.get $ptr | |
i32.load | |
) | |
(func $point_y (param $ptr i32) (result i32) | |
local.get $ptr | |
i32.const 8 | |
i32.add | |
i32.load | |
) | |
(func $point_vertical_distance (param $ptr1 i32) (param $ptr2 i32) (result i32) | |
(local $y1 i32) | |
(local $y2 i32) | |
local.get $ptr1 | |
call $point_y | |
local.set $y1 | |
local.get $ptr2 | |
call $point_y | |
local.set $y2 | |
local.get $y1 | |
local.get $y2 | |
i32.ge_s | |
(if (result i32) | |
(then | |
local.get $y1 | |
local.get $y2 | |
i32.sub | |
) | |
(else | |
local.get $y2 | |
local.get $y1 | |
i32.sub | |
) | |
) | |
) | |
(func $point_horizontal_distance (param $ptr1 i32) (param $ptr2 i32) (result i32) | |
(local $x1 i32) | |
(local $x2 i32) | |
local.get $ptr1 | |
call $point_x | |
local.set $x1 | |
local.get $ptr2 | |
call $point_x | |
local.set $x2 | |
local.get $x1 | |
local.get $x2 | |
i32.ge_s | |
(if (result i32) | |
(then | |
local.get $x1 | |
local.get $x2 | |
i32.sub | |
) | |
(else | |
local.get $x2 | |
local.get $x1 | |
i32.sub | |
) | |
) | |
) | |
(func $point_manhattan_distance (param $ptr1 i32) (param $ptr2 i32) (result i32) | |
local.get $ptr1 | |
local.get $ptr2 | |
call $point_vertical_distance | |
local.get $ptr1 | |
local.get $ptr2 | |
call $point_horizontal_distance | |
i32.add | |
) | |
;; the pointer of the next allocation | |
(global $alloc_offset (mut i32) (i32.const 32)) | |
;; allocate some memory! | |
(func $alloc (param $size i32) (result (;pointer;) i32) | |
(local $curr_alloc_ptr i32) | |
(local $next_alloc_ptr i32) | |
;; get the current ptr | |
global.get $alloc_offset | |
local.set $curr_alloc_ptr | |
;; calculate the next ptr | |
local.get $curr_alloc_ptr | |
local.get $size | |
i32.add | |
local.set $next_alloc_ptr | |
;; store the ptr to the next allocation | |
local.get $next_alloc_ptr | |
global.set $alloc_offset | |
;; and return the current pointer | |
local.get $curr_alloc_ptr | |
) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module | |
(export "main" (func $main)) | |
;; Create memory with at least 1 page of 64k of memory | |
(memory $mem 1) | |
(func $main (result i32 i32 i32 i32) | |
i32.const 16 | |
call $alloc | |
i32.const 16 | |
call $alloc | |
i32.const 128 | |
call $alloc | |
i32.const 16 | |
call $alloc | |
) | |
;; the pointer of the next allocation | |
(global $alloc_offset (mut i32) (i32.const 32)) | |
;; allocate some memory! | |
(func $alloc (param $size i32) (result (;pointer;) i32) | |
(local $curr_alloc_ptr i32) | |
(local $next_alloc_ptr i32) | |
;; get the current ptr; we'll return this | |
;; to the caller | |
global.get $alloc_offset | |
local.set $curr_alloc_ptr | |
;; "bump" over the bytes that we're giving | |
;; to the caller, and store that as the next | |
;; available pointer | |
local.get $curr_alloc_ptr | |
local.get $size | |
i32.add | |
local.set $next_alloc_ptr | |
;; store the ptr to the next allocation | |
local.get $next_alloc_ptr | |
global.set $alloc_offset | |
;; and return the current pointer | |
local.get $curr_alloc_ptr | |
) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module | |
(export "main" (func $main)) | |
;; Create memory with at least 1 page of 64k of memory | |
(memory $mem 1) | |
(func $main (result i32 i32 i32 i32 i32) | |
i32.const 65000 | |
call $alloc | |
i32.const 65000 | |
call $alloc | |
i32.const 65000 | |
call $alloc | |
i32.const 128 | |
call $alloc | |
memory.size | |
) | |
;; the pointer of the next allocation | |
(global $alloc.offset (mut i32) (i32.const 32)) | |
(func $alloc (param $size i32) (result (;pointer;) i32) | |
(local $this_alloc_ptr i32) | |
(local $next_alloc_ptr i32) | |
(local $current_capacity i32) | |
;; If the requested size is more than a 64k page, fail. | |
local.get $size | |
i32.const 65536 | |
i32.gt_u | |
(if | |
(then | |
i32.const 0x01 | |
unreachable | |
) | |
) | |
;; calculate the current ptr and the next ptr | |
global.get $alloc.offset | |
local.tee $this_alloc_ptr | |
local.get $size | |
i32.add | |
local.set $next_alloc_ptr | |
;; If this allocation extends into a page of memory we haven't reserved | |
;; we need to reserve more memory | |
memory.size | |
i32.const 65536 | |
i32.mul | |
local.set $current_capacity | |
local.get $next_alloc_ptr | |
local.get $current_capacity | |
i32.gt_u | |
(if | |
(then | |
i32.const 1 | |
memory.grow | |
;; if memory couldn't grow, panic | |
i32.const -1 | |
i32.eq | |
(if | |
(then | |
i32.const 0x02 | |
unreachable | |
) | |
) | |
) | |
) | |
;; store the ptr to the next allocation | |
local.get $next_alloc_ptr | |
global.set $alloc.offset | |
;; and return the current pointer | |
local.get $this_alloc_ptr | |
) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment