You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Introduce TypedClosures in the IR, which are closures without JS interop.
A `TypedClosure` is like a `Closure` but without any semantics for
JS interop. This is stronger than `Char`, which is "merely" opaque
to JS. A `Char` can still be passed to JS and has a meaningful
`toString()`. A `TypedClosure` *cannot* be passed to JS in any way.
That is enforced by making their type *not* a subtype of `any`.
Since a `TypedClosure` has no JS interop semantics, it is free to
strongly, statically type its parameters and result type.
More importantly, we can freely choose its representation in the
best possible way for the given target. On JS, that remains an
arrow function. On Wasm, however, we represent is as a pair of
`(capture data pointer, function pointer)`. This allows to compile
them in an efficient way that does not require going through a JS
bridge closure. The latter has been shown to have a devastating
impact on performance when a Scala function is used in a tight
loop.
The type of a `TypedClosure` is a `ClosureType`. It records its
parameter types and its result type. Closure types are non-variant:
they are only subtypes of themselves. As mentioned, they are not
subtypes of `any`. They are however subtypes of `void` and
supertypes of `nothing`.
To call a typed closure, we introduce a dedicated application node
`ApplyTypedClosure`. IR checking ensures that actual arguments match
the expected parameter types. The result type is directly used as
the type of the application.
There are no changes to the source language. In particular, there
is no way to express typed closures or their types at the user
level.
However, we change the compilation of SAM anonymous functions, both
for Scala functions and JVM-like SAMs, to use a `TypedClosure`
instead of a `Closure`. We wrap the `TypedClosure` inside an
instance of `scala.scalajs.runtime.TypedFunctionN`. These classes
are generated "by hand" in the build, since there is no user-level
way to define them. They have valid IR, though.
These changes have no real impact on the JS output (only marginal
naming differences). On Wasm, however, they make Scala functions
much, much faster. Before, a Scala function in a typed loop would
cause a Wasm implementation to be, in the worst measured case, 20x
slower than on JS. After these changes, similar benchmarks become
significantly faster on Wasm than on JS.
0 commit comments