]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/os_wasip1.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / runtime / os_wasip1.go
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 getRandomData(r []byte) {
184         if random_get(unsafe.Pointer(&r[0]), size(len(r))) != 0 {
185                 throw("random_get failed")
186         }
187 }
188
189 func goenvs() {
190         // arguments
191         var argc size
192         var argvBufLen size
193         if args_sizes_get(unsafe.Pointer(&argc), unsafe.Pointer(&argvBufLen)) != 0 {
194                 throw("args_sizes_get failed")
195         }
196
197         argslice = make([]string, argc)
198         if argc > 0 {
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")
203                 }
204
205                 for i := range argslice {
206                         start := argv[i] - uintptr32(uintptr(unsafe.Pointer(&argvBuf[0])))
207                         end := start
208                         for argvBuf[end] != 0 {
209                                 end++
210                         }
211                         argslice[i] = string(argvBuf[start:end])
212                 }
213         }
214
215         // environment
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")
220         }
221
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")
228                 }
229
230                 for i := range envs {
231                         start := environ[i] - uintptr32(uintptr(unsafe.Pointer(&environBuf[0])))
232                         end := start
233                         for environBuf[end] != 0 {
234                                 end++
235                         }
236                         envs[i] = string(environBuf[start:end])
237                 }
238         }
239 }
240
241 func walltime() (sec int64, nsec int32) {
242         return walltime1()
243 }
244
245 func walltime1() (sec int64, nsec int32) {
246         var time timestamp
247         if clock_time_get(clockRealtime, 0, unsafe.Pointer(&time)) != 0 {
248                 throw("clock_time_get failed")
249         }
250         return int64(time / 1000000000), int32(time % 1000000000)
251 }
252
253 func nanotime1() int64 {
254         var time timestamp
255         if clock_time_get(clockMonotonic, 0, unsafe.Pointer(&time)) != 0 {
256                 throw("clock_time_get failed")
257         }
258         return int64(time)
259 }