code generation of a switch on an enum

Vitaly Davidovich vitalyd at gmail.com
Thu Sep 11 03:14:47 UTC 2014


Sorry, forgot to mention one other thing.

The lookup switch performs redundant cmp followed by jmp instructions.
Something like this is emitted:

cmp $6, %ebp
je <some_label>
cmp $6, %ebp
jae <some_other_label>
... this repeats a bit until the binary search is narrowed down
sufficiently.

As far as I know, jmp doesn't affect flags so you could place consecutive
jmp instructions.  I hear much older x86 machines had a stall if two jmp
were placed together, requiring a nop to be placed in between,  but
supposedly that isn't an issue on today's cpus.

Is there a reason the code is generated like this?

Thanks

Sent from my phone
On Sep 10, 2014 11:02 PM, "Vitaly Davidovich" <vitalyd at gmail.com> wrote:

> Thanks John!
>
> Besides not special casing the FOUR constant here (which the bug report
> addresses), why is a lookup switch used and not a table switch? The numeric
> range is dense with no holes at all, so even if FOUR isn't special cased,
> it's surprising to see a lookup instead of a switch.
>
> Sent from my phone
> On Sep 10, 2014 10:50 PM, "John Rose" <john.r.rose at oracle.com> wrote:
>
>> So I went into JBS to find the bug for this long-known problem, and came
>> up empty.
>> Thanks for reporting it!  I filed this:
>>   https://bugs.openjdk.java.net/browse/JDK-8058192
>>
>> — John
>>
>> On Sep 10, 2014, at 3:54 PM, Vitaly Davidovich <vitalyd at gmail.com> wrote:
>>
>> > Hi guys,
>> >
>> > Looking at generated asm (x86-64 SandyBridge, 1.7u60) for a switch
>> statement on an enum from C2 compiler, I'm wondering whether there's some
>> missing profile information that could be incorporated into the generated
>> code.
>> >
>> > private enum E {
>> >       ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE
>> >     }
>> >
>> > private static int getInt(E e) {
>> >       switch (e) {
>> >       case ZERO: return 0;
>> >       case ONE: return 1;
>> >       case TWO: return 2;
>> >       case THREE: return 3;
>> >       case FOUR: return 4;
>> >       case FIVE: return 5;
>> >       case SIX: return 6;
>> >       case SEVEN: return 7;
>> >       case EIGHT: return 8;
>> >       case NINE: return 9;
>> >
>> >       default: throw new Error();
>> >       }
>> >     }
>> >
>> > public void foo() {
>> >       int sum = 0;
>> >       for (int i = 0; i < 100000; ++i) {
>> >           sum += getInt(E.FOUR);
>> >       }
>> >       System.out.println(sum);
>> >     }
>> >
>> > The generated code for getInt() appears to proceed through a binary
>> search of the enum ordinal range, trying to match the incoming argument.
>> But, as can be seen above, the incoming argument is always E.FOUR.  I tried
>> to restrict E to have only 4 members, but the strategy used by the JIT
>> didn't change.  Why isn't it doing a quick test against FOUR before
>> proceeding with the search through the value range?
>> >
>> > Also, what's the reason this isn't generating a direct lookup into a
>> switch table? If I change getInt() above to do the ordinal switching myself:
>> >
>> > switch (e.ordinal()) {
>> >       case 0: return 0;
>> >       case 1: return 1;
>> >       case 2: return 2;
>> >       case 3: return 3;
>> >       case 4: return 4;
>> >       case 5: return 5;
>> >       case 6: return 6;
>> >       case 7: return 7;
>> >       case 8: return 8;
>> >       case 9: return 9;
>> >
>> >       default: throw new Error();
>> >
>> > It still generates the same type of code.  For comparison, gcc 4.9 and
>> clang 3.4.1 generate a lookup into a switch table after checking that the
>> argument isn't going to go into the default case.
>> >
>> > I can paste the generated asm if that helps, but it should be easy to
>> reproduce given the above code.
>> >
>> > Thanks
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20140910/430abd91/attachment-0001.html>


More information about the hotspot-compiler-dev mailing list