github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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 subscriptionFdReadwrite struct { 127 fd int32 128 } 129 130 type subscription struct { 131 userdata userdata 132 u subscriptionUnion 133 } 134 135 type subscriptionUnion [5]uint64 136 137 func (u *subscriptionUnion) eventtype() *eventtype { 138 return (*eventtype)(unsafe.Pointer(&u[0])) 139 } 140 141 func (u *subscriptionUnion) subscriptionClock() *subscriptionClock { 142 return (*subscriptionClock)(unsafe.Pointer(&u[1])) 143 } 144 145 func (u *subscriptionUnion) subscriptionFdReadwrite() *subscriptionFdReadwrite { 146 return (*subscriptionFdReadwrite)(unsafe.Pointer(&u[1])) 147 } 148 149 //go:wasmimport wasi_snapshot_preview1 poll_oneoff 150 //go:noescape 151 func poll_oneoff(in, out unsafe.Pointer, nsubscriptions size, nevents unsafe.Pointer) errno 152 153 func write1(fd uintptr, p unsafe.Pointer, n int32) int32 { 154 iov := iovec{ 155 buf: uintptr32(uintptr(p)), 156 bufLen: size(n), 157 } 158 var nwritten size 159 if fd_write(int32(fd), unsafe.Pointer(&iov), 1, unsafe.Pointer(&nwritten)) != 0 { 160 throw("fd_write failed") 161 } 162 return int32(nwritten) 163 } 164 165 func usleep(usec uint32) { 166 var in subscription 167 var out event 168 var nevents size 169 170 eventtype := in.u.eventtype() 171 *eventtype = eventtypeClock 172 173 subscription := in.u.subscriptionClock() 174 subscription.id = clockMonotonic 175 subscription.timeout = timestamp(usec) * 1e3 176 subscription.precision = 1e3 177 178 if poll_oneoff(unsafe.Pointer(&in), unsafe.Pointer(&out), 1, unsafe.Pointer(&nevents)) != 0 { 179 throw("wasi_snapshot_preview1.poll_oneoff") 180 } 181 } 182 183 func readRandom(r []byte) int { 184 if random_get(unsafe.Pointer(&r[0]), size(len(r))) != 0 { 185 return 0 186 } 187 return len(r) 188 } 189 190 func goenvs() { 191 // arguments 192 var argc size 193 var argvBufLen size 194 if args_sizes_get(unsafe.Pointer(&argc), unsafe.Pointer(&argvBufLen)) != 0 { 195 throw("args_sizes_get failed") 196 } 197 198 argslice = make([]string, argc) 199 if argc > 0 { 200 argv := make([]uintptr32, argc) 201 argvBuf := make([]byte, argvBufLen) 202 if args_get(unsafe.Pointer(&argv[0]), unsafe.Pointer(&argvBuf[0])) != 0 { 203 throw("args_get failed") 204 } 205 206 for i := range argslice { 207 start := argv[i] - uintptr32(uintptr(unsafe.Pointer(&argvBuf[0]))) 208 end := start 209 for argvBuf[end] != 0 { 210 end++ 211 } 212 argslice[i] = string(argvBuf[start:end]) 213 } 214 } 215 216 // environment 217 var environCount size 218 var environBufLen size 219 if environ_sizes_get(unsafe.Pointer(&environCount), unsafe.Pointer(&environBufLen)) != 0 { 220 throw("environ_sizes_get failed") 221 } 222 223 envs = make([]string, environCount) 224 if environCount > 0 { 225 environ := make([]uintptr32, environCount) 226 environBuf := make([]byte, environBufLen) 227 if environ_get(unsafe.Pointer(&environ[0]), unsafe.Pointer(&environBuf[0])) != 0 { 228 throw("environ_get failed") 229 } 230 231 for i := range envs { 232 start := environ[i] - uintptr32(uintptr(unsafe.Pointer(&environBuf[0]))) 233 end := start 234 for environBuf[end] != 0 { 235 end++ 236 } 237 envs[i] = string(environBuf[start:end]) 238 } 239 } 240 } 241 242 func walltime() (sec int64, nsec int32) { 243 return walltime1() 244 } 245 246 func walltime1() (sec int64, nsec int32) { 247 var time timestamp 248 if clock_time_get(clockRealtime, 0, unsafe.Pointer(&time)) != 0 { 249 throw("clock_time_get failed") 250 } 251 return int64(time / 1000000000), int32(time % 1000000000) 252 } 253 254 func nanotime1() int64 { 255 var time timestamp 256 if clock_time_get(clockMonotonic, 0, unsafe.Pointer(&time)) != 0 { 257 throw("clock_time_get failed") 258 } 259 return int64(time) 260 }