JDK-6932852 : HotSpot could do much better with do...while loop
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: compiler
  • Priority: P4
  • Status: Closed
  • Resolution: Incomplete
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2010-03-08
  • Updated: 2016-03-21
  • Resolved: 2016-03-21
Description
A DESCRIPTION OF THE REQUEST :
do...whole loop seems to be "forgotten" to optimize in comparison to simple while loop.


JUSTIFICATION :
Compare the 2 methods in the SOURCE section. They are equivalent, but do...while consumes 1152 bytes in comparison to simple while loop which only consumes 640 bytes after compilation.
In particular the inner loop wastes a lot of CPU instructions.

  From another variant see the most optimal register usage:
...
...
  0x00b8b28d: movzwl 0x2(%ebp),%ecx     ;*caload
                                        ; - java.lang.String::equals7@126 (line 1215)
  0x00b8b291: movzwl 0x2(%eax),%ebx     ;*caload
                                        ; - java.lang.String::equals7@119 (line 1215)
  0x00b8b295: cmp    %ecx,%ebx
  0x00b8b297: jne    0x00b8b302         ;*if_icmpeq
                                        ; - java.lang.String::equals7@127 (line 1215)
  0x00b8b299: movzwl 0x0(%ebp),%ecx     ;*caload
                                        ; - java.lang.String::equals7@126 (line 1215)
  0x00b8b29d: movzwl (%eax),%ebx        ;*caload
                                        ; - java.lang.String::equals7@119 (line 1215)
  0x00b8b2a0: cmp    %ecx,%ebx
  0x00b8b2a2: jne    0x00b8b302         ;*if_icmpeq
                                        ; - java.lang.String::equals7@127 (line 1215)
  0x00b8b2a4: movzwl -0x2(%ebp),%ecx    ;*caload
                                        ; - java.lang.String::equals7@126 (line 1215)
  0x00b8b2a8: movzwl -0x2(%eax),%ebp    ;*caload
                                        ; - java.lang.String::equals7@119 (line 1215)
  0x00b8b2ac: cmp    %ecx,%ebp
  0x00b8b2ae: jne    0x00b8b302         ;*if_icmpeq
                                        ; - java.lang.String::equals7@127 (line 1215)
  0x00b8b2b0: add    $0xfffffff8,%edi   ;*iinc
                                        ; - java.lang.String::equals7@106 (line 1213)
  0x00b8b2b3: cmp    0x8(%esp),%edi
  0x00b8b2b7: jg     0x00b8b230
  0x00b8b2bd: cmp    $0xffffffff,%edi
  0x00b8b2c0: jle    0x00b8b15b


EXPECTED VERSUS ACTUAL BEHAVIOR :
Attached seperatly

---------- BEGIN SOURCE ----------
    public boolean equals9(Object anObject) {
        if (this == anObject) // 1st check identitiy
            return true;
        if (anObject instanceof String) { // 2nd check type
            String anotherString = (String)anObject;
            int n = count;
            if (n == anotherString.count) { // 3rd check lengths
                int h1 = hash, h2 = anotherString.hash;
                if (n > 0) { // 4th avoid additional work if length == 0
                    if (h1 != 0 && h2 != 0) // 5th check the hashes
                        if (h1 != h2)
                            return false;
                        else if (n == 1)
                            return true;
                    char[] v1 = value, v2 = anotherString.value;
                    int o1 = offset, o2 = anotherString.offset;
                    if (v1 != v2 || o1 != o2) // 6th don't compare the chars if identical
                        while (n-- > 0) // only decrement 1 register
                            // to benefit from CPU's complex addressing modes
                            if (v1[o1+n] != v2[o2+n]) // compare the chars backwards
                                return false;
                }
                return true;
            }
        }
        return false;
    }


    public boolean equals11(Object anObject) {
        if (this == anObject) // 1st check identitiy
            return true;
        if (anObject instanceof String) { // 2nd check type
            String anotherString = (String)anObject;
            int n = count;
            if (n == anotherString.count) { // 3rd check lengths
                int h1 = hash, h2 = anotherString.hash;
                if (n-- > 0) { // 4th avoid additional work if length == 0
                    if (h1 != 0 && h2 != 0) // 5th check the hashes
                        if (h1 != h2)
                            return false;
                        else if (n == 0)
                            return true;
                    char[] v1 = value, v2 = anotherString.value;
                    int o1 = offset, o2 = anotherString.offset;
                    if (v1 != v2 || o1 != o2) // 6th don't compare the chars if identical
                        do // only decrement 1 register to benefit from CPU's complex addressing modes
                            if (v1[o1+n] != v2[o2+n]) // compare the chars backwards
                                return false;
                        while (n-- > 0);
                }
                return true;
            }
        }
        return false;
    }
---------- END SOURCE ----------

Comments
Please provide JMH benchmarks to show the issue.
21-03-2016