On Aug 12, 2019, at 11:17 AM, Dan Smith <[email protected]> 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.
