Summary
Might be a necrobump of #2577
Currently pattern matching on union types discriminates the types in the union using instanceOf. This incurs a significant performance penalty for larger union types and makes it infeasible to dispatch the code based on the type(switch on a tag instead of an if(... instanceof ...) ladder. Additionally construction of large data structures is slow due to the need to constantly allocate new heap objects(instead of being JS literal). JIT is affected as accessing a property/walking the prototype chain is not cheap.
Consider replacing data structures with an array ["TAG", value0, value1, ..., valueN]
Motivation
After running sed -i 's/instanceof/.constructor ===/g' dist/bundle.js on https://github.com/erlscripten/erlps-aesophia I've decreased the runtime by 6%. This makes sense as erlscripten is based on the following union type - https://github.com/erlscripten/erlps-core/blob/c881e39901a2d6c29972b8a13c3c1ee760754560/src/Erlang/Type.purs#L42
I've started benchmarking various alternatives to instanceof and came to the conclusion that by just keeping everything in an array we generate fast JS which also can be easily optimized by the JIT compiler.
For
data Tree = Node Tree Tree | Leaf Int
foo :: Tree -> Int -> Int
foo (Node l r) acc = foo r (foo l acc)
foo (Leaf x) acc = acc + x
main :: Int
main = foo (Node (Node (Node (Leaf 1) (Leaf 2)) (Node (Leaf 3) (Leaf 4))) (Node (Node (Leaf 5) (Leaf 6)) (Node (Leaf 7) (Leaf 8)))) 0
Keeping everything in an array yields an 95%+ performance improvement https://jsbench.me/beklw3j28m/2
I've also noticed that construction of large terms in erlscripten is suspiciously slow(due to the usage of "new")
Proposal
Replace new Foo(a1, a2, a3) with ['Foo', a1, a2, a3]
Replace v instanceof Foo with v[0] === 'Foo'
Replace v.valueN with v[N+1]
Examples
Take a look at the benchmark: https://jsbench.me/beklw3j28m/2
Small question
In the Erlscripten project we plan to maintain and ship a custom superoptimizing Purescript compiler.
Right now it lives here: https://github.com/erlscripten/purescript/commits/erlscripten-lambdaelim It includes some unmerged fixes in this repository and it features a completelly reworked codegen which never generates additional lamdas(it uses let statements instead of lambdas to save on stack space, this also allows for TCO to be applied everywhere). We will implement this proposal on our fork next week. Would you be interested in a PR? Is this a feature which can be upstreamed?
Summary
Might be a necrobump of #2577
Currently pattern matching on union types discriminates the types in the union using instanceOf. This incurs a significant performance penalty for larger union types and makes it infeasible to dispatch the code based on the type(switch on a tag instead of an if(... instanceof ...) ladder. Additionally construction of large data structures is slow due to the need to constantly allocate new heap objects(instead of being JS literal). JIT is affected as accessing a property/walking the prototype chain is not cheap.
Consider replacing data structures with an array ["TAG", value0, value1, ..., valueN]
Motivation
After running
sed -i 's/instanceof/.constructor ===/g' dist/bundle.json https://github.com/erlscripten/erlps-aesophia I've decreased the runtime by 6%. This makes sense as erlscripten is based on the following union type - https://github.com/erlscripten/erlps-core/blob/c881e39901a2d6c29972b8a13c3c1ee760754560/src/Erlang/Type.purs#L42I've started benchmarking various alternatives to instanceof and came to the conclusion that by just keeping everything in an array we generate fast JS which also can be easily optimized by the JIT compiler.
For
Keeping everything in an array yields an 95%+ performance improvement https://jsbench.me/beklw3j28m/2
I've also noticed that construction of large terms in erlscripten is suspiciously slow(due to the usage of "new")
Proposal
Replace
new Foo(a1, a2, a3)with['Foo', a1, a2, a3]Replace
v instanceof Foowithv[0] === 'Foo'Replace
v.valueNwithv[N+1]Examples
Take a look at the benchmark: https://jsbench.me/beklw3j28m/2
Small question
In the Erlscripten project we plan to maintain and ship a custom superoptimizing Purescript compiler.
Right now it lives here: https://github.com/erlscripten/purescript/commits/erlscripten-lambdaelim It includes some unmerged fixes in this repository and it features a completelly reworked codegen which never generates additional lamdas(it uses let statements instead of lambdas to save on stack space, this also allows for TCO to be applied everywhere). We will implement this proposal on our fork next week. Would you be interested in a PR? Is this a feature which can be upstreamed?