Okay, Vitaly, you convinced me and I replaced the combined check with two ORed checks:

-        return (((SAFE_BOUND - newCapacity) | newCapacity) < 0)
+        return (newCapacity < 0 || SAFE_BOUND - newCapacity < 0)

The webrev was updated in place:
http://cr.openjdk.java.net/~igerasim/8149330/01/webrev/

Sincerely yours,
Ivan

On 23.02.2016 3:00, Vitaly Davidovich wrote:
Yes, but my hope would be that code could be written in the natural/"canonical" manner and the JIT could then optimize accordingly (possibly based on the target). I looked at 8u60 C2 generated asm and it does not do a transformation similar to the manual elimination in your code; I played around with similar looking C++ code using gcc 5.3 and clang 3.7, and they actually sometimes (depends on what's inside the if/else blocks themselves) generate better code with the || present.

But really, this is the JIT's domain -- it knows the target arch, it knows whether it's an OoO cpu or not, it knows whether (highly predictable) branch elimination can be worthwhile, it can estimate whether logical OR version (as written above) that carries a dependency on both sides of the expression (granted dependencies are in registers/stack slots here) is better than letting cpu run both sides in parallel (no data dependency), and so on. I'm not even entirely certain the above transform yields any benefit on modern cpus, yet it contorts the code somewhat (this particular example isn't too bad though); that's not even taking into account that what follows this nano optimization is an Arrays.copyOf operation, which will almost certainly dominate the cost here.

I recall seeing Martin doing similar gymnastics in the ArrayList/Vector changes he alluded to, but my hope would be that code can be written in a "canonical" manner and let the JIT optimize it as it sees fit.

Just my $.02 :)


On Mon, Feb 22, 2016 at 6:40 PM, Ivan Gerasimov <[email protected] <mailto:[email protected]>> wrote:



    On 22.02.2016 23:43, Vitaly Davidovich wrote:
    165 final int SAFE_BOUND = (MAX_ARRAY_SIZE >> coder);
    166 if (((SAFE_BOUND - newCapacity) | newCapacity) < 0) {
    Do the hotspot compiler engineers know you guys are doing manual
    branch elimination like this? :)


    Well, both these checks will be performed in the common case (and
    we know it in advance), so combining them together seems to be
    worthwhile.

    Sincerely yours,
    Ivan

    On Mon, Feb 22, 2016 at 2:20 PM, Ivan Gerasimov
    <[email protected] <mailto:[email protected]>> wrote:

        Hello!

        When the capacity of a StringBuilder needs to be increased
        (either due to append() or due to explicit call to
        ensureCapacity()), the new capacity is calculated as "twice
        the old capacity, plus 2", rounded down to Integer.MAX_VALUE:
        
http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html#ensureCapacity-int-
        Because of that, StringBuilder throws OOM early, even though
        there may be room to grow.

        The proposed solution is to reserve a few bytes at the top of
        the range and only try to allocate them if absolutely required.

        The regression test is @ignored by default, as it is too
        greedy for memory.

        Would you please help review the fix?

        BUGURL: https://bugs.openjdk.java.net/browse/JDK-8149330
        WEBREV:
        http://cr.openjdk.java.net/~igerasim/8149330/00/webrev/
        <http://cr.openjdk.java.net/%7Eigerasim/8149330/00/webrev/>

        Sincerely yours,
        Ivan





Reply via email to