javac code elimination capabilities
Asked Answered
C

4

7

I'm having a hard time finding information about javac's code elimination capabilities:

I read that if you have something like the following, the if-statement will be eliminated:

static final boolean DEBUG = false;

if (DEBUG) System.out.println("Hello World!"); // will be removed

But how about this, for example:

static final int VALUE = 3;

if (VALUE > 9) System.out.println("VALUE > 9 ???"); // will this be removed?

Or this:

static final SomeEnum VALUE = SomeEnum.FOO;

if (VALUE==SomeEnum.BAR) System.out.println("Bar???"); // will this be removed?

Since it's very difficult/impossible to analyze a program to find all dead code (probably similar to the halting problem), I would imagine that there are only a few well-defined constructs (like the first example above), which javac will recognize and remove reliably. Is there a comprehensive list of these constructs?

Chitin answered 31/7, 2013 at 8:42 Comment(3)
Well have you tried it to see? javap -c will make it pretty clear...Gumboil
@JonSkeet I haven't yet, since I was hoping to find a list of these constructs, so I don't have to try them out one by one. Also, I'd probably not be able to come up with all possibilities... But, for the two examples shown above, of course, you are right, I could check...Chitin
For the record, the first two are eliminated the third one isn't.Hagen
C
8

assylias seems to have found the answer (let me just put it all together):

Chapter "14.21. Unreachable Statements" of the JLS specifies, that, in general, any unreachable statement in the code is considered a compile-time-error, with the only exception being a special treatment of if-statements to specifically allow for conditional compiles.

Therefore, the only construct that may result in code elimination (if the compiler chooses to do so!) is:

if (compileTimeConstantExpression) {
    doThis(); // may be removed if compileTimeConstantExpression == false;
} else {
    doThat(); // may be removed if compileTimeConstantExpression == true;
}

(the else-part is optional, of course)

All other constructs that would allow for code elimination, like for example while (false) ..., are disallowed and cause a compile-time-error instead rather than resulting in conditional compilation.

The definition for what constitutes an acceptable compileTimeConstantExpression can be found in chapter "15.28. Constant Expressions" of the JLS. Another great page with further examples can be found here: Compile Time Constants in Java

Note: There is no requirement for a compiler to remove the "unreachable" sections of an if-stament. javac seems to do this reliably, but other compilers may not. The only way to know for sure is to check the output via decompilation, for example using javap -c as suggested by Jon Skeet.

Chitin answered 31/7, 2013 at 9:42 Comment(0)
H
5

I have run a few tests and it seems (logically) that javac removes the code iif (if and only if) the condition is a constant expression that evaluates to false.

In summary, constant expressions are expressions that only use constants as operands, i.e. primitives, string literals and final primitives or Strings variables that have been initialised with a constant value.

Note that this is compiler dependent as the JLS does not force the compiler to be that smart as explained at the very bottom of 14.21:

An optimizing compiler may realize that the statement x=3; will never be executed and may choose to omit the code for that statement from the generated class file.

Hagen answered 31/7, 2013 at 8:50 Comment(4)
That sounds like it would make a lot of sense... Do you know if this is actually specified in the docs somewhere? +1Chitin
I've put together an answer building on the links and info you provided. I believe it's more complete/clear this way. But I still think you deserve the credit for providing the relevant building blocks initially. So, I was wondering if you'd like to update your answer one more time (feel free to copy parts from mine), so I can accept yours instead and remove mine. :)Chitin
@MarkusA. No probs - I think yours is better indeed and you should accept it.Hagen
That'll work... Will do as soon as I'm allowed to! Thanks for your help!Chitin
G
0

I see that for 2nd example it gets removed too

this was my class

public class Test {

    public static void main(String[] args) throws Exception{
        final int VALUE = 3;
        if (VALUE > 9) System.out.println("VALUE > 9 ???");
    }
}

and this is decompiled version

Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

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

}
Glycogen answered 31/7, 2013 at 8:49 Comment(0)
M
0

My guess would be that this is implementation specific (Oracle, IBM,...).

If you're interested in Oracle's version, a good place to start looking for resources would be the OpenJDK project: http://openjdk.java.net/groups/compiler/

Melamie answered 31/7, 2013 at 8:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.