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
Replace the JS object given to jl.Class by primitive IR operations.
`java.lang.Class` requires primitive capabilities that only the
linker can provide for most of its core methods. This commit changes
the fundamental way to provide those.
In the process, remove creation of multi-dimensional arrays from
the IR, and move it to user-space instead.
---
Previously, the contract was that the linker provided a JS object
with specified properties and methods to the constructor of
`jl.Class`. For example, it contained a `"name"` property in order
to implement `jl.Class.getName()`. We happened to reuse the
`$TypeData` instance as that object, for convenience, and to avoid
more indirections.
This design grew organically over the years, and was eventually
specified in Scala.js IR 1.0.0. However, it always had some
shortcomings that I was not happy about.
First, the `getSuperclass()` method had to be special-cased in the
Analyzer and Emitter: its very presence requires additional metadata.
When it is not reachable, we do not actually provide the supposedly
specified member `"getSuperclass"()` on the JS object. That assumes
that only `jl.Class.getSuperclass()` actually calls that method.
In turn, that assumes it never gets inlined (!), since doing so
would make it unreachable, but the feature would still be required.
Second, for optimization purposes, the emitter needs direct access
to the `$TypeData` stored inside `jl.Class` (for some of its
Transients). There again, that assumed a field with a particular
name be present in `jl.Class` in which the JS object would be
stored. This implicit requirement was already leaking in the way
`jl.Class` was written, in order to prevent scalac from renaming
the field.
---
In this commit, we completely change the approach, and therefore
the IR spec. We remove the JS object passed to `jl.Class`; its
constructor now takes no arguments. Instead, we add primitives in
the IR, in the form of new `UnaryOp`s and `BinaryOp`s. These new
primitives operate on an argument of type `jl.Class!`, and possibly
a second argument.
For example, `UnaryOp.Class_name` replaces the functionality
previously offered by the `"name"` field. `BinaryOp.Class_superClass`
replaces `"getSuperclass"()`.
It is up to the backend to ensure it can, somehow, implement those
operations given an instance of `jl.Class`. We choose to add a
magic field to `jl.Class` at the Emitter level to store the
corresponding instance of `$TypeData`, and implement the operations
in terms of that.
The approach has several benefits:
* It solves the two fundamental issues of the JS object, mentioned
above.
* It does not require "public" (unminifiable) property names for
the features; since there is no JS object spec, we can consistently
minify those members.
* Several methods that were given an *intrinsic* treatment by the
optimizer now fall, more naturally, under regular folding of
operations.
---
Since we are changing the spec anyway, we use the opportunity to
switch what is primitive about `Array.newInstance`. Previously, the
overload with multiple dimensions was primitive, and the one with a
single dimension delegated to it. This was a waste, since usages of
the multi-dimensional overload are basically non-existent otherwise.
Similarly, the `NewArray` node was designed for multiple dimensions,
and the single dimension was a special case.
We now make the one-dimensional operations the only primitives.
We implement the multi-dimensional overload of `newInstance` in
terms of the other one. We also use that overload as a replacement
for multi-dimensional `NewArray` nodes. This simplifies the treatment
in the linker, and produces shorter and more efficient code at the
end of the day.
---
The change of approach comes with a non-negligible cost for backward
compatibility. It is entirely done using deserialization hacks. The
most glaring issue is the synthesization of the multi-dimensional
overload of `Array.newInstance`.
In this commit, we do not change the library/compiler yet, so that
we can exercise the deserialization hacks.
0 commit comments