6

I've got a simple class for the illustration purposes:

public class Test {

    public int test1() {
        int result = 100;
        result = 200;
        return result;
    }

    public int test2() {
        return 200;
    }
}

The bytecode produced by the compiler (inspected by javap -c Test.class) is the following:

public int test1();
Code:
   0: bipush        100
   2: istore_1
   3: sipush        200
   6: istore_1
   7: iload_1
   8: ireturn

public int test2();
Code:
   0: sipush        200
   3: ireturn

Why is the compiler not optimizing the test1 method to the same bytecode produced for the test2 method? I would expect it to at least avoid redundant initialization of the result variable considering that it is easy to conclude that the value 100 is not used at all.

I observed this with both Eclipse compiler and javac.

javac version: 1.8.0_72, installed as part of JDK together with Java:

Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)
Dragan Bozanovic
  • 23,102
  • 5
  • 43
  • 110
  • 6
    The *Java Language Specification* doesn't require any optimizations like these, so it's not meaningful to talk about "the compiler" as if there were only one. You should indicate what compiler you're using. – ruakh Feb 13 '16 at 19:33
  • 6
    the classic answer is that optimizations are done in the JVM (http://stackoverflow.com/questions/5981460/optimization-by-java-compiler) – wero Feb 13 '16 at 19:54
  • @ruakh Good remark; added compiler information. – Dragan Bozanovic Feb 13 '16 at 20:15
  • I think they *deliberately* keep javac as dumb as possible, even if there are simple optimizations that the compiler guys can easily do. This is to keep pressure on JVM to perform all optimizations, to benefit other compiler guys that are not as good in optimization techniques. – ZhongYu Feb 13 '16 at 20:18
  • The `javac` only optimises constant expressions. If you make the `j` a `final` field it will be optimised as you expect. – Peter Lawrey Feb 13 '16 at 20:42
  • @biziclop and wero, thank you for the useful link. However, the answers provided there do not contain any official documentation about the subject. Basically, all of the answers there imply that more information is available at runtime, so jvm can make better optimizations. That makes a lot of sense of course. However, regardless of the runtime parameters, doing unnecessary work cannot under any circumstances be more optimal than not doing it at all. – Dragan Bozanovic Feb 13 '16 at 20:51
  • I'm voting to reopen this question because I think that the answer should contain the official documentation about the decisions not to make these kinds of optimizations at compile time. – Dragan Bozanovic Feb 13 '16 at 20:51
  • @DraganBozanovic There is no such documentation as far as I know. Compilers are free to make optimisations, they just don't. Other tools however do, [ProGuard](http://proguard.sourceforge.net/manual/optimizations.html) for example can make a raft of transformations on the bytecode, I think `code/removal/advanced` covers your case for example. – biziclop Feb 13 '16 at 21:11
  • 1
    But an authoritative answer would be nice, I'll throw a bounty on the original question and we'll see what comes up. – biziclop Feb 13 '16 at 21:17
  • 1
    @PeterLawrey Although it isn't written down explicitly, constant expressions pretty much have to be optimised by the compiler for the bytecode to obey the JLS while fitting in the class file format. – biziclop Feb 13 '16 at 21:22
  • @biziclop Yes, that makes sense. Thanks! – Dragan Bozanovic Feb 13 '16 at 21:30

2 Answers2

5

JVM optimizes the bytecode, creating something called a code cache. Unlike C++, JVM can collect a lot of data about your program, eg, How hot is that for loop?, Is that code block even worth optimizing?, etc. So optimizing here is very useful, and an often produce better results.

If you optimize when translating from java to bytecode (ie, when you call javac), your code might be optimal for your computer, but not for some different platform. So it makes no sense to optimize here.

As an example, suppose your program uses AES encryption. Modern CPUs have AES-specific instruction sets, with special hardware to make the encryption go a lot faster.

If javac attempts to optimize at compile time, then it will either

  • optimize the instructions at a software level, in which case you program wont benefit from modern CPUs, or,
  • replace your AES instructions with equivalent CPU-AES instructions, supported only on new CPUs, which will reduce your compatibility.

If instead javac leaves them as is in the byptcode, then the JVM running on newer CPUs can recognize them as AES and exploit this CPU capability, while JVMs running on older CPUs can optimize them at a software level at runtime (code cache), giving you both optimality and compatibility.

xyz
  • 3,349
  • 1
  • 23
  • 29
4

A typical Java virtual machine optimizes your program at runtime, not during compilation. At runtime, the JVM knows a lot more about your application, both about the actual behavior of your program and about the actual hardware your program is executed upon.

The byte code is merely a description of how your program is supposed to behave. The runtime is free to apply any optimization to your byte code.

Of course, one can argue that such trivial optimizations could be applied even during compilation but in general it makes sense to not distribute optimizations over several steps. Any optimization is effectively causing a loos of information about the original program and this might make other optimizations impossible. This said, not all "best optimizations" are always obvious. An easy approach to this is to simply drop (almost) all optimizations during compilation and to apply them at runtime instead.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • yes -- at least the information of line number would be lost, so stacktrace won't be accurate; and debugging will be harder. – ZhongYu Feb 13 '16 at 20:42