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

Optimize JVM_GetDeclaringClass

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P4 P4
    • 16
    • 16
    • hotspot
    • b08

      On 10/06/2020 3:52 am, Christoph Dreis wrote:

      I've just stumbled upon JVM_GetDeclaringClass that I think could be optimized.
      The basic idea of the attached patch is to avoid repeated calls to JNIHandles::resolve_non_null & java_lang_Class::as_Klass.

      With the following benchmark:

      @BenchmarkMode(Mode.AverageTime)
      @OutputTimeUnit(TimeUnit.NANOSECONDS)
      public class MyBenchmark {

          @State(Scope.Benchmark)
          public static class ThreadState {
              private Class<?> clazz = ThreadState.class;
          }

          @Benchmark
          public Class<?> testClass(ThreadState threadState) {
              return threadState.clazz.getDeclaringClass();
          }

      }

      I see the following results:

      BEFORE
      Benchmark Mode Cnt Score Error Units
      MyBenchmark.testClass avgt 10 119,462 ± 3,914 ns/op
                                                                    
      PATCHED
      Benchmark Mode Cnt Score Error Units
      MyBenchmark.testClass avgt 10 102,457 ± 4,746 ns/op

      In case you think this is worthwhile, I would appreciate if someone can sponsor the patch.

      Let me know what you think & if I'm missing something (my C++ is a bit rusted).
      (Because there seem to be similar optimizations possible throughout jvm.cpp.)

      Cheers,
      Christoph


      ===== PATCH =====

      --- a/src/hotspot/share/prims/jvm.cpp Sat Jun 06 08:13:40 2020 +0000
      +++ b/src/hotspot/share/prims/jvm.cpp Tue Jun 09 19:41:02 2020 +0200
      @@ -1560,15 +1560,17 @@
       JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass))
       {
         // ofClass is a reference to a java_lang_Class object.
      - if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) ||
      - ! java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->is_instance_klass()) {
      + oop mirror = JNIHandles::resolve_non_null(ofClass);
      + if (java_lang_Class::is_primitive(mirror)) {
      + return NULL;
      + }
      + Klass* k = java_lang_Class::as_Klass(mirror);
      + if (!k->is_instance_klass()) {
           return NULL;
         }

         bool inner_is_member = false;
      - Klass* outer_klass
      - = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))
      - )->compute_enclosing_class(&inner_is_member, CHECK_NULL);
      + Klass* outer_klass = InstanceKlass::cast(k)->compute_enclosing_class(&inner_is_member, CHECK_NULL);
         if (outer_klass == NULL) return NULL; // already a top-level class
         if (!inner_is_member) return NULL; // a hidden or unsafe anonymous class (inside a method)
         return (jclass) JNIHandles::make_local(env, outer_klass->java_mirror());

            dholmes David Holmes
            dholmes David Holmes
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: