Updated VM-bridges document
Karen Kinnear
karen.kinnear at oracle.com
Thu Apr 11 21:18:54 UTC 2019
> On Apr 10, 2019, at 5:22 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
>
> OK, so in the old world, D has m(Date).
>
>
> Now, D has m(LDT), with a forwarder from m(Date) -> m(LDT), with some sort of metadata stapled somewhere to effect the Date <--> LDT conversions.
>
>> class E extends D { m(Date); } which now overrides the forwarder.
>> We do not change class E. We do not recompile it
>
>> old class ClientD invokevirtual D.m(Date) receiver:E
>> Migration step 3: new class ClientD invokevirtual D.m(LDT) receiver:E
>> resolution: finds D.m(LDT)
>> selection: starts with E, there is no E.m(LDT) so call D.m(LDT)
(LDT is LocalDateTime)
>
> OK, so at this point, the classfiles that have been loaded look like:
>
> class D {
> void m(LDT) { real method }
> @Forwarding(m(LDT)) abstract void m(Date);
> }
>
> class E extends D {
> @Override
> m(Date) { impl }
> }
>
> So D has members m(LTD) and m(Date), the latter is a forwarder. Therefore E has the same members (instance methods are inherited).
From a source perspective, E has the same names of members, although it has overridden the contents of m(Date).
>
> Here's how I would imagine this turns into in the VM:
not important, but this was m(LDT) not m(LTD)
>
> class D {
> void m(LTD) { real method }
> void m(Date d) { m(adapt(d)); } // generated forwarder
> }
>
> class E extends D {
> private void m$synthetic(Date d) { real method, body as present in classfile }
I would expect that the existing m(Date) with the real method would stay unchanged - including
the name and the access controls - since there may be clients of subclass E still trying to invoke it.
> void m(LTD ltd) { m$synthetic(adapt(ltd)); } // generated reverser
I think we are in agreement that there is a reverser:
void m(LDT) generated receiver:
1) adapt LDT -> Date
2) invoke local m(Date)
3) if return had changed, adapt back
// adaptations for reverser are the inverse as for the forwarder
> }
>
>
> resolves
> selects
> invokevirtual D::m(LTD)
> D::m(LTD)
> E::m(LTD)
> invokevirtual D::m(Date)
> D::m(Date)
> D::m(Date), forwards to invvir D::m(LTD)
> In turn, selects E::m(LTD)
> invokevirtual E::m(LTD)
> E::m(LTD)
> E::m(LTD)
> invokevirtual E::m(Date)
> D::m(Date)
> D::m(Date), forwards to invvir D::m(LTD)
> In turn, selects E::m(LTD)
> In other words, we arrange that once the vtable is laid out, it is as if no one ever overrides the forwarders -- they only override the real method. Hence the reverser is needed only where a class (like E) actually overrides a descriptor that corresponds to a forwarder.
A VM perspective:
invocation
dynamic receiver
resolution
NOT invoked
selection:
actual execution
invokevirtual D::m(LDT)
D
D.m(LDT)
D.m(LDT)
invokevirtual D::m(LDT)
E
D.m(LDT)
E.m(LDT)
reverser: adapt LDT->Date
invoke local E.m(Date)
if return had changed, adapt return back
invokevirtual D::m(Date)
D
D.m(Date)
D.m(Date)
forwarder: adapt Date->LDT
invoke local m(LDT)
if return had changed, adapt
invokevirtual D.m(Date)
E
D.m(Date)
E.m(Date)
invokevirtual E.m(LDT)
E
E.m(LDT)
reverser)
E.m(LDT):
reverser: adapt LDT->Date
invoke local E.m(Date)
if return had changed, adapt return back
invokevirtual E.m(Date)
E
E.m(Date)
E.m(Date) // original - unchanged behavior
Point 1: The resolved method is NOT invoked, it is only the selected method that is invoked.
We do NOT follow forwarding for the resolved method.
If the resolved method happens to also be the selected method, we will now execute it and will follow the forwarding.
Note, the same applies to fields - we will not get/set the resolved field. We will get/set the
selected field, and follow the forwarding at that point.
Point 2: Hotspot’s vtable implementation is set up so that for
class E - a vtable (or itable) is a selection cache. It allows for fast virtual dispatch.
For Hotspot, for class E, the vtable starts with the inherited vtable from superclass D.
Any entries in the table are replaced when a method overrides an inherited method.
Additional methods are appended.
So resolution gives you the offset in the vtable. Selection tells you which vtable owner
to index based on that offset.
We KEEP the existing methods in the subclass so that they are executed exactly the same
with no change in behavior (no exceptions due to narrowing etc.)
Agree that so far the only reverser need I have identified is when a class overrides a forwarder.
>
>> It is my belief that the expected behavior is that we want to invoke E.m(Date) with asType signature matching.
>> To do that, I propose that if the vm detects overriding of a forwarder, that we need to generate a reverser:
>>
>> E.m(Date) overrides D.m(Date)// forwarder: Date->LDT/invoke D.m(LDT)/return conversion
>>
>> The reverser that we want would be
>> E.m(LDT) overrides D.m(LDT) // reverser: LDT->Date/invoke E.m(Date)/return reverse conversion
>
> I think we want: a reverser for E::m(LTD), but not for E::m(Date). Are we saying the same thing?
I think so on this sentence - we already have E::m(Date) overriding forwarder D::m(Date) so we need
a reverser E::m(LDT) to override the forwardee and reverse to call E::m(Date) with the reverse adaptations.
thanks,
Karen
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/valhalla-spec-experts/attachments/20190411/3b294c07/attachment-0001.html>
More information about the valhalla-spec-experts
mailing list