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

forax at univ-mlv.fr forax at univ-mlv.fr
Mon Aug 14 13:55:43 UTC 2023


> 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 
} 

> --Dan

Rémi 

> On Sat, Aug 12, 2023 at 6:49 PM John Rose < [ mailto:john.r.rose at oracle.com |
> 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 < [ mailto:forax at univ-mlv.fr |
>> > 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/fa393413/attachment-0001.htm>


More information about the valhalla-spec-observers mailing list