Suboptimal C2 code generation

Vitaly Davidovich vitalyd at gmail.com
Thu Nov 19 22:58:27 UTC 2015


Hi guys,

Consider the following code/setup (8u51 C2 compiler):

private interface I
    {
        long value();

        long value2();
    }

private static final class C implements I
    {

        @Override
        public long value() {
            return 1;
        }

        @Override
        public long value2() {
            return 1;
        }
    }

private static final class Wrapper
    {
        private I _i;

        public long value() {
            return _i != null ? _i.value() : -1;
        }

        public long value2() {
            return _i != null ? _i.value2() : -1;
        }
    }

// The below is in the outer class now

private final Wrapper _w = new Wrapper();

private long doIt() {
        return _w.value() + _w.value2();
 }

Simple harness to get code generated:

public void foo() {
        int s = 0;
        for (int i = 0; i < 15_000; ++i) {
            if (i % 1000 == 0) {
                _w._i = null;
            } else {
                _w._i = new C();
            }
            s += doIt();
        }
        System.out.println(s);
    }

The idea here is to create a profile whereby vast majority of the time
_w._i is not null.  Here's the generated code for doIt(), which is the
method I'm interested in:

[Verified Entry Point]
  0x00007ff5f82e0080: mov    %eax,-0x14000(%rsp)
  0x00007ff5f82e0087: push   %rbp
  0x00007ff5f82e0088: sub    $0x20,%rsp         ;*synchronization entry

  0x00007ff5f82e008c: mov    0x18(%rsi),%r11d   ;*getfield _w

  0x00007ff5f82e0090: mov    0xc(%r12,%r11,8),%r11d  ;*getfield _i
                                                ; implicit exception:
dispatches to 0x00007ff5f82e0111
  0x00007ff5f82e0095: mov    $0x1,%eax
  0x00007ff5f82e009a: test   %r11d,%r11d
  0x00007ff5f82e009d: je     0x00007ff5f82e00d4  ;*ifnull

  0x00007ff5f82e009f: mov    0x8(%r12,%r11,8),%r8d
  0x00007ff5f82e00a4: cmp    $0xf8015a89,%r8d   ;   {metadata('$C')} //
NOTE: I'm stripping away the nonessential fully qualified name
  0x00007ff5f82e00ab: jne    0x00007ff5f82e00f9  ;*invokeinterface value

  0x00007ff5f82e00ad: mov    $0x1,%ebp          ;*lreturn

  0x00007ff5f82e00b2: test   %r11d,%r11d
  0x00007ff5f82e00b5: je     0x00007ff5f82e00dd  ;*ifnull

  0x00007ff5f82e00b7: mov    0x8(%r12,%r11,8),%r10d
  0x00007ff5f82e00bc: cmp    $0xf8015a89,%r10d  ;   {metadata('$C')}
  0x00007ff5f82e00c3: jne    0x00007ff5f82e00e6  ;*lreturn

  0x00007ff5f82e00c5: add    %rbp,%rax          ;*ladd

  0x00007ff5f82e00c8: add    $0x20,%rsp
  0x00007ff5f82e00cc: pop    %rbp
  0x00007ff5f82e00cd: test   %eax,0x5e11f2d(%rip)        #
0x00007ff5fe0f2000
                                                ;   {poll_return}
  0x00007ff5f82e00d3: retq

Does anyone know why (a) the null check is performed twice and (b) the type
check for $C is performed twice? The simple getters were devirtualized and
constants inlined, which is nice, but I'm wondering why there are redundant
safety checks.

Thanks
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20151119/4af18803/attachment.html>


More information about the hotspot-compiler-dev mailing list