Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why doesn't the java compiler rewrite this code?

I'm testing with this code:

public class TestNull {
   public void leftComparison(String s) {
       if (s == null);
   }
   public void rightComparison(String s) {
       if (null == s);
   }
}

I compiled it with javac 1.8.0_05, and then inspected the bytecode:

public class TestNull {
  ....
  public void leftComparison(java.lang.String);
    Code:
       0: aload_1       
       1: ifnonnull     4
       4: return        

  public void rightComparison(java.lang.String);
     Code:
       0: aconst_null   
       1: aload_1       
       2: if_acmpne     5
       5: return        
}

Apparently, leftComparison is compiled to push and pop 1 variable on the stack while rightComparison pushes and pops 2. I speculate that leftComparison is therefore slightly more efficient than rightComparison?

I'm wondering why the compiler doesn't rewrite the code of rightComparison? In my opinion, the two comparisons should be semantically equivalent, right?

like image 966
James Avatar asked Jul 23 '14 02:07

James


2 Answers

The Java bytecode compiler does very little in the way of optimization. The serious optimization work is almost all done by the JIT compiler.

I'm wondering why the compiler doesn't rewrite the code of rightComparison?

Because there's no point in rewriting it. The JIT compiler should be able to deal with both of them, and most likely generates optimal (native) code for both versions. (You can check this if you are interested. There are ways to see the native code generated by the JIT compiler.)

(Also see @codenheim's answer for a more technical explanation.)

In my opinion, the two comparisons should be semantically equivalent, right?

That is correct ... but it doesn't mean that the bytecode compiler is obligated to generate the same bytecode sequences for both versions.


The real lesson here is that the bytecode sequences generated by the bytecode compiler tell you very little about how your code is actually going to perform. Any performance conclusions that you might draw from reading the bytecodes are highly suspect.

like image 74
Stephen C Avatar answered Oct 23 '22 12:10

Stephen C


In practice, bytecode amounts to Intermediate Code. There is low ROI for optimizing too early or optimizing twice.

  1. It introduces needless layers of maintenance overhead.
  2. Optimization is best done when we know the target platform. The Java stack based instruction set doesn't lend itself to advanced optimization anyway. It is too simplistic (by design). There is only so much "optimization" we can accomplish by shuffling a few stack-based opcodes around. While it is feasible to do a lot of high-level "no brainer" optimizations in javac, I think pragmatism has won here, and we punt it to the JIT which can make use of a far richer native intruction set and techniques (which vary by platform) that just aren't available in bytecode.
like image 36
codenheim Avatar answered Oct 23 '22 11:10

codenheim