1 // Copyright 2023 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
11 // GOARCH=wasm currently has 64 bits pointers, but the WebAssembly host expects
12 // pointers to be 32 bits so we use this type alias to represent pointers in
13 // structs and arrays passed as arguments to WASI functions.
15 // Note that the use of an integer type prevents the compiler from tracking
16 // pointers passed to WASI functions, so we must use KeepAlive to explicitly
17 // retain the objects that could otherwise be reclaimed by the GC.
18 type uintptr32 = uint32
20 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-size-u32
23 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-errno-variant
26 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-filesize-u64
27 type filesize = uint64
29 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-timestamp-u64
30 type timestamp = uint64
32 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-clockid-variant
36 clockRealtime clockid = 0
37 clockMonotonic clockid = 1
40 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-iovec-record
46 //go:wasmimport wasi_snapshot_preview1 proc_exit
49 //go:wasmimport wasi_snapshot_preview1 args_get
51 func args_get(argv, argvBuf unsafe.Pointer) errno
53 //go:wasmimport wasi_snapshot_preview1 args_sizes_get
55 func args_sizes_get(argc, argvBufLen unsafe.Pointer) errno
57 //go:wasmimport wasi_snapshot_preview1 clock_time_get
59 func clock_time_get(clock_id clockid, precision timestamp, time unsafe.Pointer) errno
61 //go:wasmimport wasi_snapshot_preview1 environ_get
63 func environ_get(environ, environBuf unsafe.Pointer) errno
65 //go:wasmimport wasi_snapshot_preview1 environ_sizes_get
67 func environ_sizes_get(environCount, environBufLen unsafe.Pointer) errno
69 //go:wasmimport wasi_snapshot_preview1 fd_write
71 func fd_write(fd int32, iovs unsafe.Pointer, iovsLen size, nwritten unsafe.Pointer) errno
73 //go:wasmimport wasi_snapshot_preview1 random_get
75 func random_get(buf unsafe.Pointer, bufLen size) errno
77 type eventtype = uint8
80 eventtypeClock eventtype = iota
85 type eventrwflags = uint16
88 fdReadwriteHangup eventrwflags = 1 << iota
91 type userdata = uint64
93 // The go:wasmimport directive currently does not accept values of type uint16
94 // in arguments or returns of the function signature. Most WASI imports return
95 // an errno value, which we have to define as uint32 because of that limitation.
96 // However, the WASI errno type is intended to be a 16 bits integer, and in the
97 // event struct the error field should be of type errno. If we used the errno
98 // type for the error field it would result in a mismatching field alignment and
99 // struct size because errno is declared as a 32 bits type, so we declare the
100 // error field as a plain uint16.
105 fdReadwrite eventFdReadwrite
108 type eventFdReadwrite struct {
113 type subclockflags = uint16
116 subscriptionClockAbstime subclockflags = 1 << iota
119 type subscriptionClock struct {
126 type subscriptionFdReadwrite struct {
130 type subscription struct {
135 type subscriptionUnion [5]uint64
137 func (u *subscriptionUnion) eventtype() *eventtype {
138 return (*eventtype)(unsafe.Pointer(&u[0]))
141 func (u *subscriptionUnion) subscriptionClock() *subscriptionClock {
142 return (*subscriptionClock)(unsafe.Pointer(&u[1]))
145 func (u *subscriptionUnion) subscriptionFdReadwrite() *subscriptionFdReadwrite {
146 return (*subscriptionFdReadwrite)(unsafe.Pointer(&u[1]))
149 //go:wasmimport wasi_snapshot_preview1 poll_oneoff
151 func poll_oneoff(in, out unsafe.Pointer, nsubscriptions size, nevents unsafe.Pointer) errno
153 func write1(fd uintptr, p unsafe.Pointer, n int32) int32 {
155 buf: uintptr32(uintptr(p)),
159 if fd_write(int32(fd), unsafe.Pointer(&iov), 1, unsafe.Pointer(&nwritten)) != 0 {
160 throw("fd_write failed")
162 return int32(nwritten)
165 func usleep(usec uint32) {
170 eventtype := in.u.eventtype()
171 *eventtype = eventtypeClock
173 subscription := in.u.subscriptionClock()
174 subscription.id = clockMonotonic
175 subscription.timeout = timestamp(usec) * 1e3
176 subscription.precision = 1e3
178 if poll_oneoff(unsafe.Pointer(&in), unsafe.Pointer(&out), 1, unsafe.Pointer(&nevents)) != 0 {
179 throw("wasi_snapshot_preview1.poll_oneoff")
183 func getRandomData(r []byte) {
184 if random_get(unsafe.Pointer(&r[0]), size(len(r))) != 0 {
185 throw("random_get failed")
193 if args_sizes_get(unsafe.Pointer(&argc), unsafe.Pointer(&argvBufLen)) != 0 {
194 throw("args_sizes_get failed")
197 argslice = make([]string, argc)
199 argv := make([]uintptr32, argc)
200 argvBuf := make([]byte, argvBufLen)
201 if args_get(unsafe.Pointer(&argv[0]), unsafe.Pointer(&argvBuf[0])) != 0 {
202 throw("args_get failed")
205 for i := range argslice {
206 start := argv[i] - uintptr32(uintptr(unsafe.Pointer(&argvBuf[0])))
208 for argvBuf[end] != 0 {
211 argslice[i] = string(argvBuf[start:end])
216 var environCount size
217 var environBufLen size
218 if environ_sizes_get(unsafe.Pointer(&environCount), unsafe.Pointer(&environBufLen)) != 0 {
219 throw("environ_sizes_get failed")
222 envs = make([]string, environCount)
223 if environCount > 0 {
224 environ := make([]uintptr32, environCount)
225 environBuf := make([]byte, environBufLen)
226 if environ_get(unsafe.Pointer(&environ[0]), unsafe.Pointer(&environBuf[0])) != 0 {
227 throw("environ_get failed")
230 for i := range envs {
231 start := environ[i] - uintptr32(uintptr(unsafe.Pointer(&environBuf[0])))
233 for environBuf[end] != 0 {
236 envs[i] = string(environBuf[start:end])
241 func walltime() (sec int64, nsec int32) {
245 func walltime1() (sec int64, nsec int32) {
247 if clock_time_get(clockRealtime, 0, unsafe.Pointer(&time)) != 0 {
248 throw("clock_time_get failed")
250 return int64(time / 1000000000), int32(time % 1000000000)
253 func nanotime1() int64 {
255 if clock_time_get(clockMonotonic, 0, unsafe.Pointer(&time)) != 0 {
256 throw("clock_time_get failed")