Target of opportunity: remove method <vnew> and aconst_init / withfield opcodes

Dan Heidinga heidinga at redhat.com
Mon Aug 14 14:35:31 UTC 2023


On Mon, Aug 14, 2023 at 9:55 AM <forax at univ-mlv.fr> wrote:

>
>
> ------------------------------
>
> *From: *"Dan Heidinga" <heidinga at redhat.com>
> *To: *"John Rose" <john.r.rose at oracle.com>
> *Cc: *"Remi Forax" <forax at univ-mlv.fr>, "valhalla-spec-experts" <
> valhalla-spec-experts at openjdk.java.net>
> *Sent: *Monday, August 14, 2023 2:53:31 PM
> *Subject: *Re: Target of opportunity: remove method <vnew> and
> aconst_init / withfield opcodes
>
> Can one of you sketch out the bytecode sequences being proposed?  Being
> able to look at some concrete "before we used <vnew>/aconst_init/withfield"
> and now "we use ....." comparisons would make the proposal clearer.
> For a value class like Point, with a "Point changeX(int x)" method, we
> used withfield to pop an instance off the stack, create a new instance with
> the updated single field, and put that instance back on the stack which
> allows us to preserve our immutability without needing a constructor per
> field we want to change.
>
> Old bytecode:
> Point changeX(int x) {
>   aload0
>   iload_1
>   withfield "Point:x"
>   areturn
> }
>
> What would the new bytecode do?
>
>
> Sure, for the content of the constructor of a value class the bytecode is
> almost the same as for an identity class, the only difference is that the
> call to super() is not emitted.
>
> The constructor of Point
>   <init>(int x, int y) {
>     aload 0
>     iload 1
>     putfield Field:x
>     aload 0
>     iload 2
>     putfield Field:y
>     return
>   }  // here, 'this' is not larval anymore
>
> For all the other methods, a value class or an identity class use the same
> bytecode, for the method Point:changeX
>   Point changeX(int x) {
>     new. // in larval state
>     dup
>     iload 1
>     aload 0
>     getfield Field:y
>     invokespecial Method Point:<init>(II)V
>     areturn // not larval anymore
>   }
>

If I'm following correctly, changing one field requires stacking all the
fields and calling the constructor?

>From a VM perspective withfield is nice but as I dig through my notes, I
don't see any notes on how we'd expose it in the language.  All the
examples I'm finding are either directly generating the withfield bytecode
or java source that shows the fields passing through a constructor.  Do we
have a model on how javac would generate withfield or have we already
defaulted in the ctor model?

--Dan


>
>
>
> --Dan
>
>
> Rémi
>
>
>
> On Sat, Aug 12, 2023 at 6:49 PM John Rose <john.r.rose at oracle.com> wrote:
>
>> The header bit is not a problem because value object headers have no
>> object monitor. Thus, their headers are relatively empty OC state. Lots of
>> slack.
>>
>> In the spirit of minimizing JVMS changes I think this approa), might make
>> sense. The new byte codes paired well with new Q-descriptors and new
>> verifier rules. Not so much now.
>>
>> Also, we already built the necessary states for serialization. The
>> verifier will also hide them for us in bytecode. That was a new discovery
>> yesterday over burgers.
>>
>> > On Aug 12, 2023, at 1:40 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>> >
>> > John and I and several others had several interresting discussions
>> yesterday about Valhalla,
>> > one of them about the removal of <vnew> and aconst_init/withfield,
>> something i've called in the past, solving the last mile issue.
>> >
>> > Currently, refactoring from/to a value class/identity class is not a
>> backward compatible move because of the way value classes are initialized
>> using the <vnew> factory method. The reason is that during the
>> initialization, a class instance is mutable but the VM considers that all
>> value class instances are non-mutable.
>> >
>> > But at the same time, in order to implement Serialization of value
>> classes (exactly de-serialization), there is a need for a mechanism to tag
>> value class instances as "not yet finished to be initialized", something
>> John refers has the object being in larval state because the
>> de-serialization first create the instance and then populate its fields. In
>> the lw prototypes, this is currently implemented using Unsafe.
>> >
>> > I think we have the opportunity now to use the same larval protocol for
>> all values classes, making them binary backward compatible with identity
>> classes. With both of them using the initialization protocol, the same
>> new/dup/invokespecial dance.
>> >
>> > In term of specification, the idea is that "new" on a value class
>> creates a larval instance and the end of the constructor mark the instance
>> as non-larval/true-value-instance.
>> >
>> > I think that using the same initialization protocol at callsite is a
>> good idea. We are re-aligning the bytecode with the Java code, One thing
>> wichh is currently hard to understand for our users is that currently the
>> Java code is the same for a value class and an identity class but the
>> generated bytecode is not binary compatible. This also go well with the
>> recent move to remove the Q-descriptor, we are moving toward the goal of
>> being fully binary backward compatible.
>> >
>> > We may want to modify the verifier to verify that "this" does not
>> escape the constructor in case of a value class, but I do not thing it's a
>> requirement, so it's maybe better to not do that :)
>> >
>> > The end of constructor is already a point where all VMs/JITs are able
>> to emit codes (for store/store barrier or finalizer registration), so we
>> are piggy backing on an existing concept. The only main drawback I see is
>> that the header of a buffered value type has to have one bit to indicate
>> the larval state and those header bits are really precious.
>> >
>> > regards,
>> > Rémi
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20230814/fcbe2893/attachment.htm>


More information about the valhalla-spec-observers mailing list