RFR: 8149330: Capacity of StringBuilder should not get close to Integer.MAX_VALUE unless necessary

Ivan Gerasimov ivan.gerasimov at oracle.com
Tue Feb 23 11:39:27 UTC 2016

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:

Sincerely yours,

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 
> <ivan.gerasimov at oracle.com <mailto:ivan.gerasimov at oracle.com>> 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
>>     <ivan.gerasimov at oracle.com <mailto:ivan.gerasimov at oracle.com>> 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

More information about the core-libs-dev mailing list