1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
//go:build tinygo.wasm && wasi
// +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
}
}
)
|