does call site polymorphism factor in method overrides?

210 views
Skip to first unread message

Brian Harris

unread,
Dec 29, 2019, 10:22:24 AM12/29/19
to mechanica...@googlegroups.com
Hello!



When the runtime type of the call receiver is being observed, is it considered whether that type actually overrides the method in question? For example, when the method is an interface's default method that none of the runtime call receivers override, can we expect to get a monomorphic call site regardless of how many different receiver types are observed at runtime, given there is only one method body to invoke?

Thanks
Brian

Vitaly Davidovich

unread,
Dec 29, 2019, 3:42:45 PM12/29/19
to mechanica...@googlegroups.com
In Hotspot, CHA is currently (AFAIK) disabled for default methods (
https://bugs.openjdk.java.net/browse/JDK-8036580).  So you have to be careful putting hot code into them.  Overriding the method in the impl and just calling super will at least restore some performance if type profiling at the callsite helps.

Thanks
Brian

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/mechanical-sympathy/CAFtUM9Zt%2BwJvkDix_ZEYA%2B5u6hA86VQW7d5ceEyvxetiLvq%2BfA%40mail.gmail.com.
--
Sent from my phone

Brian Harris

unread,
Dec 30, 2019, 11:13:53 AM12/30/19
to mechanica...@googlegroups.com
Good to know Vitaly! 

So a poor example then. Better example is an abstract class with a method implementation that no subtypes override, yet multiple subtypes are found to be the receiver of a particular call site. Should we expect a monomorphic call site in that case.

Remi Forax

unread,
Dec 30, 2019, 1:09:06 PM12/30/19
to mechanical-sympathy
De: "Brian Harris" <brianfr...@gmail.com>
À: "mechanical-sympathy" <mechanica...@googlegroups.com>
Envoyé: Lundi 30 Décembre 2019 17:13:38
Objet: Re: does call site polymorphism factor in method overrides?
Good to know Vitaly! 
So a poor example then. Better example is an abstract class with a method implementation that no subtypes override, yet multiple subtypes are found to be the receiver of a particular call site. Should we expect a monomorphic call site in that case.

On Sun, Dec 29, 2019 at 12:42 PM Vitaly Davidovich <vit...@gmail.com> wrote:


On Sun, Dec 29, 2019 at 10:22 AM Brian Harris <brianfr...@gmail.com> wrote:
Hello!


When the runtime type of the call receiver is being observed, is it considered whether that type actually overrides the method in question? For example, when the method is an interface's default method that none of the runtime call receivers override, can we expect to get a monomorphic call site regardless of how many different receiver types are observed at runtime, given there is only one method body to invoke?
In Hotspot, CHA is currently (AFAIK) disabled for default methods (
https://bugs.openjdk.java.net/browse/JDK-8036580).  So you have to be careful putting hot code into them.  Overriding the method in the impl and just calling super will at least restore some performance if type profiling at the callsite helps.

CHA only avoids one cheap cmp + jump that will perfectly predicted, so i'm not sure you will able be to see any perf difference apart from using a micro benchmark.
And as far as i remember, CHA has never worked for abstract methods and nobody care.


Thanks
Brian

Rémi

Vitaly Davidovich

unread,
Dec 30, 2019, 1:43:41 PM12/30/19
to mechanica...@googlegroups.com
Yeah, I don’t think CHA works for a type-megamorphic callsite that targets the same method in the type hierarchy.  I might be wrong, but pretty sure Hotspot doesn’t handle this case - it ends up being a virtual call if there’s no dominant receiver type.

The big (potential) optimization loss here would be inlining; branch + call overhead itself is unlikely to matter modulo truly trivial code called in a tight loop.  Missed optimizations due to inlining failure is the real problem.


Thanks
Brian

Rémi

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.

Remi Forax

unread,
Dec 30, 2019, 1:56:56 PM12/30/19
to mechanical-sympathy
no, you're right. It's a known weakness of c2. But as far as i remember, it works with graal.


The big (potential) optimization loss here would be inlining; branch + call overhead itself is unlikely to matter modulo truly trivial code called in a tight loop.  Missed optimizations due to inlining failure is the real problem.


Thanks
Brian

Rémi

Rémi

Wojciech Kudla

unread,
Dec 30, 2019, 2:46:32 PM12/30/19
to mechanical-sympathy
Hi Brian,

I think I can safely assume your question was dictated by (perfectly valid) concerns about method dispatch cost in extremely latency sensitive sections of code. After all, we've used to work together on the same problem space in the same institution only weeks ago.
Vitaly provided a valuable advice wrt default interface methods however I would supplement this with a general remark about dispatch cost:

invokeinterface > invokevirtual > invokestatic

(omitted invokespecial and invokedynamic as I have confidence they are completely out of scope for your case) 

For dispatch other than static you'll also have to pay the cost of implicit null check.
In some cases you can get substantial gains by cheating the runtime and using instanceof in conjunction with an if-else or switch to invoke a static method. 
If you can test this without committing atrocities on your code base I'd definitely recommend giving it a try. 


--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.

Gil Tene

unread,
Dec 31, 2019, 11:23:03 AM12/31/19
to mechanica...@googlegroups.com
In the specific case below, of a concrete method implemented in a base class (abstract or not) which has no overriding methods in any loaded subclass, CHA will identify the fact that only a single possible target exists and get the speed you seek regardless of encountered polymorphism level at the call site, (so yes, works even in megamorphic call sites).

Getters and setters are great (and very common) examples of this.

And when CHA can prove a single target, the cost is no higher than an invokeststic (assuming the object reference is already known to be non-null for some other reason in the same frame, which tends to overwhelmingly be the case).

To Remi’s point, in cases that are monomorphic, guarded inlining can be so close to CHA in results that it’s hard to measure the difference, since the difference becomes a perfectly predicted cmp + jmp. When going megamorphic, CHA benefits (compared to guarded inlining) depend on the level of megamorphism and the JIT you end up using. E.g. HotSpot/OpenJDK will do biomorphic guarded inlining, and while the jmp is not perfectly predictable, it often is “very very predictable” (hardware branch predictors are amazing things). Falcon (in Zing) and the Graal JITs will both do guarded inlining on much more megamorphic cases (e.g. hexamorphic, septamorphic, or octamorphic guarded inlining have shown real benefits). But if your megamorphism level blows past the JITs guarded inlining levels, you end up with a vcall, and more importantly, loose the optimization benefits that come from inlining the target. In the case where there is a single target that CHA can identify, even that level of megamorphism will get the benefits of inlining. But in practice, those situations (where CHA is a win) are very rare these days (especially with the level of megamorphism that a Falcon and a Graal will put up with and still inline).

On Monday, December 30, 2019 at 8:13:53 AM UTC-8, Brian Harris wrote:
Good to know Vitaly! 

So a poor example then. Better example is an abstract class with a method implementation that no subtypes override, yet multiple subtypes are found to be the receiver of a particular call site. Should we expect a monomorphic call site in that case.

On Sun, Dec 29, 2019 at 12:42 PM Vitaly Davidovich <vit...@gmail.com> wrote:
On Sun, Dec 29, 2019 at 10:22 AM Brian Harris <brianfr...@gmail.com> wrote:
Hello!



When the runtime type of the call receiver is being observed, is it considered whether that type actually overrides the method in question? For example, when the method is an interface's default method that none of the runtime call receivers override, can we expect to get a monomorphic call site regardless of how many different receiver types are observed at runtime, given there is only one method body to invoke?
In Hotspot, CHA is currently (AFAIK) disabled for default methods (
https://bugs.openjdk.java.net/browse/JDK-8036580).  So you have to be careful putting hot code into them.  Overriding the method in the impl and just calling super will at least restore some performance if type profiling at the callsite helps.

Thanks
Brian

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-sympathy+unsub...@googlegroups.com.
--
Sent from my phone

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-sympathy+unsub...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages