Question

First code:

public static int pitagoras(int a, int b)
{
    return (int) Math.sqrt(a*a + b*b);
}

public static int distance(int x, int y, int x2, int y2)
{
    return pitagoras(x - x2, y - y2);
}

distance is called very often. When I compiled it with javac and then decompiled with javap -c I got this bytecode:

public static int pitagoras(int, int);
  Code:
   0:   iload_0
   1:   iload_0
   2:   imul
   3:   iload_1
   4:   iload_1
   5:   imul
   6:   iadd
   7:   i2d
   8:   invokestatic    #24; //Method java/lang/Math.sqrt:(D)D
   11:  d2i
   12:  ireturn

public static int distance(int, int, int, int);
  Code:
   0:   iload_0
   1:   iload_2
   2:   isub
   3:   iload_1
   4:   iload_3
   5:   isub
   6:   invokestatic    #34; //Method pitagoras:(II)I
   9:   ireturn

It seems that javac hasn't optimized second function, distance.

Second code, I think, faster:

public static int distance(int x, int y, int x2, int y2)
{
    return (int) Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
}

And its bytecode:

public static int distance(int, int, int, int);
  Code:
   0:   iload_0
   1:   iload_2
   2:   isub
   3:   iload_0
   4:   iload_2
   5:   isub
   6:   imul
   7:   iload_1
   8:   iload_3
   9:   isub
   10:  iload_1
   11:  iload_3
   12:  isub
   13:  imul
   14:  iadd
   15:  i2d
   16:  invokestatic    #24; //Method java/lang/Math.sqrt:(D)D
   19:  d2i
   20:  ireturn

Is invokestatic so fast that it's the same as inlining static function? Why javac did not optimize this? Or maybe it is in fact optimized and these two codes will give the same, but I'm missing something?

Was it helpful?

Solution

javac doesn't optimise. That's the job of the JVM implementation (typically HotSpot).

There used to be a few optimisations in javac but they complicated the code and allegedly tended to arrange the code so that HotSpot optimisations were inhibited.

HotSpot optimisations are generally done dynamically after thousands of iterations (configurable, default dependent upon whether using "Client", "Server" or tiered versions).

There are some things that javac is required to do by the language specification, such as inlining constants and combining literal strings.

OTHER TIPS

The Java language does not define inlined functions. Many (perhaps most) Just-In-Time (JIT) compilers will dynamically (at run time) replace such static function calls with inlined code.

I believe that performance of both version will be similar because JVM uses JIT to increase the performance.

The kind of optimization you're looking for (inlining) doesn't necessarily occur at compile time, but it's quite possible that the Just in Time (JIT) compiler will perform it during runtime.

So it's unlikely that you'll be able to see the inlining happen at the byte code level, more likely, it'll occur at the native code level during program execution.

The given answers are right : javac does not inline methods as it may not be the best thing to do.

Suppose that the distance() method is called once in a while but not very often. Optimizing it by inlining pitagoras() and stuff would slow down compilation for something that is barely used.

On the other hand, Hotspot knows when a method is called and how many times it is called. If the method is executed often, then Hotspot may inline it and compile it to native code, but only if it improves performances. Remember that Hotspot is the only component that knows if an optimization is a good thing or not.

Also, note that javac may do one optimization : it eliminates dead code. Consider this class :

public class Test {
public final static boolean ENABLED=false;

public static void main(String... args) { 
  if(ENABLED)
    System.out.println("Hello World");
  }
}

The compiled bytecode for the main method is this :

public static void main(java.lang.String[]);
  Code:
   0:   return

=> javac detected that the println line could not be reached and removed it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top