Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JVM option to optimize loop statements

I've been told at school that it's a bad practice to modify the index variable of a for loop:

Example :

for(int i = 0 ; i < limit ; i++){
    if(something){
        i+=2;      //bad
    }
    if(something){
        limit+=2;      //bad
    }
}

The argument was that some compiler optimization can optimize the loop and not recalculate the index and bound at each loop.

I 've made some test in java and it seems that by default index and bound are recalculate each time.

I'm wondering if it's possible to activate this kind of feature in the JVM HotSpot?

For example to optimize this kind of loop :

for(int i = 0 ; i < foo.getLength() ; i++){   }

without having to write :

int length = foo.getLength()
for(int i = 0 ; i < length ; i++){   }

It's just an example I'm curious to try and see the improvments.

EDIT

According to Peter Lawrey answer why in this simple example the JVM don't inline getLength() method? :

public static void main(String[] args) {
   Too t = new Too();
   for(int j=0; j<t.getLength();j++){
   }
}


class Too {

    int l = 10;
    public Too() {
    }
    public int getLength(){
        //System.out.println("test");
        return l;
    }
}

In the output "test" is print 10 times.

I think it could be nice to optimize this kind of execution.

EDIT 2 : Seems I made a misunderstood...

I have remove the println and indeed the profiler tell me that the method getLength() is not even call once in this case.

like image 393
alain.janinm Avatar asked Feb 17 '12 23:02

alain.janinm


1 Answers

I've made some test in java and it seems that by default index and bound are recalculate each time.

According to the Java Language Specification, this:

for(int i = 0 ; i < foo.getLength() ; i++){   }

means that getLength() is called on each loop iteration. Java compilers are only allowed to move the getLength() call out of the loop if they can effectively prove that it does not alter the observable behavior.

(For instance, if getLength() just returns the value of some variable, then there is a chance that the JIT compiler can inline the call. If after inlining it can deduce that the variable won't change (under certain assumptions) it can apply a hoisting optimization. On the other hand, if getLength() involves getting the length of a concurrent or synchronized collection, the chances are slim to none that the hoisting optimization will be permitted ... because of potential actions of other threads.)

So that's what a compiler is allowed to do.

I'm wondering if it's possible to activate this kind of feature in the JVM HotSpot?

The simple answer is No.

You seem to be suggesting a compiler switch that tells / allows the compiler to ignore the JLS rules. There is no such switch. Such a switch would be a BAD IDEA. It would be liable to cause correct/valid/working programs to break. Consider this:

class Test {
   int count;

   int test(String[] arg) {
       for (int i = 0; i < getLength(arg); i++) {
           // ...
       }
       return count;
   }

   int getLength(String[] arg) {
       count++;
       return arg.length;
   }
}

If the compiler was permitted to move the getLength(arg) call out of the loop, it would change the number of times that the method was called, and therefore change the value returned by the test method.

Java optimizations that change the behaviour of a properly written Java program are not valid optimizations. (Note that multi-threading tends to muddy the waters. The JLS, and specifically the memory model rules, permit a compiler to perform optimizations that could result in different threads seeing inconsistent versions of the application's state ... if they don't synchronize properly, resulting in behaviour that is incorrect from the developer's perspective. But the real problem is with the application, not the compiler.)


By the way, a more convincing reason that you shouldn't change the loop variable in the loop body is that it makes your code harder to understand.

like image 73
Stephen C Avatar answered Oct 11 '22 09:10

Stephen C