C1/C2 signature classes loading oddity

XMLWordPrintable

    • Type: Enhancement
    • Resolution: Unresolved
    • Priority: P4
    • tbd
    • Affects Version/s: 27
    • Component/s: hotspot

      (Derived from a question [~godin] asked me offline)

      Consider a following benchmark:

      @State(Scope.Thread)
      @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
      @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
      @Fork(1)
      @BenchmarkMode(Mode.AverageTime)
      @OutputTimeUnit(TimeUnit.NANOSECONDS)
      public class UnloadedSigCompile {
          public static class MyClassA {
          }

          public Object returnObject() {
              return null;
          }

          public MyClassA returnA() {
              return null;
          }

          @Benchmark
          public Object test_returnA() {
              return returnA();
          }

          @Benchmark
          public Object test_returnObject() {
              return returnObject();
          }
      }


      The performance of these two methods is considerably different:

      ```
      Benchmark Mode Cnt Score Error Units
      UnloadedSigCompile.test_returnA avgt 5 2.387 ± 0.057 ns/op
      UnloadedSigCompile.test_returnObject avgt 5 0.595 ± 0.005 ns/op
      ```

      Apparently, this comes down to inlining. `test_returnObject()` inlines fully. But for the other case, +PrintInlining says that `test_returnA()` does not inline `returnA()` because of the unloaded class signatures. That unloaded class is `MyClassA`. The performance is back if we do:

      ```
      static {
        MyClassA.class.getName();
      }
      ```

      Now, a very curious result is that supplying `-XX:-TieredCompilation` levels the performance out as well!

      ```
      Benchmark Mode Cnt Score Error Units
      UnloadedSigCompile.test_returnA avgt 5 0.596 ± 0.004 ns/op
      UnloadedSigCompile.test_returnObject avgt 5 0.596 ± 0.003 ns/op
      ```

      And here is why:

      ```
      nmethod* CompileBroker::compile_method(...) {
        ...
        // some prerequisites that are compiler specific
        if (comp->is_c2() || comp->is_jvmci()) {
          InternalOOMEMark iom(THREAD);
          method->constants()->resolve_string_constants(CHECK_AND_CLEAR_NONASYNC_NULL);
          // Resolve all classes seen in the signature of the method
          // we are compiling.
          Method::load_signature_classes(method, CHECK_AND_CLEAR_NONASYNC_NULL);
        }
      ```

      That is, if we got a root C2 compile with signature that bears the unloaded signature class, we would end up loading that signature class. Then the second compilation that goes in and attempts to inline that method succeeds. This happens almost always with -XX:-TieredCompilation; and almost never with default tiered policy, as the method gets compiled with C1.

      So there might be an opportunity here: since we apparently are fine with loading signature classes for C2 compiles, can we do the same for C1 compiles? This would level out this particular performance bump. It would still, of course, depend on luck of root-compiling the prospective inlinee method, but I would wager if we wanted to inline a method, it was likely non-cold, and likely compiled by lower tiers already.

      E.g. do something like this:

      ```
      diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
      index 574f4d6543b..d1a252569f8 100644
      --- a/src/hotspot/share/compiler/compileBroker.cpp
      +++ b/src/hotspot/share/compiler/compileBroker.cpp
      @@ -1429,7 +1429,7 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
       
         assert(!HAS_PENDING_EXCEPTION, "No exception should be present");
         // some prerequisites that are compiler specific
      - if (comp->is_c2() || comp->is_jvmci()) {
      + {
           InternalOOMEMark iom(THREAD);
           method->constants()->resolve_string_constants(CHECK_AND_CLEAR_NONASYNC_NULL);
           // Resolve all classes seen in the signature of the method
      ```

            Assignee:
            Aleksey Shipilev
            Reporter:
            Aleksey Shipilev
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: