
This generally means that code size is reduced, especially when the os package is not imported. Specifically: - On Linux (which currently statically links musl), it avoids calling malloc, which avoids including the musl C heap for small programs saving around 1.6kB. - On WASI, it avoids initializing the args slice when the os package is not used. This reduces binary size by around 1kB.
164 строки
3,9 КиБ
Go
164 строки
3,9 КиБ
Go
// +build tinygo.wasm,wasi
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
type timeUnit int64
|
|
|
|
// libc constructors
|
|
//export __wasm_call_ctors
|
|
func __wasm_call_ctors()
|
|
|
|
//export _start
|
|
func _start() {
|
|
// These need to be initialized early so that the heap can be initialized.
|
|
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
|
|
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
|
|
run()
|
|
}
|
|
|
|
// Read the command line arguments from WASI.
|
|
// For example, they can be passed to a program with wasmtime like this:
|
|
//
|
|
// wasmtime ./program.wasm arg1 arg2
|
|
func init() {
|
|
__wasm_call_ctors()
|
|
}
|
|
|
|
var args []string
|
|
|
|
//go:linkname os_runtime_args os.runtime_args
|
|
func os_runtime_args() []string {
|
|
if args == nil {
|
|
// Read the number of args (argc) and the buffer size required to store
|
|
// all these args (argv).
|
|
var argc, argv_buf_size uint32
|
|
args_sizes_get(&argc, &argv_buf_size)
|
|
if argc == 0 {
|
|
return nil
|
|
}
|
|
|
|
// Obtain the command line arguments
|
|
argsSlice := make([]unsafe.Pointer, argc)
|
|
buf := make([]byte, argv_buf_size)
|
|
args_get(&argsSlice[0], unsafe.Pointer(&buf[0]))
|
|
|
|
// Convert the array of C strings to an array of Go strings.
|
|
args = make([]string, argc)
|
|
for i, cstr := range argsSlice {
|
|
length := strlen(cstr)
|
|
argString := _string{
|
|
length: length,
|
|
ptr: (*byte)(cstr),
|
|
}
|
|
args[i] = *(*string)(unsafe.Pointer(&argString))
|
|
}
|
|
}
|
|
return args
|
|
}
|
|
|
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
|
return int64(ticks)
|
|
}
|
|
|
|
func nanosecondsToTicks(ns int64) timeUnit {
|
|
return timeUnit(ns)
|
|
}
|
|
|
|
const timePrecisionNanoseconds = 1000 // TODO: how can we determine the appropriate `precision`?
|
|
|
|
var (
|
|
sleepTicksSubscription = __wasi_subscription_t{
|
|
userData: 0,
|
|
u: __wasi_subscription_u_t{
|
|
tag: __wasi_eventtype_t_clock,
|
|
u: __wasi_subscription_clock_t{
|
|
id: 0,
|
|
timeout: 0,
|
|
precision: timePrecisionNanoseconds,
|
|
flags: 0,
|
|
},
|
|
},
|
|
}
|
|
sleepTicksResult = __wasi_event_t{}
|
|
sleepTicksNEvents uint32
|
|
)
|
|
|
|
func sleepTicks(d timeUnit) {
|
|
sleepTicksSubscription.u.u.timeout = uint64(d)
|
|
poll_oneoff(&sleepTicksSubscription, &sleepTicksResult, 1, &sleepTicksNEvents)
|
|
}
|
|
|
|
func ticks() timeUnit {
|
|
var nano uint64
|
|
clock_time_get(0, timePrecisionNanoseconds, &nano)
|
|
return timeUnit(nano)
|
|
}
|
|
|
|
// Implementations of WASI APIs
|
|
|
|
//go:wasm-module wasi_snapshot_preview1
|
|
//export args_get
|
|
func args_get(argv *unsafe.Pointer, argv_buf unsafe.Pointer) (errno uint16)
|
|
|
|
//go:wasm-module wasi_snapshot_preview1
|
|
//export args_sizes_get
|
|
func args_sizes_get(argc *uint32, argv_buf_size *uint32) (errno uint16)
|
|
|
|
//go:wasm-module wasi_snapshot_preview1
|
|
//export clock_time_get
|
|
func clock_time_get(clockid uint32, precision uint64, time *uint64) (errno uint16)
|
|
|
|
//go:wasm-module wasi_snapshot_preview1
|
|
//export poll_oneoff
|
|
func poll_oneoff(in *__wasi_subscription_t, out *__wasi_event_t, nsubscriptions uint32, nevents *uint32) (errno uint16)
|
|
|
|
type __wasi_eventtype_t = uint8
|
|
|
|
const (
|
|
__wasi_eventtype_t_clock __wasi_eventtype_t = 0
|
|
// TODO: __wasi_eventtype_t_fd_read __wasi_eventtype_t = 1
|
|
// TODO: __wasi_eventtype_t_fd_write __wasi_eventtype_t = 2
|
|
)
|
|
|
|
type (
|
|
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-subscription-record
|
|
__wasi_subscription_t struct {
|
|
userData uint64
|
|
u __wasi_subscription_u_t
|
|
}
|
|
|
|
__wasi_subscription_u_t struct {
|
|
tag __wasi_eventtype_t
|
|
|
|
// TODO: support fd_read/fd_write event
|
|
u __wasi_subscription_clock_t
|
|
}
|
|
|
|
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-subscription_clock-record
|
|
__wasi_subscription_clock_t struct {
|
|
id uint32
|
|
timeout uint64
|
|
precision uint64
|
|
flags uint16
|
|
}
|
|
)
|
|
|
|
type (
|
|
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-event-record
|
|
__wasi_event_t struct {
|
|
userData uint64
|
|
errno uint16
|
|
eventType __wasi_eventtype_t
|
|
|
|
// only used for fd_read or fd_write events
|
|
// TODO: support fd_read/fd_write event
|
|
_ struct {
|
|
nBytes uint64
|
|
flags uint16
|
|
}
|
|
}
|
|
)
|