<div dir="ltr">Hi Vladimir,<div><br></div><div>Yes, this is exactly it -- "halfway to desired shape" is a great description.</div><div><br></div><div>The motivating example, from which I extracted this small illustrative one, is wrapping an instance of some interface and providing a different/narrowed view on top of it; the wrapped interface object has strong profile towards one type, with a very small occurrence of it being null.  After wrapping it, the wrapper is then used to invoke another method in the following manner:</div><div><br></div><div>Wrapper w = ...;</div><div>callAnotherMethod(w.value(), w.value2(), w.value3(), w.value4()...);</div><div><br></div><div>Each of these valueX() methods internally does that null check.  I wanted to see if the JIT would effectively transform that chain into:</div><div><br></div><div>if (w.i != null) {</div><div>    callAnotherMethod(<no repeated null checks, just call into the interface methods>);</div><div>} else {</div><div>   callAnotherMethod(<use the null value branches from all those accessors>);</div><div>}</div><div><br></div><div>After the above transformation and knowing that there's a single receiver type (when it's not null) with very simple code backing the interface methods, I was checking if the interface calls were devirtualized.  What I found was a bit surprising, which warranted this email :).</div><div><br></div><div>Would it be difficult to enhance this?</div><div><br></div><div>Thanks</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Nov 20, 2015 at 7:54 AM, Vladimir Ivanov <span dir="ltr"><<a href="mailto:vladimir.x.ivanov@oracle.com" target="_blank">vladimir.x.ivanov@oracle.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">It looks like C2 stops halfway to desired shape.<br>
The load is commoned, but repeated null check is not eliminated.<br>
<br>
Final IR shape looks like:<br>
  w = Load this._w<br>
<br>
  If (w == NULL) deopt<br>
<br>
  i = Load w._i<br>
<br>
  If (i != NULL) {<br>
    If (!i instanceof C) deopt<br>
  } v1 = Phi(T:1,F:-1);<br>
<br>
  If (i != NULL) {<br>
    If (!i instanceof C) deopt<br>
  } v2 = Phi(T:2,F:-1)<br>
<br>
  return v1+v2<br>
<br>
The next transformation would be:<br>
  w = Load this._w<br>
  If (w == NULL) deopt<br>
  i = Load w._i<br>
  If (i != NULL) {<br>
    If (!i instanceof C) deopt<br>
    If (!i instanceof C) deopt<br>
  } v1 = Phi(T:1,F:-1)<br>
    v2 = Phi(T:2,F:-1)<br>
  return v1+v2<br>
<br>
And finally:<br>
  w = Load this._w<br>
  If (w == NULL) deopt<br>
  i = Load w._i<br>
  If (i != NULL) {<br>
    If (!i instanceof C) deopt<br>
  } v1 = Phi(T:1,F:-1)<br>
    v2 = Phi(T:2,F:-1)<br>
  return i1+i2;<br>
<br>
Best regards,<br>
Vladimir Ivanov<span class=""><br>
<br>
On 11/20/15 5:29 AM, John Rose wrote:<br>
</span><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
On Nov 19, 2015, at 2:58 PM, Vitaly Davidovich <<a href="mailto:vitalyd@gmail.com" target="_blank">vitalyd@gmail.com</a><br></span><span class="">
<mailto:<a href="mailto:vitalyd@gmail.com" target="_blank">vitalyd@gmail.com</a>>> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
        return _w.value() + _w.value2();<br>
</blockquote>
<br>
Which is (ignoring non-taken null branches):<br>
<br>
         return _w._i.value() + _w._i.value2();<br>
<br>
There are two independent fetches of _w._i in the bytecode.<br>
The machine code is treating them as independent, where<br>
we would want the optimizer to use a common value.<br>
<br>
The machine code is optimistic that _w._i is always a C,<br>
but it appears to be leaving open the possibility that some<br>
activity not tracked by the JIT could store some other C2 <: I.<br>
<br>
What happens at 0x00007ff5f82e00f9?  Does it de-opt,<br>
or does it merge back into 0x00007ff5f82e00b2?  In the<br>
latter case, the JIT cannot assume that _w._i is a C.<br>
<br>
So, it could be a failure to de-opt, or it could be some<br>
fluff in the IR which is preventing the two _w._i from<br>
commoning.  Or something else.<br>
<br>
— John<br>
</span></blockquote>
</blockquote></div><br></div>