DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / wasm / platform_wasi.wam
1 (module $platform_wasi
2
3 (memory 256)
4 (export "memory" (memory 0))
5
6 (global $WASI_RIGHT_FD_READ i64 (i64.const 2))
7 (global $WASI_ESUCCESS i32 0)
8 (global $WASI_EBADF i32 8)
9 (global $WASI_PREOPENTYPE_DIR i32 0)
10
11 (import "wasi_unstable" "args_get" (func $args_get (param i32 i32) (result i32)))
12 (import "wasi_unstable" "args_sizes_get" (func $args_sizes_get (param i32 i32) (result i32)))
13 (import "wasi_unstable" "clock_time_get" (func $clock_time_get (param i32 i64 i32) (result i32)))
14 (import "wasi_unstable" "fd_prestat_get" (func $fd_prestat_get (param i32 i32) (result i32)))
15 (import "wasi_unstable" "fd_prestat_dir_name" (func $fd_prestat_dir_name (param i32 i32 i32) (result i32)))
16 (import "wasi_unstable" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32)))
17 (import "wasi_unstable" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
18 (import "wasi_unstable" "path_open" (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
19 (import "wasi_unstable" "proc_exit" (func $proc_exit (param i32)))
20
21 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
22
23 (func $fatal (param $code i32 $msg i32)
24 ($print $msg)
25 ($proc_exit $code)
26 )
27
28 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
29
30 (func $print (param $addr i32)
31 (LET $ret 0
32 $nwritten_ptr (STATIC_ARRAY 4 4)
33 $iovec (STATIC_ARRAY 8 8))
34 (i32.store $iovec $addr)
35 (i32.store offset=4 $iovec ($strlen $addr))
36 (local.set $ret ($fd_write 1 $iovec 1 $nwritten_ptr))
37 )
38
39 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
40
41 (func $readline (param $prompt i32 $buf i32) (result i32)
42 (LET $ret 0
43 $nread_ptr (STATIC_ARRAY 4 4)
44 $iovec (STATIC_ARRAY 8 8))
45 ($print $prompt)
46 (i32.store $iovec $buf)
47 (i32.store offset=4 $iovec 200) ;; TODO: not hardcoded length
48 (local.set $ret ($fd_read 0 $iovec 1 $nread_ptr))
49 (if (i32.le_s (i32.load $nread_ptr) 0)
50 (return 0))
51 ;; Replace ending newline with NULL
52 (i32.store8 (i32.add $buf (i32.sub (i32.load $nread_ptr) 1)) 0)
53 1
54 )
55
56 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
57
58 (func $read_file (param $path i32 $buf i32) (result i32)
59 (LET $orig_path $path
60 $ret 0
61 $prestat_ptr (STATIC_ARRAY 8 4)
62 $pr_type 0
63 $pr_name_len 0
64 $prepath (STATIC_ARRAY 1024)
65 $dirfd -1
66 $fd 3
67 $fd_ptr (STATIC_ARRAY 4 4)
68 $nread_ptr (STATIC_ARRAY 4 4)
69 $iovec (STATIC_ARRAY 8 8))
70
71 ;; Find the pre-opened dir fd with the same prefix as the our path
72 ;; following the algorithm at:
73 ;; https://github.com/CraneStation/wasi-sysroot/blob/1cc98f27f5ab8afdc033e16eac8799ee606eb769/libc-bottom-half/crt/crt1.c#L71
74 ;; The matching dir fd is then used to open and read the path.
75 (block $loop_done
76 (loop $loop
77 ;; prestat the fd from 3 onward until EBADF is returned
78 (local.set $ret ($fd_prestat_get $fd $prestat_ptr))
79 (if (i32.eq (global.get $WASI_EBADF) $ret)
80 (br $loop_done))
81 (if (i32.ne (global.get $WASI_ESUCCESS) $ret)
82 (then
83 (local.set $fd (i32.add 1 $fd))
84 (br $loop)))
85 ;;(br $loop_done))
86 (local.set $pr_type (i32.load $prestat_ptr))
87 (local.set $pr_name_len (i32.load offset=4 $prestat_ptr))
88 ;; Read the pre-opened path name
89 (local.set $ret ($fd_prestat_dir_name $fd $prepath $pr_name_len))
90 (if (i32.ne (global.get $WASI_ESUCCESS) $ret)
91 (br $loop_done))
92 ;; if pr_name_len includes a null, exclude it from the compare
93 ;;($printf_2 "here1 pr_name_len: %d, char is %d\n" $pr_name_len (i32.load8_u (i32.add $prepath (i32.sub $pr_name_len 1))))
94 (if (i32.eqz (i32.load8_u (i32.add $prepath (i32.sub $pr_name_len 1))))
95 (then
96 (local.set $pr_name_len (i32.sub $pr_name_len 1))))
97 ;; if it is a dir and the path prefix matches, use it
98 ;;($printf_5 "fd: %d, ret: %d, pr_type: %d, pr_name_len: %d, prepath: %s\n"
99 ;; $fd $ret $pr_type $pr_name_len $prepath)
100 (if (AND (i32.eq $pr_type (global.get $WASI_PREOPENTYPE_DIR))
101 (i32.eqz ($strncmp $prepath $path $pr_name_len)))
102 (then
103 (local.set $path (i32.add $pr_name_len $path))
104 (local.set $dirfd $fd)
105 (br $loop_done)))
106 (local.set $fd (i32.add 1 $fd))
107 (br $loop)
108 )
109 )
110
111 ;;($printf_3 "final dirfd: %d, adjusted path: %s (%d)\n" $dirfd $path ($strlen $path))
112
113 (if (i32.eq $dirfd -1)
114 (then
115 ($printf_1 "ERROR: could not find permission for '%s'\n" $orig_path)
116 (return 0)))
117
118 (local.set $ret ($path_open $dirfd
119 1 ;; dirflags (symlink follow)
120 $path
121 ($strlen $path)
122 0 ;; o_flags
123 (global.get $WASI_RIGHT_FD_READ)
124 (global.get $WASI_RIGHT_FD_READ)
125 0 ;; fs_flags
126 $fd_ptr))
127 (if (i32.ne (global.get $WASI_ESUCCESS) $ret)
128 (then
129 ($printf_2 "ERROR: failed to open '%s', error %d\n" $orig_path $ret)
130 (return 0)))
131
132 (i32.store $iovec $buf)
133 ;; TODO: use stat result instead of not hardcoded length
134 (i32.store offset=4 $iovec 16384)
135 (local.set $ret ($fd_read (i32.load $fd_ptr) $iovec 1 $nread_ptr))
136 (if (i32.ne (global.get $WASI_ESUCCESS) $ret)
137 (then
138 ($printf_2 "ERROR: failed to read '%s', error %d\n" $orig_path $ret)
139 (return 0)))
140
141 ;; Add null to string
142 (i32.store8 (i32.add $buf (i32.load $nread_ptr)) 0)
143 (i32.add 1 (i32.load $nread_ptr))
144 )
145
146 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
147
148 (func $get_time_ms (result i32)
149 (LET $tv (STATIC_ARRAY 8 8))
150 (drop (call $clock_time_get 0 (i64.const 0) $tv))
151 (i32.wrap_i64
152 ;; convert nanoseconds to milliseconds
153 (i64.div_u (i64.load $tv) (i64.const 1000000)))
154 )
155
156 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
157
158 ;; Returns an i64 with argc in high 32 and argv in low 32.
159 ;; String memory is: argv + (argc * 4)
160 (func $get_argc_argv (result i64)
161 (LET $argc_ptr (STATIC_ARRAY 4 4)
162 $argv_size_ptr (STATIC_ARRAY 4 4)
163 $argc 0
164 $argv (STATIC_ARRAY 1024 4))
165 (drop ($args_sizes_get $argc_ptr $argv_size_ptr))
166 (local.set $argc (i32.load $argc_ptr))
167 (if (i32.gt_u (i32.add (i32.mul 4 $argc)
168 (i32.load $argv_size_ptr))
169 1024)
170 ($fatal 2 "Command line arguments memory exceeds 1024 bytes"))
171 (drop ($args_get $argv (i32.add $argv (i32.mul 4 $argc))))
172 (i64.or (i64.shl (i64.extend_i32_u $argc) (i64.const 32))
173 (i64.extend_i32_u $argv))
174 )
175
176 (func $entry
177 (local $argc_argv i64)
178 ($init_memory)
179 (local.set $argc_argv ($get_argc_argv))
180 ($proc_exit
181 ($main (i32.wrap_i64 (i64.shr_u $argc_argv (i64.const 32)))
182 (i32.wrap_i64 $argc_argv)))
183 )
184 ;;(start $entry)
185
186 (export "_start" (func $entry))
187
188 )