When the JIT gets it wrong

Overview

I have often wondered what you would see if the JIT compiled code incorrectly, but it has been a long time since I found an example.

A not so infinite loop

There are many way to write an infinite loop. One confusing way is to write for(int i=0; i <= Integer.MAX_VALUE; i++) This is an infinite loop because i as an int value is always less than or equal to the maximum value, by definition.

The JIT can detect this and take action. However the action taken in Oracle Java 6 update 25 is surprising. It just stops the loop, first at a rather random point and later after one iteration.

public static void main(String[] args) {
    for(int i=0;i<10;i++)
        generate(Integer.MAX_VALUE);
    for(int i=0;i<10;i++)
        generate2(Integer.MAX_VALUE);
    System.out.println("End of Main");
}

// generate primes.
public static void generate(int limit)  {
    int lastPrime = 0;
     for (int i = 3; i <= limit; i += 2)
        if (isPrime(i))
            lastPrime = i;
    System.out.println("1: Stopped generating at lastPrime= "+lastPrime);
}

// smae as generate() but need to be JITed again.
public static void generate2(int limit){
    int lastPrime = 0;
     for (int i = 3; i <= limit; i += 2)
        if (isPrime(i))
            lastPrime = i;
    System.out.println("2: Stopped generating at lastPrime= "+lastPrime);
}

// checking for primes
public static boolean isPrime(int n) {
    double sqrt = Math.sqrt(n);
    for (int i = 2; i <= sqrt; i++)
        if (n % i == 0)
            return false;
    return true;
}
prints
1: Stopped generating at lastPrime= 39367
1: Stopped generating at lastPrime= 55291
1: Stopped generating at lastPrime= 3
1: Stopped generating at lastPrime= 3
1: Stopped generating at lastPrime= 3
1: Stopped generating at lastPrime= 3
1: Stopped generating at lastPrime= 3
1: Stopped generating at lastPrime= 3
1: Stopped generating at lastPrime= 3
1: Stopped generating at lastPrime= 3
2: Stopped generating at lastPrime= 49603
2: Stopped generating at lastPrime= 2039
2: Stopped generating at lastPrime= 2039
2: Stopped generating at lastPrime= 3
2: Stopped generating at lastPrime= 3
2: Stopped generating at lastPrime= 3
2: Stopped generating at lastPrime= 3
2: Stopped generating at lastPrime= 3
2: Stopped generating at lastPrime= 3
2: Stopped generating at lastPrime= 3
End of Main

What is happening

What appears to be happening is the JIT does one optimisation which stops the loop early and later stops the loop after one iteration. Note: if I change limit to Integer.MAX_VALUE-1 this doesn't happen. Instead it uses alot of CPU which will probibly produces a large prime as the last results as expected. (if waited long enough)

Workaround

In short, don't write confusing code. This confuses the optimiser and you get less optimal code, and in this case, it appears you get unexpected behaviour. !

Bug Database link

Related Links

Don't Use Java 7? Are you kidding me?

Comments

Popular posts from this blog

Low Latency Microservices, A Retrospective

Unusual Java: StackTrace Extends Throwable

System wide unique nanosecond timestamps