summaryrefslogtreecommitdiffstats
path: root/src/runtime/os_wasip1.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/os_wasip1.go')
-rw-r--r--src/runtime/os_wasip1.go260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/runtime/os_wasip1.go b/src/runtime/os_wasip1.go
new file mode 100644
index 0000000..acac2b3
--- /dev/null
+++ b/src/runtime/os_wasip1.go
@@ -0,0 +1,260 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build wasip1
+
+package runtime
+
+import "unsafe"
+
+// GOARCH=wasm currently has 64 bits pointers, but the WebAssembly host expects
+// pointers to be 32 bits so we use this type alias to represent pointers in
+// structs and arrays passed as arguments to WASI functions.
+//
+// Note that the use of an integer type prevents the compiler from tracking
+// pointers passed to WASI functions, so we must use KeepAlive to explicitly
+// retain the objects that could otherwise be reclaimed by the GC.
+type uintptr32 = uint32
+
+// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-size-u32
+type size = uint32
+
+// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-errno-variant
+type errno = uint32
+
+// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-filesize-u64
+type filesize = uint64
+
+// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-timestamp-u64
+type timestamp = uint64
+
+// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-clockid-variant
+type clockid = uint32
+
+const (
+ clockRealtime clockid = 0
+ clockMonotonic clockid = 1
+)
+
+// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-iovec-record
+type iovec struct {
+ buf uintptr32
+ bufLen size
+}
+
+//go:wasmimport wasi_snapshot_preview1 proc_exit
+func exit(code int32)
+
+//go:wasmimport wasi_snapshot_preview1 args_get
+//go:noescape
+func args_get(argv, argvBuf unsafe.Pointer) errno
+
+//go:wasmimport wasi_snapshot_preview1 args_sizes_get
+//go:noescape
+func args_sizes_get(argc, argvBufLen unsafe.Pointer) errno
+
+//go:wasmimport wasi_snapshot_preview1 clock_time_get
+//go:noescape
+func clock_time_get(clock_id clockid, precision timestamp, time unsafe.Pointer) errno
+
+//go:wasmimport wasi_snapshot_preview1 environ_get
+//go:noescape
+func environ_get(environ, environBuf unsafe.Pointer) errno
+
+//go:wasmimport wasi_snapshot_preview1 environ_sizes_get
+//go:noescape
+func environ_sizes_get(environCount, environBufLen unsafe.Pointer) errno
+
+//go:wasmimport wasi_snapshot_preview1 fd_write
+//go:noescape
+func fd_write(fd int32, iovs unsafe.Pointer, iovsLen size, nwritten unsafe.Pointer) errno
+
+//go:wasmimport wasi_snapshot_preview1 random_get
+//go:noescape
+func random_get(buf unsafe.Pointer, bufLen size) errno
+
+type eventtype = uint8
+
+const (
+ eventtypeClock eventtype = iota
+ eventtypeFdRead
+ eventtypeFdWrite
+)
+
+type eventrwflags = uint16
+
+const (
+ fdReadwriteHangup eventrwflags = 1 << iota
+)
+
+type userdata = uint64
+
+// The go:wasmimport directive currently does not accept values of type uint16
+// in arguments or returns of the function signature. Most WASI imports return
+// an errno value, which we have to define as uint32 because of that limitation.
+// However, the WASI errno type is intended to be a 16 bits integer, and in the
+// event struct the error field should be of type errno. If we used the errno
+// type for the error field it would result in a mismatching field alignment and
+// struct size because errno is declared as a 32 bits type, so we declare the
+// error field as a plain uint16.
+type event struct {
+ userdata userdata
+ error uint16
+ typ eventtype
+ fdReadwrite eventFdReadwrite
+}
+
+type eventFdReadwrite struct {
+ nbytes filesize
+ flags eventrwflags
+}
+
+type subclockflags = uint16
+
+const (
+ subscriptionClockAbstime subclockflags = 1 << iota
+)
+
+type subscriptionClock struct {
+ id clockid
+ timeout timestamp
+ precision timestamp
+ flags subclockflags
+}
+
+type subscriptionFdReadwrite struct {
+ fd int32
+}
+
+type subscription struct {
+ userdata userdata
+ u subscriptionUnion
+}
+
+type subscriptionUnion [5]uint64
+
+func (u *subscriptionUnion) eventtype() *eventtype {
+ return (*eventtype)(unsafe.Pointer(&u[0]))
+}
+
+func (u *subscriptionUnion) subscriptionClock() *subscriptionClock {
+ return (*subscriptionClock)(unsafe.Pointer(&u[1]))
+}
+
+func (u *subscriptionUnion) subscriptionFdReadwrite() *subscriptionFdReadwrite {
+ return (*subscriptionFdReadwrite)(unsafe.Pointer(&u[1]))
+}
+
+//go:wasmimport wasi_snapshot_preview1 poll_oneoff
+//go:noescape
+func poll_oneoff(in, out unsafe.Pointer, nsubscriptions size, nevents unsafe.Pointer) errno
+
+func write1(fd uintptr, p unsafe.Pointer, n int32) int32 {
+ iov := iovec{
+ buf: uintptr32(uintptr(p)),
+ bufLen: size(n),
+ }
+ var nwritten size
+ if fd_write(int32(fd), unsafe.Pointer(&iov), 1, unsafe.Pointer(&nwritten)) != 0 {
+ throw("fd_write failed")
+ }
+ return int32(nwritten)
+}
+
+func usleep(usec uint32) {
+ var in subscription
+ var out event
+ var nevents size
+
+ eventtype := in.u.eventtype()
+ *eventtype = eventtypeClock
+
+ subscription := in.u.subscriptionClock()
+ subscription.id = clockMonotonic
+ subscription.timeout = timestamp(usec) * 1e3
+ subscription.precision = 1e3
+
+ if poll_oneoff(unsafe.Pointer(&in), unsafe.Pointer(&out), 1, unsafe.Pointer(&nevents)) != 0 {
+ throw("wasi_snapshot_preview1.poll_oneoff")
+ }
+}
+
+func readRandom(r []byte) int {
+ if random_get(unsafe.Pointer(&r[0]), size(len(r))) != 0 {
+ return 0
+ }
+ return len(r)
+}
+
+func goenvs() {
+ // arguments
+ var argc size
+ var argvBufLen size
+ if args_sizes_get(unsafe.Pointer(&argc), unsafe.Pointer(&argvBufLen)) != 0 {
+ throw("args_sizes_get failed")
+ }
+
+ argslice = make([]string, argc)
+ if argc > 0 {
+ argv := make([]uintptr32, argc)
+ argvBuf := make([]byte, argvBufLen)
+ if args_get(unsafe.Pointer(&argv[0]), unsafe.Pointer(&argvBuf[0])) != 0 {
+ throw("args_get failed")
+ }
+
+ for i := range argslice {
+ start := argv[i] - uintptr32(uintptr(unsafe.Pointer(&argvBuf[0])))
+ end := start
+ for argvBuf[end] != 0 {
+ end++
+ }
+ argslice[i] = string(argvBuf[start:end])
+ }
+ }
+
+ // environment
+ var environCount size
+ var environBufLen size
+ if environ_sizes_get(unsafe.Pointer(&environCount), unsafe.Pointer(&environBufLen)) != 0 {
+ throw("environ_sizes_get failed")
+ }
+
+ envs = make([]string, environCount)
+ if environCount > 0 {
+ environ := make([]uintptr32, environCount)
+ environBuf := make([]byte, environBufLen)
+ if environ_get(unsafe.Pointer(&environ[0]), unsafe.Pointer(&environBuf[0])) != 0 {
+ throw("environ_get failed")
+ }
+
+ for i := range envs {
+ start := environ[i] - uintptr32(uintptr(unsafe.Pointer(&environBuf[0])))
+ end := start
+ for environBuf[end] != 0 {
+ end++
+ }
+ envs[i] = string(environBuf[start:end])
+ }
+ }
+}
+
+func walltime() (sec int64, nsec int32) {
+ return walltime1()
+}
+
+func walltime1() (sec int64, nsec int32) {
+ var time timestamp
+ if clock_time_get(clockRealtime, 0, unsafe.Pointer(&time)) != 0 {
+ throw("clock_time_get failed")
+ }
+ return int64(time / 1000000000), int32(time % 1000000000)
+}
+
+func nanotime1() int64 {
+ var time timestamp
+ if clock_time_get(clockMonotonic, 0, unsafe.Pointer(&time)) != 0 {
+ throw("clock_time_get failed")
+ }
+ return int64(time)
+}