Repository: go
Issue: misc/wasm: Go's WASM running slow in Node v19
Labels: Performance,NeedsInvestigation,arch-wasm

<!--
Please answer these questions before submitting your issue. Thanks!
-->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.20.3 darwin/amd64
</pre>

### Does this issue reproduce with the latest release?
Yes

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/penghaoh/.cache/go-build"
GOENV="/Users/penghaoh/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/penghaoh/Workplace/my_go_workspace/pkg/mod"
GONOPROXY="*"
GONOSUMDB="*"
GOOS="darwin"
GOPATH="/Users/penghaoh/Workplace/my_go_workspace"
GOPRIVATE="*"
GOPROXY="direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.20.3"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/h0/6tx4n9fn59z1vj88py9mncmr00vbmk/T/go-build2636679718=/tmp/go-build -gno-record-gcc-switches -fno-common"
</pre></details>

### What did you do?

<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on go.dev/play is best.
-->
- Make a go program trying to reuse some logic in our project written in Go

<details><summary><code>main.go</code></summary><br>

```golang
var done chan bool

func init() {
	done = make(chan bool)
}

func main() {
	var hash js.Func
	hash = js.FuncOf(func(this js.Value, args []js.Value) any {
		h := crypto.SHA512.New()
		h.Write([]byte(args[0].String()))
		return hex.EncodeToString(h.Sum(nil))
	})
	js.Global().Set("wasmHash", hash)
	var close js.Func
	close = js.FuncOf(func(this js.Value, args []js.Value) any {
		defer close.Release()
		defer hash.Release()
		done <- true
		return nil
	})
	js.Global().Set("close", close)
	<-done
}

```

</pre></details>

- Build it with `GOOS=js GOARCH=wasm go build -o wasm.wasm main.go` and the binary size is 19.4 MB (i add some extra dependencies to simulate the real project for this prototype)
- Compress the wasm file `gzip -9 -v -c wasm.wasm > wasm.wasm.gz`
- Run it with `node ./main.js`

<details><summary><code>main.js</code></summary><br><pre>

```js
const pako = require("pako");
require("./wasm_exec");
fs = require("fs");

const wasmBuffer = new Uint8Array(pako.ungzip(fs.readFileSync("wasm.wasm.gz")));
const go = new Go();
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
WebAssembly.instantiate(wasmBuffer, go.importObject).then((wasmModule) => {
  go.run(wasmModule.instance);
  console.log(wasmHash("asdf"));
  close();
  process.on("exit", (code) => {
    // Node.js exits if no event handler is pending

    // commend the block avoid deadlock
    if (code === 0 && !go.exited) {
      // deadlock, make Go print error and stack traces
      go._pendingEvent = { id: 0 };
      go._resume();
    }
    process.exit();
  });
  return;
});
```

</pre></details>

### What did you expect to see?
The hashed result for `asdf` showing up instantly.

### What did you see instead?
If the binary size is big, after seeing the result, it takes 5 seconds on my machine to exit. However, it is surprising to me that if I rewrite the js file in deno, it exits instantly after printing the result in my terminal.

<details><summary><code>deno.js</code></summary><br><pre>

```js
import * as _ from "./wasm_exec.js";
const go = new window.Go();
const f = await Deno.open("./wasm.wasm");
const buf = await Deno.readAll(f);
const inst = await WebAssembly.instantiate(buf, go.importObject);
go.run(inst.instance);
const result = wasmHash("asdf");
console.log(result);

```

</pre></details>