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