Skip to content

Commit 24a0f23

Browse files
aykevldeadprogram
authored andcommitted
wasm: use wasi ABI for basic startup/stdout
This allows TinyGo-built binaries to run under wasmtime, for example: tinygo build -o test.wasm -no-debug -target=wasm examples/test wasmtime run test.wasm 0
1 parent eb9c2c2 commit 24a0f23

File tree

2 files changed

+50
-36
lines changed

2 files changed

+50
-36
lines changed

src/runtime/runtime_wasm.go

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,43 @@
22

33
package runtime
44

5+
import "unsafe"
6+
57
type timeUnit float64 // time in milliseconds, just like Date.now() in JavaScript
68

79
const tickMicros = 1000000
810

9-
//go:export io_get_stdout
10-
func io_get_stdout() int32
11-
12-
//go:export resource_write
13-
func resource_write(id int32, ptr *uint8, len int32) int32
14-
15-
var stdout int32
16-
17-
func init() {
18-
stdout = io_get_stdout()
11+
// Implements __wasi_ciovec_t and __wasi_iovec_t.
12+
type wasiIOVec struct {
13+
buf unsafe.Pointer
14+
bufLen uint
1915
}
2016

21-
//go:export _start
17+
//go:wasm-module wasi_unstable
18+
//export fd_write
19+
func fd_write(id uint32, iovs *wasiIOVec, iovs_len uint, nwritten *uint) (errno uint)
20+
21+
//export _start
2222
func _start() {
2323
initAll()
24-
}
25-
26-
//go:export cwa_main
27-
func cwa_main() {
28-
initAll() // _start is not called by olin/cwa so has to be called here
2924
callMain()
3025
}
3126

27+
// Using global variables to avoid heap allocation.
28+
var (
29+
putcharBuf = byte(0)
30+
putcharIOVec = wasiIOVec{
31+
buf: unsafe.Pointer(&putcharBuf),
32+
bufLen: 1,
33+
}
34+
)
35+
3236
func putchar(c byte) {
33-
resource_write(stdout, &c, 1)
37+
// write to stdout
38+
const stdout = 1
39+
var nwritten uint
40+
putcharBuf = c
41+
fd_write(stdout, &putcharIOVec, 1, &nwritten)
3442
}
3543

3644
var handleEvent func()

targets/wasm_exec.js

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -181,31 +181,37 @@
181181

182182
const timeOrigin = Date.now() - performance.now();
183183
this.importObject = {
184-
env: {
185-
io_get_stdout: function() {
186-
return 1;
187-
},
188-
189-
resource_write: function(fd, ptr, len) {
184+
wasi_unstable: {
185+
// https://github.com/bytecodealliance/wasmtime/blob/master/docs/WASI-api.md#__wasi_fd_write
186+
fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) {
187+
let nwritten = 0;
190188
if (fd == 1) {
191-
for (let i=0; i<len; i++) {
192-
let c = mem().getUint8(ptr+i);
193-
if (c == 13) { // CR
194-
// ignore
195-
} else if (c == 10) { // LF
196-
// write line
197-
let line = decoder.decode(new Uint8Array(logLine));
198-
logLine = [];
199-
console.log(line);
200-
} else {
201-
logLine.push(c);
189+
for (let iovs_i=0; iovs_i<iovs_len;iovs_i++) {
190+
let iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32
191+
let ptr = mem().getUint32(iov_ptr + 0, true);
192+
let len = mem().getUint32(iov_ptr + 4, true);
193+
for (let i=0; i<len; i++) {
194+
let c = mem().getUint8(ptr+i);
195+
if (c == 13) { // CR
196+
// ignore
197+
} else if (c == 10) { // LF
198+
// write line
199+
let line = decoder.decode(new Uint8Array(logLine));
200+
logLine = [];
201+
console.log(line);
202+
} else {
203+
logLine.push(c);
204+
}
202205
}
203206
}
204207
} else {
205208
console.error('invalid file descriptor:', fd);
206209
}
210+
mem().setUint32(nwritten_ptr, nwritten, true);
211+
return 0;
207212
},
208-
213+
},
214+
env: {
209215
// func ticks() float64
210216
"runtime.ticks": () => {
211217
return timeOrigin + performance.now();
@@ -344,7 +350,7 @@
344350
setTimeout(resolve, 0); // make sure it is asynchronous
345351
};
346352
});
347-
this._inst.exports.cwa_main();
353+
this._inst.exports._start();
348354
if (this.exited) {
349355
break;
350356
}

0 commit comments

Comments
 (0)