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  }