null checks vs. class resolution, and translation strategy for casts
John Rose
john.r.rose at oracle.com
Thu Apr 9 20:02:44 UTC 2020
Correction… The recommended reflective approach has
a flaw (easily fixed), which makes indy my real recommendation.
On Apr 8, 2020, at 11:43 AM, John Rose <john.r.rose at oracle.com> wrote:
> …
> I have a proposal for a translation strategy:
>
> 1. Translate casts to inline classes differently from “classic”
> casts. Add an extra step of null hostility. For very low-level
> reasons, I suggest using “ldc X” followed by Class::cast.
>
> Generally speaking, it’s a reasonable move to use reflective
> API points (like Class::cast) on constant metadata (like X.class)
> to implement language semantics.
This suggestion is incomplete. If the result of the cast is
going to be used as type X, then the verifier must be
pacified by adding `checkcast X`. Basically, you have
to do both reflective and intrinsic cast operations, if you
need to get the verifier on board, as well as do a null
check. That tips me over to recommending indy instead,
which was #2. Indy, that Swiss army knife of an instruction,
can get it done in one.
> The following alternatives are also possible; I present them
> in decreasing order of preference:
>
> 2. Use invokedynamic to roll our own instruction. It will
> be a trivial BSM since we are really just doing an asType
> operation. But I think this is probably overkill, despite
> my fondness for indy.
For a conversion to type X, where X may be a null-hostile
inline type (or any type whose semantics is not exactly
covered by native checkcast), a single invokedynamic
instruction will cover the operational semantics
required and will also feed the right type to the verifier.
It will have this signature:
(Object) => X
It will have a utility bootstrap method which materializes
conversions, basically riffing on MethodHandles::identity
and asType. (Not MethodHandles::explicitCastArguments,
because we are concerned with checked reference conversions.)
It will have *no extra arguments* (not even X.class), because
the BSM can easily derive X.class from the return type of
the method type signature passed to the BSM.
ConstantCallSite convertBSM(Lookup ig1, String ig2, MethodType mt) {
var mh = MethodHandles.identity(Object.class).asType(mt);
return new ConstantCallSite(mh);
}
As such, it is a candidate for proposed simplifications to
bootstrap method configuration (but not the simplest such
simplifications, because of the need to feed X.class into
the linkage logic).
MethodHandle simplifiedConvertBSM() {
return MethodHandles.identity(Object.class);
}
(At some point I should write up those simplifications,
shouldn’t I?)
— John
More information about the valhalla-spec-observers
mailing list