programming diary

Tuesday, 30 October 2012

Java Server VM JIT compiler may create infinite loop.

I have some books on my backlog that I should have read a long time a go. One of them is Java Concurrency in Practice by Brian Goetz [1]. There's an interesting bit about volatile keyword, which I'm going to write about in this post.

JDK comes with server and client VM. Both have different JIT compilers, which perform different optimizations. Let's consider a code sample from [1] book listing 3.4.

boolean asleep;
 ...
  while (!asleep) 
   countSomeSheep();

Asleep is a flag that will never be modified inside of the while loop, but might be modified outside of the loop by a different thread. When starting java with JVM command line parameter -server, server JIT compiler might notice that above code will never modify asleep flag inside of the loop body. Thus it might optimize that code by taking condition test outside of the loop, turning it into infinite loop, equivalent to:

boolean asleep;
 ...
  conditionTest = !asleep
  while (conditionTest) 
   countSomeSheep();

I wrote that it might optimize, and not will, because there really is no guarantee when it comes to JIT compiler. And who knows if this optimization is or will be present in all versions of VM? If anyone can correct me on this, please post a comment.

Below is complete code sample that shows described optimization problem. I've ran it on 32 bit JRE (build 1.6.0_26-b03) with client and server VM (build 20.1-b02).

public class UnsafeFlag {
 
 // Add volatile to avoid server VM JIT compiler optimization, 
 // ie. private volatile boolean flag;
 private boolean flag;

 public void foo() {
  // When flag is not volatile and -server VM is used, JIT compiler might
  // take loop condition test outside of the loop (because flag is never 
  // modified inside of the loop body), turning it into infinite loop. 
  while (!flag) { 
   // fooing   
  }  
 }
 
 public static void main(String[] args) {
  final UnsafeFlag unsafeFlag = new UnsafeFlag();
    
  final Thread flagChanger = new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    unsafeFlag.flag = true;   
   }   
  });
  
  flagChanger.start();   
  unsafeFlag.foo();  
 }
 
}

When above code is run with -server VM parameter, while loop is infinite on my computer. Below are (most just for the sake of experimentation and fun) ways to avoid infinite loop:

  • Use server vm but disable JIT compiler: -server -Djava.compiler=none
  • Use client vm: -client
  • Add volatile to flag: private volatile boolean flag
  • Use Actor model. Instead of changing value of the flag directly from the outside, send STOP message to the actor. Actor will then change the flag on the inside of the loop, causing loop to terminate [3] [4].

Of course a flag use like shown above is not a common sight ;), but important conclusion is that when developing we should always take into consideration on what VM our code will run in production.  For example, one might be developing server-side code, which will run on server VM. In this case, tests should also be run with java -server VM parameter.

Appendix
To print JIT statistics use "-XX:+PrintCompilation -XX:-CITime" parameters. If nothing is printed, change -XX:CompileThreshold parameter. [2]

For example try running example code without volatile keyword with parameters:
"-server -XX:+PrintCompilation -XX:-CITime -Djava.compiler=none"
and then with parameters:
"-server -XX:+PrintCompilation -XX:-CITime"
First test will print no statistics for FlagChanger#foo method, because JIT compiler is disabled by Djava.compiler=none parameter. Second test will print statistics if boolean IS NOT volatile and XX:CompileThreshold parameter is satisfied. 

Reference
[1] Brian Goetz. et al. Java Concurrency in Practice. Addison-Wesley, 2006.
[2] http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
[3] Solution suggested by Daniel Korzekwa http://www.danmachine.com/
[4] Scala Actors: A Short Tutorial http://www.scala-lang.org/node/242

Sunday, 24 October 2010

GWT 2.0 - JRE Presenter Test: ERROR: GWT.create() is only usable in client code!

I was writing JRE Test for one of my presenter classes. My presenter has display interface, which is implemented by view. As usual, I mocked out display interface in my presenter class.
mockDisplay = createStrictMock(EditInterviewPresenter.Display.class);
Hovewer, when I tried to run the test I received an exception:
java.lang.UnsupportedOperationException: ERROR: GWT.create() is only usable in client code! It cannot be called, for example, from server code. If you are running a unit test, check that your test case extends GWTTestCase and that GWT.create() is not called from within an initializer or constructor.
The source of a problem was method deleteQuestionAnswerPanel from display interface. One of the parameters is PushButton object, which is of type UIObject:
void deleteQuestionAnswerPanel(Long id, PushButton deleteButton);
EasyMock uses reflection mechanism of java, and in the process...
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
... method is called for display interface method parameters. Furthermore, this method is called with initialize parameter set to true, which means that static fields will be initialized. And UIObject class contains one very specific static field that causes an exception:
private static DebugIdImpl debugIdImpl = GWT.create(DebugIdImpl.class);
Solution:

1) Use types like HasText, HasClickHandlers insteed of UIObject types.
2) Before creating mock object, call: GWTMockUtilities.disarm()
Replace the normal GWT.create() behavior with a method that returns null instead of throwing a runtime exception. This is to allow JUnit tests to mock classes that make GWT.create() calls in their static initializers. This is not for use with GWTTestCase, and is not for use testing widgets themselves. Rather, it is to allow pure java unit tests of classes that need to manipulate widgets.