diff options
author | Nia Waldvogel <[email protected]> | 2021-07-21 14:30:01 -0400 |
---|---|---|
committer | Ron Evans <[email protected]> | 2021-11-14 10:49:28 +0100 |
commit | 641dcd7c16d60a53faf8b61b509057830441a765 (patch) | |
tree | 2db29ae018645871178727e8c355bc69b24db796 /goenv/goenv.go | |
parent | 523d1f28cf31ebd398093636b915bbcb3dcd93d5 (diff) | |
download | tinygo-641dcd7c16d60a53faf8b61b509057830441a765.tar.gz tinygo-641dcd7c16d60a53faf8b61b509057830441a765.zip |
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.
Diffstat (limited to 'goenv/goenv.go')
-rw-r--r-- | goenv/goenv.go | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/goenv/goenv.go b/goenv/goenv.go index 3f1352a78..0ef18ba50 100644 --- a/goenv/goenv.go +++ b/goenv/goenv.go @@ -3,12 +3,15 @@ package goenv import ( + "bytes" + "errors" "fmt" "os" "os/exec" "os/user" "path/filepath" "runtime" + "strings" ) // Keys is a slice of all available environment variable keys. @@ -67,11 +70,98 @@ func Get(name string) string { return "1" case "TINYGOROOT": return sourceDir() + case "WASMOPT": + if path := os.Getenv("WASMOPT"); path != "" { + err := wasmOptCheckVersion(path) + if err != nil { + fmt.Fprintf(os.Stderr, "cannot use %q as wasm-opt (from WASMOPT environment variable): %s", path, err.Error()) + os.Exit(1) + } + + return path + } + + return findWasmOpt() default: return "" } } +// Find wasm-opt, or exit with an error. +func findWasmOpt() string { + tinygoroot := sourceDir() + searchPaths := []string{ + tinygoroot + "/bin/wasm-opt", + tinygoroot + "/build/wasm-opt", + } + + var paths []string + for _, path := range searchPaths { + if runtime.GOOS == "windows" { + path += ".exe" + } + + _, err := os.Stat(path) + if err != nil && os.IsNotExist(err) { + continue + } + + paths = append(paths, path) + } + + if path, err := exec.LookPath("wasm-opt"); err == nil { + paths = append(paths, path) + } + + if len(paths) == 0 { + fmt.Fprintln(os.Stderr, "error: could not find wasm-opt, set the WASMOPT environment variable to override") + os.Exit(1) + } + + errs := make([]error, len(paths)) + for i, path := range paths { + err := wasmOptCheckVersion(path) + if err == nil { + return path + } + + errs[i] = err + } + fmt.Fprintln(os.Stderr, "no usable wasm-opt found, update or run \"make binaryen\"") + for i, path := range paths { + fmt.Fprintf(os.Stderr, "\t%s: %s\n", path, errs[i].Error()) + } + os.Exit(1) + panic("unreachable") +} + +// wasmOptCheckVersion checks if a copy of wasm-opt is usable. +func wasmOptCheckVersion(path string) error { + cmd := exec.Command(path, "--version") + var buf bytes.Buffer + cmd.Stdout = &buf + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + return err + } + + str := buf.String() + if strings.Contains(str, "(") { + // The git tag may be placed in parentheses after the main version string. + str = strings.Split(str, "(")[0] + } + + str = strings.TrimSpace(str) + var ver uint + _, err = fmt.Sscanf(str, "wasm-opt version %d", &ver) + if err != nil || ver < 102 { + return errors.New("incompatible wasm-opt (need 102 or newer)") + } + + return nil +} + // Return the TINYGOROOT, or exit with an error. func sourceDir() string { // Use $TINYGOROOT as root, if available. |