github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/runtime_wasip1.go (about)

     1  //go:build wasip1
     2  
     3  package runtime
     4  
     5  import (
     6  	"unsafe"
     7  )
     8  
     9  type timeUnit int64
    10  
    11  // libc constructors
    12  //
    13  //export __wasm_call_ctors
    14  func __wasm_call_ctors()
    15  
    16  //export _start
    17  func _start() {
    18  	// These need to be initialized early so that the heap can be initialized.
    19  	heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
    20  	heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
    21  	run()
    22  }
    23  
    24  // Read the command line arguments from WASI.
    25  // For example, they can be passed to a program with wasmtime like this:
    26  //
    27  //	wasmtime run ./program.wasm arg1 arg2
    28  func init() {
    29  	__wasm_call_ctors()
    30  }
    31  
    32  var args []string
    33  
    34  //go:linkname os_runtime_args os.runtime_args
    35  func os_runtime_args() []string {
    36  	if args == nil {
    37  		// Read the number of args (argc) and the buffer size required to store
    38  		// all these args (argv).
    39  		var argc, argv_buf_size uint32
    40  		args_sizes_get(&argc, &argv_buf_size)
    41  		if argc == 0 {
    42  			return nil
    43  		}
    44  
    45  		// Obtain the command line arguments
    46  		argsSlice := make([]unsafe.Pointer, argc)
    47  		buf := make([]byte, argv_buf_size)
    48  		args_get(&argsSlice[0], unsafe.Pointer(&buf[0]))
    49  
    50  		// Convert the array of C strings to an array of Go strings.
    51  		args = make([]string, argc)
    52  		for i, cstr := range argsSlice {
    53  			length := strlen(cstr)
    54  			argString := _string{
    55  				length: length,
    56  				ptr:    (*byte)(cstr),
    57  			}
    58  			args[i] = *(*string)(unsafe.Pointer(&argString))
    59  		}
    60  	}
    61  	return args
    62  }
    63  
    64  func ticksToNanoseconds(ticks timeUnit) int64 {
    65  	return int64(ticks)
    66  }
    67  
    68  func nanosecondsToTicks(ns int64) timeUnit {
    69  	return timeUnit(ns)
    70  }
    71  
    72  const timePrecisionNanoseconds = 1000 // TODO: how can we determine the appropriate `precision`?
    73  
    74  var (
    75  	sleepTicksSubscription = __wasi_subscription_t{
    76  		userData: 0,
    77  		u: __wasi_subscription_u_t{
    78  			tag: __wasi_eventtype_t_clock,
    79  			u: __wasi_subscription_clock_t{
    80  				id:        0,
    81  				timeout:   0,
    82  				precision: timePrecisionNanoseconds,
    83  				flags:     0,
    84  			},
    85  		},
    86  	}
    87  	sleepTicksResult  = __wasi_event_t{}
    88  	sleepTicksNEvents uint32
    89  )
    90  
    91  func sleepTicks(d timeUnit) {
    92  	sleepTicksSubscription.u.u.timeout = uint64(d)
    93  	poll_oneoff(&sleepTicksSubscription, &sleepTicksResult, 1, &sleepTicksNEvents)
    94  }
    95  
    96  func ticks() timeUnit {
    97  	var nano uint64
    98  	clock_time_get(0, timePrecisionNanoseconds, &nano)
    99  	return timeUnit(nano)
   100  }
   101  
   102  // Implementations of WASI APIs
   103  
   104  //go:wasmimport wasi_snapshot_preview1 args_get
   105  func args_get(argv *unsafe.Pointer, argv_buf unsafe.Pointer) (errno uint16)
   106  
   107  //go:wasmimport wasi_snapshot_preview1 args_sizes_get
   108  func args_sizes_get(argc *uint32, argv_buf_size *uint32) (errno uint16)
   109  
   110  //go:wasmimport wasi_snapshot_preview1 clock_time_get
   111  func clock_time_get(clockid uint32, precision uint64, time *uint64) (errno uint16)
   112  
   113  //go:wasmimport wasi_snapshot_preview1 poll_oneoff
   114  func poll_oneoff(in *__wasi_subscription_t, out *__wasi_event_t, nsubscriptions uint32, nevents *uint32) (errno uint16)
   115  
   116  type __wasi_eventtype_t = uint8
   117  
   118  const (
   119  	__wasi_eventtype_t_clock __wasi_eventtype_t = 0
   120  	// TODO: __wasi_eventtype_t_fd_read  __wasi_eventtype_t = 1
   121  	// TODO: __wasi_eventtype_t_fd_write __wasi_eventtype_t = 2
   122  )
   123  
   124  type (
   125  	// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-subscription-record
   126  	__wasi_subscription_t struct {
   127  		userData uint64
   128  		u        __wasi_subscription_u_t
   129  	}
   130  
   131  	__wasi_subscription_u_t struct {
   132  		tag __wasi_eventtype_t
   133  
   134  		// TODO: support fd_read/fd_write event
   135  		u __wasi_subscription_clock_t
   136  	}
   137  
   138  	// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-subscription_clock-record
   139  	__wasi_subscription_clock_t struct {
   140  		id        uint32
   141  		timeout   uint64
   142  		precision uint64
   143  		flags     uint16
   144  	}
   145  )
   146  
   147  type (
   148  	// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-event-record
   149  	__wasi_event_t struct {
   150  		userData  uint64
   151  		errno     uint16
   152  		eventType __wasi_eventtype_t
   153  
   154  		// only used for fd_read or fd_write events
   155  		// TODO: support fd_read/fd_write event
   156  		_ struct {
   157  			nBytes uint64
   158  			flags  uint16
   159  		}
   160  	}
   161  )