Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8215634

Static method of uninitialized class is called in violation of JVMS

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P3 P3
    • None
    • 8u192, 11.0.1, 12
    • hotspot
    • None

      Consider the following class demonstrating the classic initialization deadlock. However, HotSpot JVM does not deadlock but rather prints

      Called from main
      Called from Thread-2
      Initialization complete

      --- StaticInit.java ---

      public class StaticInit {

          static void staticTarget() {
              System.out.println("Called from " + Thread.currentThread().getName());
          }

          static {
              Runnable r = new Runnable() {
                  @Override
                  public void run() {
                      staticTarget();
                  }
              };

              r.run();

              Thread thread2 = new Thread(r, "Thread-2");
              thread2.start();
              try { thread2.join(); } catch (Exception ignore) {}

              System.out.println("Initialization complete");
          }

          public static void main(String[] args) {
          }
      }

      ---

      When StaticInit$1 executes invokestatic bytecode, according to JVMS §6.5 "on successful resolution of the method, the class or interface that declared the resolved method is initialized if that class or interface has not already been initialized".

      StaticInit class is obviously not initialized when Thread-2 invokes staticTarget method. According to JVMS §5.5 "if the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this procedure." This means Thread-2 must block, but it does not.

      Other JVMs (e.g. OpenJ9 and JET) expectedly hang on this test. HotSpot also hangs in -Xcomp mode, but not in -Xint or mixed mode.

      --- Evaluation ---

      Upon the first invocation of invokestatic by the main thread interpreter calls InterpreterRuntime::resolve_from_cache, successfully resolves the bytecode and updates corresponding ConstantPoolCacheEntry. The next invocation by the Thread-2 sees the resolved cp_cache entry and thus does not call InterpreterRuntime and skips class initialization procedure.

      A similar bug with getstatic/putstatic was fixed long ago - JDK-4493560. The fix was to put "zero" bytecode in cp_cache entry if the class is not fully initialized, so that the next time InterpreterRuntime is called again. The same fix could be applied when resolving invokestatic.

            Unassigned Unassigned
            apangin Andrei Pangin
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: