javafor-loopoptimization

Automatic compiler optimizations in Java control structures?


I have a quick question about how "smart" the Java compiler provided in Sun's JDK is. Specifically, is it smart enough to evaluate any functions appearing in the conditional part of a for() loop ahead of time instead of evaluating them at every iteration of the loop?

For instance, consider the following code.

// Array of doubles to "hold" the array.
private double matrix[][];

public int getCols() {
    // Compute the number of columns in a matrix.
}

public int getRows() { 
    // Compute the number of rows in a matrix.
}

// Compute the sum of all elements in the matrix.
public double sum() {

    double result = 0;

    for (int r = 0; r < getRows(); r++) {
        for (int c = 0; c < getCols(); c++) {
            result += this.matrix[r][c];
        }
    }

    return result;
}

Clearly, I could modify the sum() method to ensure that getRows() and getCols() aren't evaluated at each iteration of the loop by changing it to

public double sum() {

    double result = 0;
    int numRows = getRows();
    int numCols = getCols();

    for (int r = 0; r < numRows; r++) {
        for (int c = 0; c < numCols; c++) {
            result += this.matrix[r][c];
        }
    }
    
    return result;
}

I wonder, however, if the compiler is smart enough to pre-evaluate these itself. That is, will it automatically spot that it's computationally cheaper to evaluate any functions that appear in conditionals ahead of time rather than evaluate them at each iteration?


Solution

  • Generally, such an optimization would be wrong. The methods are virtual, so they may be changed in a subclass to do something entirely different (such as returning random numbers) and it may be hard to impossible to statically prove (yes, it needs to be a proof) that they return the same value on every iteration even if they were final. In fact, maybe they don't do that at all (think another thread changing the number of rows/columns in parallel - yeah, you got an whole lot of other problems in that case, but it still needs to be considered).

    And apart from that, the compiler doesn't need to optimize anything: At runtime, the JIT-compiler can optimize much more. For instance, it can generate code with the virtual calls inlines and it may (depending on the code) be able to factor out the wrong (at least if they unconditionally return a constant). If can't, however, change semantics, so again, it won't do this. If it's really important, do it yourself. Either way, check if it's a bottleneck at all.