Initial commit: Go 1.23 release state
This commit is contained in:
260
src/runtime/os_wasip1.go
Normal file
260
src/runtime/os_wasip1.go
Normal file
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user