Equality for values -- new analysis, same conclusion

John Rose john.r.rose at oracle.com
Tue Aug 13 18:19:58 UTC 2019

On Aug 12, 2019, at 11:17 AM, Dan Smith <daniel.smith at oracle.com> wrote:

>> This is what I call L.I.F.E., the Legacy Idiom For Equality.  ID== is good here too.  FAST== would be fine here, and a JIT could perform that strength reduction if it notices that the == expression is post-dominated by Object.equals (on the false path).  I think that’s usually detectable.
> Major caveat for this kind of optimization: it relies on a "well-behaved" 'equals' method. If 'equals' can thrown an exception or have some other side effect (even indirectly) when a == b, we can't just blindly execute that code.
> Maybe the optimization you envision is able to cope with these possibilities. JIT is a mystery to me. But it seems like something that needs careful attention.

Yes it does. I think we need to consider (a) classifying equals methods which are well behaved and maybe (b) allowing the spec to open up loopholes for inexact execution of equals as a way of simplifying online classification.

The JIT optimization requires skipping the SAME== check if the equals method will also carry that burden. For that to be valid we need to ensure that applying equals of the same value to itself is a constant true with no side effects. This is easy to argue for IMO since that is part of the contract of Object::equals. What’s harder is to carve the spec so that equals methods which violate it can be covered within the limits of the spec. I’d like the JIT to have latitude under the JVMS to run such methods at will after SAME== is true and accept their side effects as part of the indeterminate behavior that occurs when an object fails its contract. 

If I can’t get that latitude, there are other things we can do to special case Object::equals, but more transparently to the JVMS. The simplest is to compile two versions, one fused with SAME== and one not. The first one replaces uses of LIFE, transparently. No spec impact. Maybe the compiled method has two entry points. Call the two compile units C::equals and C::equals/LIFE. The latter prepends a SAME== rest to the former. Since the prepended test is now in the same compilation unit, it can be fused and combined with the user-written equals logic. It won’t be executed redundantly out of line. 

More information about the valhalla-spec-observers mailing list