Search code examples
javabytecodelanguage-design

Why there are JVM instructions `monitorenter/monitorexit` but no `wait/notifyAll` (they are native calls)?


When we write synchronized(some_object){} we can see two JVM instructions monitorenter/monitorexit issued as the byte code.

When we write synchronized(some_object){some_object.wait()} i would expect to see special JVM instructions like wait, but none -- instead wait/notify are implemented as native C functions.

Why there is such inconsistency (either have them all as JNI or as java byte code)? Was there a particular (historical) reason or it is just a matter of taste?

Context: i am interested in this because having all monitorenter/monitorexit/wait/notify in the bytecode would allow 'JavaByteCode program correctness verifiers that do not handle JNI' to verify concurrent Java programs that do not use JNI. Currently, such hypothetical tool has to workaround wait/notify.


Solution

  • There is no need for a verification program to deal with JNI as the semantics of wait and notify calls are well-specified. That’s not different to dedicated bytecode instructions. The same applies to how the hot spot optimizer deals with a lot of well known method invocations, which may include wait and notify. It does not necessarily generate a costly JNI invocation but rather generate code performing these low-level operations directly. Methods handled this way are called intrinsic methods (see also here or here.

    There are so many, that you couldn’t call it bytecode anymore if you tried to reserve an opcode for each of them. Further, which methods are handled this way, depends on the actual JVM implementation and the hardware architecture on which it runs. It might also change between versions so there is no sense to carve it in stone by defining bytecode instructions for them.

    You wrote “Currently, such hypothetical tool has to workaround wait/notify”. In fact, handling these special methods is not a work-around. It’s what such an audit tool has to do with a lot of methods like these declared in Lock and Condition which have similar threading-related semantics but there are also a lot of other well-known concurrency tools nowadays which have to be handled.

    The exact decision to create monitorenter and monitorexit instructions but make wait and notify methods on Object is historical (it dates back over 20 years ago). Today, the decision might look different if the developers had to make it again. But I guess it would rather go into the direction to make even monitorenter and monitorexit special methods that are invoked under the hood rather than bytecode instructions. First, they are not the only thread synchronization tool anymore. Second, it’s how most of the new feature were added in the recent JVMs, preferably as method, even if it’s expected to be intrinsified by most, if not all, implementations.