eth/tracers/js: avoid compiling js bigint when not needed #30640 (#1497)

While looking at some mem profiles from `evm` runs, I noticed that
`goja` compilation of the bigint library was present. The bigint library
compilation happens in a package `init`, whenever the package
`eth/tracers/js` is loaded. This PR changes it to load lazily when
needed.

It becomes slightly faster with this change, and slightly less alloc:y.

Non-scientific benchmark with 100 executions:
```
time for i in {1..100}; do ./evm --code 6040 run; done;
 ```

current `master`:

```
real    0m6.634s
user    0m5.213s
sys     0m2.277s
```
Without compiling bigint
```
real    0m5.802s
user    0m4.191s
sys     0m1.965s
```

Co-authored-by: Martin HS <martin@swende.se>
This commit is contained in:
Daniel Liu 2025-09-17 08:17:18 +08:00 committed by GitHub
parent beb6ff97d7
commit 2b906f22f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -22,6 +22,7 @@ import (
"fmt"
"math/big"
"slices"
"sync"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
@ -57,9 +58,17 @@ func init() {
tracers.DefaultDirectory.RegisterJSEval(newJsTracer)
}
// bigIntProgram is compiled once and the exported function mostly invoked to convert
// hex strings into big ints.
var bigIntProgram = goja.MustCompile("bigInt", bigIntegerJS, false)
var compiledBigInt *goja.Program
var compileOnce sync.Once
// getBigIntProgram compiles the bigint library, if needed, and returns the compiled
// goja program.
func getBigIntProgram() *goja.Program {
compileOnce.Do(func() {
compiledBigInt = goja.MustCompile("bigInt", bigIntegerJS, false)
})
return compiledBigInt
}
type toBigFn = func(vm *goja.Runtime, val string) (goja.Value, error)
type toBufFn = func(vm *goja.Runtime, val []byte) (goja.Value, error)
@ -563,7 +572,7 @@ func (t *jsTracer) setBuiltinFunctions() {
func (t *jsTracer) setTypeConverters() error {
// Inject bigint logic.
// TODO: To be replaced after goja adds support for native JS bigint.
toBigCode, err := t.vm.RunProgram(bigIntProgram)
toBigCode, err := t.vm.RunProgram(getBigIntProgram())
if err != nil {
return err
}