Conditional JIT-compilation - java

In Java we can do conditional compilation like so
private static final boolean DO_CHECK = false;
...
if (DO_CHECK) {
// code here
}
The compiler will see that DO_CHECK is always false and remove the entire if-statement. However, sometimes, especially in library code, we can't use conditional compilation, but I'm wondering, can we use conditional JIT-compilation?
private final boolean doCheck;
public LibraryClass(boolean d) {
doCheck = d;
}
public void oftenCalledMethod() {
if (doCheck) {
...
}
}
If we construct LibraryClass with doCheck = false, will the JIT-compiler (in Hotspot) remove the if-statement as well?
Update: I just realised that JIT-compilation is most probably not done on instance level, so I think this wouldn't work, but maybe there's a static way?

JIT stands for "just in time". That means stuff is compiled just before the VM thinks it needs it. So depending on the level of atomicity of checking you might find the code that never gets run never gets JIT compiled anyway.

Related

Why Java couldn't figure out some obvious illegal casts when type parameters are involved?

Consider the following example:
public class Example {
public static <T> void f(T obj) {
Integer i = (Integer) obj; // runtime error
}
public static void main(String[] args) {
f("hello");
}
}
Is there any reason why Java cannot figure out that cast in line 3 is illegal in compile time? Surely, because of the type erasure, the signature of the function in runtime will be f(Object obj), but it seems to me that in the compile-time it's enough information to catch the error.
Compare this with the case:
List<String> ls = new ArrayList<>();
ls.add(42); // compile-time error
ls.add("foo");
Integer i = ls.get(0); // compile-time error
where a type parameter is involved but the error succesfully detected in the compile-time.
If the answer is "the compiler is just not smart enough", then is there any reason (for backward compatibility?) why it can't be made smarter?
Explanation
Java, based on its current rule set (see the JLS) has to treat the method content and its call-site separately.
Method content
The cast
(Integer) obj
has to be allowed at compile-time since T could be an Integer. After all, a call like
f(4)
should succeed and be allowed.
Java is not allowed to take in the call-site of the method into consideration. Also, this would imply that Java would have to scan all call-sites but this is impossible since that would also include possible future call-sites that have not been written yet or are included later on, in case you are writing a library.
Call-site
The call-site also has to be legal since Java is not allowed to take the method-content into consideration.
The signature demands T (extends Object) and String fullfills that. So it is allowed to be called like that.
If Java would also check the content, imagine you would hide the cast 3 levels depper in some other method calls. Then Java not only has to check fs code but also the code of those methods and possibly all their if statements to check if the line with the bad cast is even reached.
It is NP-hard to prove that with 100% certanity at compile-time, hence it is also not part of the rule set.
Why?
While we saw that such situations are not always easy to detect and that actually proving it for all possible situations might even be impossible (NP-hard), Java designers could certainly have added some weaker rules that cover the dangerous situations partially.
Also, there are actually some similar situations in which Java will help you out with weaker rules. For example a cast like
House a = new House();
Dog b = (Dog) a;
is forbidden because Java can prove easily that the types are completely unrelated. But as soon as the setup becomes more complex, with types coming from other methods, generics, Java can not easily check it anymore.
All in all, you will have to ask a Java Language Designer for the precise reasons in the decision making. It is what it is.
Static code analysis
What you have here is typically the job of a static code analyzer (like most IDEs already include). They will actually scan through your code, all usages and so on and try to figure out if your current code flow has possible issues.
It is important to note that this also includes a lot of false-positives, as we just learned that not all of such usages might actually be wrong, some dangerous setups might be intended.
Appendix: Comments
Based on the discussion in the comments, let me stress out the fact that your particular example is indeed simple to prove to be wrong. So the call-site could easily be forbidden in this particular case (any static code analyzer will happilly throw a warning at you for this code).
However, we can do very simple modifications to the code already that demonstrates why it is so difficult to actually prove errors when connecting the call-site with the content of the method.
So the tldr is that almost all real code situations require much more efforts for a tool to prove with 100% that the call is incorrect. Also, it is much more difficult to program this and it can not always be ensured that there are no false-positives. Which is why such stuff is typically not done by a compiler but rather by static code analyzers.
The two common examples for this are method nesting and code branching.
Nesting
Imagine you hide the cast (Integer) obj a level depper, in another method:
public static void main(String[] args) {
f("hello");
}
public static <T> void f(T obj) {
g(obj);
}
public static <T> void g(T obj) {
Integer i = (Integer) obj;
}
In order to prove this, Java would now have to connect the call-site from main to the content in f, to the call-site in g. If you add more levels of nesting this quickly gets out of control and needs a recursive deep analysis before anything can be proven.
Branching
Another very common but difficult situation for the compiler is if you hide the bad cast in a branched code flow:
public static void main(String[] args) {
f("hello");
}
public static <T> void f(T obj) {
if (isMonday()) {
Integer a = (Integer) obj;
} else {
String b = (String) obj;
}
}
Now, Java would need knowledge about what isMonday() returns at compile-time, which is simply impossible.
But if Java flags this, it would be bad. Because, what if we ensure externally that we only launch the program mondays? It should work then.

Static function returns wrong value?

I have a small class which contains a static final variable and a static function:
public class GlobalConstants {
public static final boolean ONLINE = true;
public static boolean isOnline(){
return ONLINE;
}
}
(of course there is a bit of code duplication, but please ignore that)
I package my program in a runnable jar and get weird result:
log.debug(GlobalConstants.isOnline()); //prints false
log.debug(GlobalConstants.ONLINE); //prints true
I would expect that they both print "true".
Is the java compiler doing a optimization that causes this strange behavior, or am i missing something?
Have a look at this project I set up with your code. It works just as expected, your error must lie in some parts of the code you removed to simplify your code example.
And always consider that your static code must be executed. If you call the code above from a static context, some circular dependencies may result in some static variables not being initialized before being called
Cheers for the help guys! Found the problem, it appeared that my local maven repository had a lost copy of the library holding the GlobalConstants class. This class was included as dependency in the runnable jar. But that doesn't explain the "false, true" output, unless GlobalConstants.ONLINE is converted to a boolean value by a optimization by the java compiler (because it is a final). It still confuses me a bit.
[update]
I decompiled my class and indeed:
System.out.println(GlobalConstants.ONLINE);
System.out.println(GlobalConstants.isOnline());
is converted by java compiler in:
System.out.println(true);
System.out.println(GlobalConstants.isOnline());
Now it is all clear and this explains the result in my original post. Because even when it was using a wrong class version it should have produced the same result (true, true). But because java compiler does magic it is possible that it returned true, false.

can JIT optimize such unnecessary call?

I have question about JIT optimization.
I compiled a simple piece of code:
class btest
{
static final boolean flag=false;
public final void foo(int x)
{
if(flag) {a=x; b=x*2; c=x*3;}
}
public void bar(int y) {foo(y);}
int a,b,c;
};
flag is set to false so foo() is perfectly compiled to empty code - just returns.
But bar() still calls it.
Is it possible that JIT will eliminate this call?
Does it matter if flag belongs to external class?
regards
It can eliminate it and inline it in code.
Note: It can also do this for non-volatile non-final variables where it thinks the thread doesn't change the value. A common mistake is something like
boolean running = true;
public void run() {
while(running) {
// do something
}
}
public void stop() {
running = false;
}
A common misconception is that the thread might keep running for an while but stop at some unknown point, when actually the JIT might inline running and never stop.
The JIT compiler would most likely be able to eliminate this.
But actually, I think that the if statement is likely to be optimized away before then. The reason is in JLS 14.21 starting at the point where is says this:
"However, in order to allow the if statement to be used conveniently for "conditional compilation" purposes, the actual rules differ."
If goes on to say that that the compiler (that is the bytecode compiler!) may generate different code in your example depending on the known value of the condition at compile time.
Note that this special treatment only applies to if statements, and only if the condition is a constant expression. (That term has a very specific meaning - see JLS 15.28) If you tried the same "trick" with a while loop for example, you would get a compilation error complaining about unreachable code.
(This "conditional compilation" special treatment goes back to the early days of Java, and is part of the rationale for Gosling et al's decision to not include a preprocessor in the Java language.)

Java: What is considered more readable, "this" or no "this"

You don't really need to write the "this" keyword in Java. But is it better to do so anyway? Does it make sense to homogenise your style, i.e. if you use "this" once, you use it every time it's implied? Or is there a place where you would always use it and others where you never use it?
The general consensus is that you should use this only when it is necessary and not at any other time.
private String param;
public Construct(String param) {
// Usually the only place you need to use this.
this.param = param;
}
// A less common use of this
public Function() {
synchronized(this) {
// Some synchronized stuff.
}
}
As a rule I tend not to use it - if you can reduce redundant code then all the better.
There are however three places that I can think of where the this keyword cant be avoided:
Constructors (delegating to another constructor in the same class)
public MyClass() {
this("Default Parameter");
Synchronizing on the current object
synchronized(this) {
Passing the current object to another class
public void methodOne() {
anotherClass.doSomething(this);
You sometimes need it in constructors where the field name is the same as the parameter, but this isnt really mandatory as you could simply rename the paramter:
public MyClass(String data) {
this.data = data
Other than these I cant think of too many other scenarios where I'd use the this keyword. I have seen it overused (on every method and field reference) and this can make the code very hard to read.
Use it only when you have to, or when you believe that it enhances code readability.
As a general rule you should avoid redundant syntax wherever it may arise. You will read lots of opinion to the contrary, mostly referring to a thoroughly mythical programmer who doesn't know about member variables, doesn't know what parentheses are for, and doesn't remember the rules of operator precedence he was taught in third grade. I've never met him in 40 years. That isn't enough to justify disfiguring your code for him on the assumption that he will (a) not understand it and (b) therefore break it. I've never seen that happen at all.
What I have seen is code produced by such a person. That's not a reason to dumb down your own code for him. The occasions on which someone has actually gone as far as to incorrectly rewrite a piece of code of mine are exactly two: once in 1979, where someone refactored a grammar to remove the operator precedence, which was dumb, and he shouldn't have done it, and another time in about 1992, but in both cases there is no way I could have written the grammar or the code that would have prevented it.
There are some places in code, where you couldn't skip this keyword, e.g. setters:
public void setValue(String value) {
this.value = value;
}
But if its possible it's better to skip:
public String getValue() {
return value;
}

What is alone { code } in Java for?

I recently read some code that uses a special syntax regarding {}, I've asked a more experienced Java developer, but he also can't answer.
public void doSomething() {
someWorks();
{
someVariables;
someMoreWorks();
}
someEvenWorks();
{
...
}
}
Why does the code author put these lines inside {}? I guess that the variables declared within the {} will be released right after execution exits {}, right, because I can't access these outside the {} anymore?
Yes, the only difference is for scoping.
Occasionally this can be useful for throwaway code such as micro-benchmarks where you want to be able to cut and paste a block and make a minor change, then potentially reorder the blocks.
I would rarely (if ever) have something like this in "real" code though.
This gives him a nested scope to declare "more local" variables.
I guess that the variables declared within the {} will be released right after exit {}, right, because I can't access these outside the {} anymore?
Depends on your definition of "release" (they will most likely not be garbage collected until the method ends, so if this is important, you might want to null them out), but yes.
Other rarely seen uses of curly brackets include class and instance initializers:
class A {
static {
// some class initialization code
}
{
// some instance initialization code
}
}
The fact that the author put those variables in {} indicates the scope of those variables will only be that of the method defined by the {}; in turn, those variables will be up for garbage collection once method finishes execution.

Categories