Proposal: JDK-8148917 Enhanced-For Statement Should Allow Streams

Peter Levart peter.levart at
Tue Mar 12 10:29:22 UTC 2019

Hi John,

On 3/12/19 12:07 AM, John Rose wrote:
>> public static void main(String[] args) {
>>   for(int i : range(0, 100)) {
>>     System.out.println(i);
>>   }
>> }
>> It correctly compiles and prints numbers from 0 to 99. As IntStream
>> extends BaseStream<Integer, IntStream> and BaseStream<T, S extends
>> BaseStream<T, S>> defines Iterator<T> iterator(), it would be no
>> problem with using IntStream.range in such code pattern were
>> BaseStream extends IterableOnce<T>.
>> Of course this produces unnecessary garbage, as I said.
> This is a relatively simple kind of garbage to remove, because
> it is made (by calls to Integer.valueOf) at the adapted boundaries
> of the iterator, which are readily inlined into the loop.  The deeper
> internal logic of the range function is box-free, as is the loop itself,
> so the garbage is relatively easy to remove.
> That said, "out of the box" there is lots of garbage created unless
> -XX:+AggressiveUnboxing is turned on.  I assume Graal does a good
> job on it, even without this switch.
> If we ever succeed in suppressing the identity of java.lang.Integer,
> and/or after making functions like range into reified generics, the
> boxing will go away even more directly and simply.
> So, from the JIT engineering point of view, I would classify this
> particular boxing problem as relatively short-lived.
> — John

What I have observed (some time ago) is that Integer instances obtained 
by Integer.valueOf() are never found to "not escape" the JIT compilation 
unit and are therefore never scalarized by JIT because of the "feature" 
that was designed to actually prevent the continuous allocation of some 
"values" of Integer(s) - namely the caching of Integer instances in the 
Integer.IntegerCache.cache array for values in range [-128, 127]. So the 
feature designed to prevent continuous allocation is actually working 
against the desired goal. The code of Integer.valueOf is:

     public static Integer valueOf(int i) {
         if (i >= IntegerCache.low && i <= IntegerCache.high)
             return IntegerCache.cache[i + (-IntegerCache.low)];
         return new Integer(i);
     } JIT would have to create two specializations of code: one for 
cached Integer instances which are always real objects and the other for 
scalarized Integer(s) created by constructor. Last time I experimented 
with this was in JDK 8. Is HotSpot in JDK 12+ smarter now and can do 
this? Perhaps the @HotSpotIntrinsicCandidate annotation on this method 
is a clue that it is treated in a special way by the JIT?

Regards, Peter

More information about the core-libs-dev mailing list