JavaMemoryModel: Bypassing class initialization checks with quick opcodes

From: Bill Pugh (pugh@cs.umd.edu)
Date: Wed Jul 14 1999 - 17:55:18 EDT


As I mentioned in a previous message, the JVM specification
requires that the VM check to see if a class is initialized
before invoking a NEW, GETSTATIC, PUTSTATIC or INVOKESTATIC.

However, if you use the quick opcodes (described in JVMS
version 1.0 and in Sun's implementation), all of those opcodes
have a quick variant. The quick variant doesn't check to
see if the class is initialized. So you could have:

processor 1:

executes opcodes for new Bar()
  Invokes NEW Bar
    - checks to see if Bar is initialized; it isn't
    - initializes Bar
    - replaces NEW Bar with NEW_QUICK Bar
    - allocates obj of type Bar
  Invokes constructor

processor 2:

executes opcodes for new Bar()
  sees the NEW_QUICK opcode, invokes NEW_QUICK Bar
    - doesn't bother to check to see if Bar is initialized
    - allocates obj of type Bar
  Invokes constructor

This allows processor 2 to allocate and construct
an object of type Bar without doing a memory barrier.

Note that is this case, the user's code doesn't have a data
race; it is just the JVM that has a data race.

Of course, on relaxed memory machines, we are probably already
up the creek 5 different ways, but why not add a 6th?

What happens in native code? Is there always a check to see if a class
is initialized before the native code for a NEW, GETSTATIC, PUTSTATIC
or INVOKESTATIC? I could easily imagine that in an instance method
for class Bar, a compiler would omit checks to see if Bar was initialized.
But as shown here, that would allow a processor to invoke a static
method for that class without doing a memory barrier.

You wouldn't want to do a check with a memory barrier before each static call.
One think people might try is to put in a check before
the call, and then overwrite the check (e.g., turn it into
a no-op) after executing it. But that doesn't work, because each processor
has to hit the memory barrier. Just because one processor doesn't need it any
more doesn't mean that others don't.

One possibility would be to have the garbage collector remove the checks
once the class has been initialized.

By the way, no one should imagine that I am suggesting that these are
actually good solutions that I think people should implement. I hope we
will convince the architects to avoid imposing such pain on us. But
I'd trying to work out all the pain we will have to endure if they
don't.

Bill
-------------------------------
This is the JavaMemoryModel mailing list, managed by Majordomo 1.94.4.

To send a message to the list, email JavaMemoryModel@cs.umd.edu
To send a request to the list, email majordomo@cs.umd.edu and put
your request in the body of the message (use the request "help" for help).
For more information, visit http://www.cs.umd.edu/~pugh/java/memoryModel



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:16 EDT