[records] translation strategy (factory methods)

John Rose john.r.rose at oracle.com
Fri Jan 10 06:36:11 UTC 2020

Another bit of translation strategy:  What does “new R(a,b,c)” compile
to, at the bytecode level?  At some point we will cut over to factory methods,
for at least some types (inlines).  Should be pre-empt this trend for records,
and mandate that records are *always* created by factory methods?

The benefit is that records can be evolved to inline types without
recompiling their *clients*.  The risk is that (if we don’t take this
option) that we will have records which are constrained to be identity]
types *until all clients are recompiled*.  (No I don’t believe that you
can translate “new;dup;invokespecial<init>” into “invokestatic”.
Sorry, that's a pipe dream.)  This seems sad, given that records are
partially inspired by value types.

(From my 2012 blog on value types: “A value type is immutable… The
equals and hashCode operations are strictly component-wise.”  Kind
of like a record.  Meanwhile, inlines in Valhalla give component-wise
meaning to acmp not equals and identityHashCode not hashCode.)

I see three options regarding factories (apart from the above pipe dream):

0.  Do nothing.  Records are just abbreviated classes.  Whatever works
or doesn’t for evolving general identity classes to inline classes works
or doesn’t for records.  No special benefit, in this vein, to declaring
something a record.

1. Define a factory, on top of today’s JVM.  Records use a hidden API,
desugaring “new R(a,b)” to a static “R.$make$(a,b)”.

2. Define a factory, anticipating Valhalla, using a JVM-defined entry point.
The expression “new R(a,b)” compiles to “invokestatic R.<init>(int,int)R”,
preceded by a push of a and b.  This requires a (relatively shallow) change
to the JVM to double down on the name “<init>” as the factory behind a

The advantage of 2 is that, if we correctly predict that “<init>” is the claimed
factory method for value types, then records can be evolved to inlines out
of the box.  The advantage of 1 is that we don’t need to make that prediction.

There’s also this:

3. Do 1. but when 2. becomes an option create an auto-bridge from “$make$”
to “<init>”.  New code doesn’t need the bridge because it compiles to call
“<init>” out of the box.

Here’s a gut check for this group:  Are we confident enough with Valhalla
that we can settled on “invokestatic <init>” as the new dance for creating
an instance that may or may not be an inline?

— John

More information about the amber-spec-experts mailing list