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);
}
...so 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