github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/os_wasip1.go (about) 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. 4 5 //go:build wasip1 6 7 package runtime 8 9 import "unsafe" 10 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. 14 // 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 19 20 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-size-u32 21 type size = uint32 22 23 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-errno-variant 24 type errno = uint32 25 26 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-filesize-u64 27 type filesize = uint64 28 29 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-timestamp-u64 30 type timestamp = uint64 31 32 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-clockid-variant 33 type clockid = uint32 34 35 const ( 36 clockRealtime clockid = 0 37 clockMonotonic clockid = 1 38 ) 39 40 // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-iovec-record 41 type iovec struct { 42 buf uintptr32 43 bufLen size 44 } 45 46 //go:wasmimport wasi_snapshot_preview1 proc_exit 47 func exit(code int32) 48 49 //go:wasmimport wasi_snapshot_preview1 args_get 50 //go:noescape 51 func args_get(argv, argvBuf unsafe.Pointer) errno 52 53 //go:wasmimport wasi_snapshot_preview1 args_sizes_get 54 //go:noescape 55 func args_sizes_get(argc, argvBufLen unsafe.Pointer) errno 56 57 //go:wasmimport wasi_snapshot_preview1 clock_time_get 58 //go:noescape 59 func clock_time_get(clock_id clockid, precision timestamp, time unsafe.Pointer) errno 60 61 //go:wasmimport wasi_snapshot_preview1 environ_get 62 //go:noescape 63 func environ_get(environ, environBuf unsafe.Pointer) errno 64 65 //go:wasmimport wasi_snapshot_preview1 environ_sizes_get 66 //go:noescape 67 func environ_sizes_get(environCount, environBufLen unsafe.Pointer) errno 68 69 //go:wasmimport wasi_snapshot_preview1 fd_write 70 //go:noescape 71 func fd_write(fd int32, iovs unsafe.Pointer, iovsLen size, nwritten unsafe.Pointer) errno 72 73 //go:wasmimport wasi_snapshot_preview1 random_get 74 //go:noescape 75 func random_get(buf unsafe.Pointer, bufLen size) errno 76 77 type eventtype = uint8 78 79 const ( 80 eventtypeClock eventtype = iota 81 eventtypeFdRead 82 eventtypeFdWrite 83 ) 84 85 type eventrwflags = uint16 86 87 const ( 88 fdReadwriteHangup eventrwflags = 1 << iota 89 ) 90 91 type userdata = uint64 92 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. 101 type event struct { 102 userdata userdata 103 error uint16 104 typ eventtype 105 fdReadwrite eventFdReadwrite 106 } 107 108 type eventFdReadwrite struct { 109 nbytes filesize 110 flags eventrwflags 111 } 112 113 type subclockflags = uint16 114 115 const ( 116 subscriptionClockAbstime subclockflags = 1 << iota 117 ) 118 119 type subscriptionClock struct { 120 id clockid 121 timeout timestamp 122 precision timestamp 123 flags subclockflags 124 } 125 126 type subscription struct { 127 userdata userdata 128 u subscriptionUnion 129 } 130 131 type subscriptionUnion [5]uint64 132 133 func (u *subscriptionUnion) eventtype() *eventtype { 134 return (*eventtype)(unsafe.Pointer(&u[0])) 135 } 136 137 func (u *subscriptionUnion) subscriptionClock() *subscriptionClock { 138 return (*subscriptionClock)(unsafe.Pointer(&u[1])) 139 } 140 141 //go:wasmimport wasi_snapshot_preview1 poll_oneoff 142 //go:noescape 143 func poll_oneoff(in, out unsafe.Pointer, nsubscriptions size, nevents unsafe.Pointer) errno 144 145 func write1(fd uintptr, p unsafe.Pointer, n int32) int32 { 146 iov := iovec{ 147 buf: uintptr32(uintptr(p)), 148 bufLen: size(n), 149 } 150 var nwritten size 151 if fd_write(int32(fd), unsafe.Pointer(&iov), 1, unsafe.Pointer(&nwritten)) != 0 { 152 throw("fd_write failed") 153 } 154 return int32(nwritten) 155 } 156 157 func usleep(usec uint32) { 158 var in subscription 159 var out event 160 var nevents size 161 162 eventtype := in.u.eventtype() 163 *eventtype = eventtypeClock 164 165 subscription := in.u.subscriptionClock() 166 subscription.id = clockMonotonic 167 subscription.timeout = timestamp(usec) * 1e3 168 subscription.precision = 1e3 169 170 if poll_oneoff(unsafe.Pointer(&in), unsafe.Pointer(&out), 1, unsafe.Pointer(&nevents)) != 0 { 171 throw("wasi_snapshot_preview1.poll_oneoff") 172 } 173 } 174 175 func getRandomData(r []byte) { 176 if random_get(unsafe.Pointer(&r[0]), size(len(r))) != 0 { 177 throw("random_get failed") 178 } 179 } 180 181 func goenvs() { 182 // arguments 183 var argc size 184 var argvBufLen size 185 if args_sizes_get(unsafe.Pointer(&argc), unsafe.Pointer(&argvBufLen)) != 0 { 186 throw("args_sizes_get failed") 187 } 188 189 argslice = make([]string, argc) 190 if argc > 0 { 191 argv := make([]uintptr32, argc) 192 argvBuf := make([]byte, argvBufLen) 193 if args_get(unsafe.Pointer(&argv[0]), unsafe.Pointer(&argvBuf[0])) != 0 { 194 throw("args_get failed") 195 } 196 197 for i := range argslice { 198 start := argv[i] - uintptr32(uintptr(unsafe.Pointer(&argvBuf[0]))) 199 end := start 200 for argvBuf[end] != 0 { 201 end++ 202 } 203 argslice[i] = string(argvBuf[start:end]) 204 } 205 } 206 207 // environment 208 var environCount size 209 var environBufLen size 210 if environ_sizes_get(unsafe.Pointer(&environCount), unsafe.Pointer(&environBufLen)) != 0 { 211 throw("environ_sizes_get failed") 212 } 213 214 envs = make([]string, environCount) 215 if environCount > 0 { 216 environ := make([]uintptr32, environCount) 217 environBuf := make([]byte, environBufLen) 218 if environ_get(unsafe.Pointer(&environ[0]), unsafe.Pointer(&environBuf[0])) != 0 { 219 throw("environ_get failed") 220 } 221 222 for i := range envs { 223 start := environ[i] - uintptr32(uintptr(unsafe.Pointer(&environBuf[0]))) 224 end := start 225 for environBuf[end] != 0 { 226 end++ 227 } 228 envs[i] = string(environBuf[start:end]) 229 } 230 } 231 } 232 233 func walltime() (sec int64, nsec int32) { 234 return walltime1() 235 } 236 237 func walltime1() (sec int64, nsec int32) { 238 var time timestamp 239 if clock_time_get(clockRealtime, 0, unsafe.Pointer(&time)) != 0 { 240 throw("clock_time_get failed") 241 } 242 return int64(time / 1000000000), int32(time % 1000000000) 243 } 244 245 func nanotime1() int64 { 246 var time timestamp 247 if clock_time_get(clockMonotonic, 0, unsafe.Pointer(&time)) != 0 { 248 throw("clock_time_get failed") 249 } 250 return int64(time) 251 }