Inside Zero and Shark: Handles and oops, traps and checks

You’re about to run the important enterprise application “Hello World”. What’s going to happen?

class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello world!");
  }
}

After initializing itself, HotSpot will create a new Java thread. This will initially be _thread_in_vm because it’s running VM code. Eventually it will call JavaCalls::call (in javaCalls.cpp) to bridge from VM code to Java code. Before we can look at what JavaCalls::call does, however, we need to understand a couple of HotSpot conventions. Look at its prototype:

void JavaCalls::call(JavaValue* result, methodHandle method, JavaCallArguments* args, TRAPS);

The first things we need to understand are handles and oops. All Java objects, and in fact all objects in HotSpot managed by the garbage collector, are oops, and when you’re dealing with oops you need to keep the garbage collector in mind. More specifically, you need to know where in your code the GC might run, because when it does run you need to have told it the location of every single oop you’re using, and when it returns you need to deal with the fact that your oops have probably moved. If your C compiler has optimized your code such that an oop is in a register then the oop in that register is now wrong, and you’re going to crash pretty soon.

Dealing with raw oops is hard, but luckily there are ways of protecting them. In VM code — when you’re _thread_in_vm — the protection of choice is to use handles. A handle wraps an oop, managing access to it such that GC activity becomes transparent. If you’re in VM code and you’re using handles then you don’t have to worry. But you do need to know what’s happening, because if you see some code that’s calling methodHandle methods and you grep the OpenJDK tree to find the methodHandle class definition you will not find it. The methods you are looking for are actually the methods of the methodOopDesc class (in methodOop.hpp). The handle is just a wrapper.

The other thing we need to understand in that prototype is the mysterious TRAPS at the end. It’s kind of a note to the programmer: functions that trap are functions that can throw Java exceptions. When you call them you use CHECK as their final argument for a convenient exception check:

JavaCalls::call(result, method, args, CHECK);

TRAPS and CHECK are defined in exceptions.hpp. You may wish to avert your eyes:

#define TRAPS   Thread* THREAD
#define CHECK   THREAD); if (HAS_PENDING_EXCEPTION) return; (0

Now we can see how HotSpot handles exceptions: they’re simply stored in the thread. Code that cares can access the exception using these guys:

#define PENDING_EXCEPTION       (((ThreadShadow *) THREAD)->pending_exception())
#define HAS_PENDING_EXCEPTION   (((ThreadShadow *) THREAD)->has_pending_exception())

Next time I really will explain how method invocation works…