internal/task: use asyncify on webassembly

This change implements a new "scheduler" for WebAssembly using binaryen's asyncify transform.
This is more reliable than the current "coroutines" transform, and works with non-Go code in the call stack.

runtime (js/wasm): handle scheduler nesting

If WASM calls into JS which calls back into WASM, it is possible for the scheduler to nest.
The event from the callback must be handled immediately, so the task cannot simply be deferred to the outer scheduler.
This creates a minimal scheduler loop which is used to handle such nesting.
This commit is contained in:
Nia Waldvogel
2021-07-21 14:30:01 -04:00
committed by Ron Evans
parent 523d1f28cf
commit 641dcd7c16
31 changed files with 785 additions and 62 deletions
+22
View File
@@ -1,3 +1,4 @@
//go:build wasm && !wasi
// +build wasm,!wasi
package runtime
@@ -6,13 +7,19 @@ import "unsafe"
type timeUnit float64 // time in milliseconds, just like Date.now() in JavaScript
// wasmNested is used to detect scheduler nesting (WASM calls into JS calls back into WASM).
// When this happens, we need to use a reduced version of the scheduler.
var wasmNested bool
//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)
wasmNested = true
run()
wasmNested = false
}
var handleEvent func()
@@ -27,12 +34,27 @@ func resume() {
go func() {
handleEvent()
}()
if wasmNested {
minSched()
return
}
wasmNested = true
scheduler()
wasmNested = false
}
//export go_scheduler
func go_scheduler() {
if wasmNested {
minSched()
return
}
wasmNested = true
scheduler()
wasmNested = false
}
func ticksToNanoseconds(ticks timeUnit) int64 {