<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p>Hi Ashutosh,</p>
    <p>I disabled the AOTClassInitializer::is_forced_preinit_class()
      call and synced
      AOTClassInitializer::can_archive_preinitialized_mirror() with my
      upstream PR. This seems to fix the error in your test case.</p>
    <p>Could you give it a try?</p>
    <p><a class="moz-txt-link-freetext" href="https://github.com/iklam/jdk/commit/df72d0ba8dc799767521c939a531c4128e58c636">https://github.com/iklam/jdk/commit/df72d0ba8dc799767521c939a531c4128e58c636</a><br>
    </p>
    <p>Thanks</p>
    <p>- Ioi<br>
    </p>
    <p><br>
    </p>
    <p><a class="moz-txt-link-freetext" href="https://github.com/iklam/jdk/commit/df72d0ba8dc799767521c939a531c4128e58c636">https://github.com/iklam/jdk/commit/df72d0ba8dc799767521c939a531c4128e58c636</a><br>
    </p>
    <div class="moz-cite-prefix">On 9/24/24 8:24 AM, Ashutosh Mehra
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CAKt0pyTQXoW82Dx=BRFx93_wm6dEiCcncT66mDOHGXt4GqiE0Q@mail.gmail.com">
      
      <div dir="ltr">Hi Ioi,
        <div>Thanks for sharing the code changes.</div>
        <div>The wildfly-elytron testcase passes with these changes, but
          I still get the NPE in PrimitiveClassDescImpl.<clinit>
          when running with my own testcase.</div>
        <div>I have pushed my test case to a repo [2], so you can try it
          as well. I have added some instructions to the Readme file.</div>
        <div>Let me know if you face any issues in running the test
          case.</div>
        <div><br>
        </div>
        <div>[2] <a href="https://urldefense.com/v3/__https://github.com/ashu-mehra/leyden-testcase/__;!!ACWV5N9M2RV99hQ!JiRlHQ7c-vdXVJoc61a64CilNOg5VTLitO8JELhohSZdibAXZUEjeA38WbtygjLvPsQIQKUYXJ2_kA$" moz-do-not-send="true">https://github.com/ashu-mehra/leyden-testcase/</a></div>
        <div><br>
        </div>
        <div>Thanks,<br>
          <div>
            <div>
              <div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">
                <div dir="ltr">- Ashutosh Mehra</div>
              </div>
            </div>
            <br>
          </div>
        </div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Mon, Sep 23, 2024 at
          11:24 PM <<a href="mailto:ioi.lam@oracle.com" moz-do-not-send="true" class="moz-txt-link-freetext">ioi.lam@oracle.com</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div>
            <p>Hi Ashutosh,</p>
            <p>Thank you again for the summary of the issues.</p>
            I looked at the call paths again and I think two calls need
            to be moved<br>
            <blockquote>
              <p>(1) MethodType::createArchivedObjects() needs to be
                called after we have executed all other Java code. So I
                put it before the
                StringTable::allocate_shared_strings_array() call.</p>
              <p>(2)
                SystemDictionary::get_all_method_handle_intrinsics()
                needs to be done inside the safepoint, so it can be sure
                to find all the method handle intrinsic methods (which
                can be generated as the side effect of Java code
                execution).</p>
            </blockquote>
            <blockquote>
              <p>I also added the archiving of the classData field.</p>
            </blockquote>
            <p>See my temporary change at
              <a href="https://urldefense.com/v3/__https://github.com/iklam/jdk/commit/eafaa9731ae89b93f3e20702fc4d5a12cb070149__;!!ACWV5N9M2RV99hQ!JiRlHQ7c-vdXVJoc61a64CilNOg5VTLitO8JELhohSZdibAXZUEjeA38WbtygjLvPsQIQKXvE8zr1g$" target="_blank" moz-do-not-send="true">https://github.com/iklam/jdk/commit/eafaa9731ae89b93f3e20702fc4d5a12cb070149</a><br>
              <br>
              With this change, I am able to successfully run the test
              in <a href="https://urldefense.com/v3/__https://github.com/tristantarrant/elytron-leyden__;!!ACWV5N9M2RV99hQ!JiRlHQ7c-vdXVJoc61a64CilNOg5VTLitO8JELhohSZdibAXZUEjeA38WbtygjLvPsQIQKW7YFmGjQ$" target="_blank" moz-do-not-send="true">https://github.com/tristantarrant/elytron-leyden</a>
              . I also modified the LambdaWithUseImplMethodHandle.java
              test to add a similar test scenario.</p>
            <p>I agree with you that the code in
              AOTClassInitializer::is_forced_preinit_class() is too
              ad-hoc, and might change the order of class
              initialization. In the upstream PR, I have changed the
              code to only assert that the listed of classes has been
              initialized:</p>
            <p><a href="https://urldefense.com/v3/__https://github.com/iklam/jdk/blob/5cc31ed60cc9597d63b86f20b95c964d4d1a6b84/src/hotspot/share/cds/aotClassInitializer.cpp*L66-L84__;Iw!!ACWV5N9M2RV99hQ!JiRlHQ7c-vdXVJoc61a64CilNOg5VTLitO8JELhohSZdibAXZUEjeA38WbtygjLvPsQIQKUJSR9oEw$" target="_blank" moz-do-not-send="true">https://github.com/iklam/jdk/blob/5cc31ed60cc9597d63b86f20b95c964d4d1a6b84/src/hotspot/share/cds/aotClassInitializer.cpp#L66-L84</a><br>
            </p>
            <p>I will try to merge this version of the code back to the
              Leyden repo.</p>
            <p>I think by doing this, we can avoid direct manipulation
              of the class-init order of the core-library classes.
              Instead, we just make sure that we execute enough "normal"
              code during the assembly phase to ensure that these
              classes are initialized in their normal order.</p>
            <p>What do you think?</p>
            <p>Thanks</p>
            <p>- Ioi<br>
            </p>
            <p><br>
            </p>
            <div>On 9/19/24 8:05 PM, Ashutosh Mehra wrote:<br>
            </div>
            <blockquote type="cite">
              <div dir="ltr">
                <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                  <p>Upon further investigation, it seems a simple patch
                    might fix the problem with classData.<br>
                  </p>
                  <p>I tested with
                    test/hotspot/jtreg/runtime/cds/appcds/LambdaWithUseImplMethodHandle.java
                    by running jtreg with
                    -javaoptions:-XX:+AOTClassLinking<br>
                    Without the patch, I'd get a NullPointerException.
                    With the patch, the test passes.</p>
                  <p>It looks like classData is not treated as a static
                    field of the class, but rather an instance field in
                    the mirror. So classData wasn't copied by the loop
                    in HeapShared::copy_preinitialized_mirror().</p>
                  <p>Ashutosh, could you try it this fixes the crash on
                    your side?<br>
                  </p>
                  <p>Thanks</p>
                  <p>- Ioi<br>
                  </p>
                  <p>diff --git a/src/hotspot/share/cds/heapShared.cpp
                    b/src/hotspot/share/cds/heapShared.cpp<br>
                    index 0e70778f057..62cf142f67a 100644<br>
                    --- a/src/hotspot/share/cds/heapShared.cpp<br>
                    +++ b/src/hotspot/share/cds/heapShared.cpp<br>
                    @@ -634,6 +634,8 @@ void
                    HeapShared::copy_preinitialized_mirror(Klass*
                    orig_k, oop orig_mirror, oop<br>
                         }<br>
                       }<br>
                     <br>
                    +  java_lang_Class::set_class_data(m,
                    java_lang_Class::class_data(orig_mirror));<br>
                    +<br>
                       // Class::reflectData use SoftReference, which
                    cannot be archived. Set it<br>
                       // to null and it will be recreated at runtime.<br>
                       java_lang_Class::set_reflection_data(m, nullptr);</p>
                </blockquote>
                <div><br>
                </div>
                <div>Hi Ioi,</div>
                <div><br>
                </div>
                <div>This patch effectively does the same thing as my
                  initial patch for storing classData in the scratch
                  mirror object [1].</div>
                <div><br>
                </div>
                <div>At this point I think it would be useful to do a
                  quick recap of the issues mentioned in this thread.
                  There are 3 issues I have encountered so far.</div>
                <div>I was initially thinking of a solution that would
                  cover all these problems, but looking at these again,
                  I feel these are orthogonal to each other:</div>
                <div><br>
                </div>
                <div>1. The missing classData in scratch mirrors which
                  can be fixed by either of the patches shared in this
                  thread. They achieve the same goal and I don't have
                  any strong preference for any of them.</div>
                <div><br>
                </div>
                <div>2. After fixing the classData, I ran into 
                  WrongMethodTypeException issue [2] which I fixed by
                  exchanging the order of indy resolution with the call
                  to MethodType::createArchivedObjects [3].</div>
                <div>This change makes sense because we want to make
                  sure all the MethodType objects that can be archived
                  are in MethodType internTable before calling
                  MethodType::createArchivedObjects.</div>
                <div>I am not sure why
                  LambdaWithUseImplMethodHandle.java didn't throw the
                  WrongMethodTypeException, as the Infinispan code does.<br>
                </div>
                <div><br>
                </div>
                <div>3. After fixing the WrongMethodTypeException I hit
                  NPE due to the class initialization cycle between <font face="monospace">PrimitiveClassDescImpl</font> and <font face="monospace">ConstantDescs </font><font face="arial, sans-serif">[4] in one of my own
                    testcase.</font></div>
                <div><span style="font-family:arial,sans-serif">We are
                    looking for a solution to this problem. I am not
                    sure if we can break this cycle by refactoring
                    the Java code.</span></div>
                <div><span style="font-family:arial,sans-serif">Nevertheless,
                    I think it is fair to assume that there is no Java
                    code that can initiate initialization of </span><span style="font-family:monospace">PrimitiveClassDescImpl
                  </span><font face="arial, sans-serif">before</font><span style="font-family:monospace"> ConstantDescs</span><font face="arial, sans-serif">, otherwise we would have
                    hit the NPE earlier.</font></div>
                <div><font face="arial, sans-serif">So if </font><font face="monospace">ConstantDescs</font><font face="arial, sans-serif"> is always expected to be
                    initialized before </font><span style="font-family:monospace">PrimitiveClassDescImpl</span><font face="arial, sans-serif"> then I think the VM code
                    should also maintain this assumption.</font></div>
                <div><font face="arial, sans-serif">Now this brings us
                    back to the forceful initialization done by the VM
                    during the assembly phase based on the </font>forced_preinit_classes
                  list in aotClassInitializer.cpp:</div>
                <div><br>
                </div>
                <div><font face="monospace">    // TODO:<br>
                        // This is needed since JDK-8338532. Without
                    this, when<br>
                        // archived heap objects are used, the class
                    init order is not<br>
                        // expected by the jdk/internal/constant
                    bootstrap code and we<br>
                        // will get a null pointer exception.<br>
                        //<br>
                        // When bootstraping has intricated/fragile
                    order, it's probably<br>
                        // better to archive all related classes in an
                    initialized state<br>
                        // (i.e., take a snapshot). The existing
                    approach in<br>
                        //
                    heapShared::resolve_or_init_classes_for_subgraph_of()
                    won't work.<br>
                        "jdk/internal/constant/PrimitiveClassDescImpl",<br>
                        "jdk/internal/constant/ReferenceClassDescImpl",<br>
                        "java/lang/constant/ConstantDescs",<br>
                        "sun/invoke/util/Wrapper",</font><br>
                </div>
                <div><font face="arial, sans-serif"><br>
                  </font></div>
                <div><font face="arial, sans-serif">I wonder why we need
                    to explicitly add  </font><span style="font-family:monospace">PrimitiveClassDescImpl</span><font face="arial, sans-serif"> and </font><span style="font-family:monospace">ReferenceClassDescImpl</span><font face="arial, sans-serif"> in this list.</font></div>
                <div><font face="arial, sans-serif">Initialization of </font><span style="font-family:monospace">ConstantDescs</span><font face="arial, sans-serif"> would anyway trigger the
                    initialization of </font><span style="font-family:monospace">PrimitiveClassDescImpl</span><font face="arial, sans-serif"> and </font><span style="font-family:monospace">ReferenceClassDescImpl</span><font face="arial, sans-serif">.</font></div>
                <div><font face="arial, sans-serif">So if we only keep
                    the entry for </font><span style="font-family:monospace">ConstantDescs</span><font face="arial, sans-serif"> and remove </font><span style="font-family:monospace">PrimitiveClassDescImpl</span><font face="arial, sans-serif"> and </font><span style="font-family:monospace">ReferenceClassDescImpl</span><font face="arial, sans-serif"> from this list,</font></div>
                <div><font face="arial, sans-serif">we can be sure that
                    the forceful initialization by the VM would maintain
                    the same </font><span style="font-family:arial,sans-serif">order of
                    initialization as guided by the Java code,</span></div>
                <div><span style="font-family:arial,sans-serif">and we
                    will not hit the NPE when initializing </span><span style="font-family:monospace">PrimitiveClassDescImpl
                  </span><font face="arial, sans-serif">during the
                    assembly phase.</font></div>
                <div><font face="arial, sans-serif">Does this make
                    sense?</font></div>
                <div><span style="font-family:arial,sans-serif"><br>
                  </span></div>
                <div><br>
                </div>
                <div>[1] <a href="https://mail.openjdk.org/pipermail/leyden-dev/2024-September/000994.html" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://mail.openjdk.org/pipermail/leyden-dev/2024-September/000994.html</a></div>
                <div>[2] <a href="https://mail.openjdk.org/pipermail/leyden-dev/2024-September/000997.html" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://mail.openjdk.org/pipermail/leyden-dev/2024-September/000997.html</a></div>
                <div>[3] <a href="https://urldefense.com/v3/__https://github.com/ashu-mehra/leyden/commit/d8f99cce67df1c7b0f7ef8562676df438633a66e__;!!ACWV5N9M2RV99hQ!KvYLs_vG0a4GO3ltinXQkxBG1kMhCAvmmM6MwODoKzOhhVjzNL80S_0mBzYvYyhYPQnGmXhAXSw78Q$" style="font-family:arial,sans-serif" target="_blank" moz-do-not-send="true">https://github.com/ashu-mehra/leyden/commit/d8f99cce67df1c7b0f7ef8562676df438633a66e</a></div>
                <div>[4] <a href="https://mail.openjdk.org/pipermail/leyden-dev/2024-September/001018.html" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://mail.openjdk.org/pipermail/leyden-dev/2024-September/001018.html</a></div>
                <div><br>
                </div>
                <div>Thanks,</div>
                <div>
                  <div dir="ltr" class="gmail_signature">
                    <div dir="ltr">- Ashutosh Mehra</div>
                  </div>
                </div>
                <br>
              </div>
              <br>
              <div class="gmail_quote">
                <div dir="ltr" class="gmail_attr">On Thu, Sep 19, 2024
                  at 8:51 PM <<a href="mailto:ioi.lam@oracle.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">ioi.lam@oracle.com</a>>
                  wrote:<br>
                </div>
                <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                  <div>
                    <p>Upon further investigation, it seems a simple
                      patch might fix the problem with classData. <br>
                    </p>
                    <p>I tested with
                      test/hotspot/jtreg/runtime/cds/appcds/LambdaWithUseImplMethodHandle.java
                      by running jtreg with
                      -javaoptions:-XX:+AOTClassLinking<br>
                      Without the patch, I'd get a NullPointerException.
                      With the patch, the test passes.</p>
                    <p>It looks like classData is not treated as a
                      static field of the class, but rather an instance
                      field in the mirror. So classData wasn't copied by
                      the loop in
                      HeapShared::copy_preinitialized_mirror().</p>
                    <p>Ashutosh, could you try it this fixes the crash
                      on your side?<br>
                    </p>
                    <p>Thanks</p>
                    <p>- Ioi<br>
                    </p>
                    <p>diff --git a/src/hotspot/share/cds/heapShared.cpp
                      b/src/hotspot/share/cds/heapShared.cpp<br>
                      index 0e70778f057..62cf142f67a 100644<br>
                      --- a/src/hotspot/share/cds/heapShared.cpp<br>
                      +++ b/src/hotspot/share/cds/heapShared.cpp<br>
                      @@ -634,6 +634,8 @@ void
                      HeapShared::copy_preinitialized_mirror(Klass*
                      orig_k, oop orig_mirror, oop<br>
                           }<br>
                         }<br>
                       <br>
                      +  java_lang_Class::set_class_data(m,
                      java_lang_Class::class_data(orig_mirror));<br>
                      +<br>
                         // Class::reflectData use SoftReference, which
                      cannot be archived. Set it<br>
                         // to null and it will be recreated at runtime.<br>
                         java_lang_Class::set_reflection_data(m,
                      nullptr);<br>
                      <br>
                    </p>
                    <p><br>
                    </p>
                    <p><br>
                    </p>
                    <div>On 9/19/24 12:51 PM, <a href="mailto:ioi.lam@oracle.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">ioi.lam@oracle.com</a>
                      wrote:<br>
                    </div>
                    <blockquote type="cite">
                      <p><br>
                      </p>
                      <div>On 9/19/24 7:44 AM, Ashutosh Mehra wrote:<br>
                      </div>
                      <blockquote type="cite">
                        <div dir="ltr">
                          <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">As
                            I am cleaning up the code for upstreaming to
                            mainline, I am going add an equivalent check
                            in the C code to filter out these indy call
                            sites, so they won't be resolved at all
                            during the assembly phase. Otherwise, I will
                            run into problems described in <a href="https://bugs.openjdk.org/browse/JDK-8290417" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://bugs.openjdk.org/browse/JDK-8290417</a></blockquote>
                          <div><br>
                          </div>
                          <div>Thanks for the link to the bug. The
                            scenario described in that bug is exactly
                            the same as the Infinispan case.</div>
                          <div>So if we filter out such cases during
                            indy resolution then it should resolve the
                            Infinispan issue as well.</div>
                          <div><br>
                          </div>
                          <div>A basic question: why can't CDS handle
                            the lambda proxy class generated in <span style="color:rgb(31,35,40)"><font face="arial, sans-serif">useImplMethodHandle</font></span><span style="color:rgb(31,35,40);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji""> mode?</span><br>
                          </div>
                          <div><span style="color:rgb(31,35,40);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji""><br>
                            </span></div>
                        </div>
                      </blockquote>
                      <p>If I remember correctly, it has to do with the
                        shape of dynamically generated bytecode:</p>
                      <p>  public void accept(java.lang.Object);<br>
                            Code:<br>
                               0: ldc #28 // Dynamic
                        #0:_:Ljava/lang/invoke/MethodHandle;<br>
                               2: aload_0<br>
                               3: getfield #15 // Field arg$1:LTester;<br>
                               6: aload_1<br>
                               7: checkcast #30 // class
                        java/lang/String<br>
                              10: invokevirtual #36 // Method
                        java/lang/invoke/MethodHandle.invokeExact:(LTester;Ljava/lang/String;)V<br>
                              13: return<br>
                      </p>
                      <p>The result of the "ldc" was not symbolically
                        encoded in the generated class (as the generated
                        class has no permission to access that method).
                        So the MethodHandle is stored as a binary object
                        in the mirror of this generated class (with the
                        java.lang.Class::classData field).</p>
                      <p>Plain CDS doesn't archive class mirrors, so the
                        classData will be lost.</p>
                      <p>With JEP 483, we should be able to preserve the
                        classData, so I am not sure why the
                        useImplMethodHandle case is still failing. My
                        plan is to filter these out for now, but I will
                        get back to it later when I have more time.</p>
                      <p>Thanks</p>
                      <p>- Ioi<br>
                      </p>
                      <br>
                      <p><br>
                      </p>
                      <p><br>
                      </p>
                      <blockquote type="cite">
                        <div dir="ltr">
                          <div><span style="color:rgb(31,35,40);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"">Thanks,</span></div>
                          <div>
                            <div dir="ltr" class="gmail_signature">
                              <div dir="ltr">- Ashutosh Mehra</div>
                            </div>
                          </div>
                          <br>
                        </div>
                        <br>
                        <div class="gmail_quote">
                          <div dir="ltr" class="gmail_attr">On Thu, Sep
                            19, 2024 at 1:45 AM <<a href="mailto:ioi.lam@oracle.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">ioi.lam@oracle.com</a>>
                            wrote:<br>
                          </div>
                          <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                            <div>
                              <p>Hi Ashutosh,<br>
                              </p>
                              <p>I have some update:</p>
                              <p>The original crash was caused by the
                                "useImplMethodHandle" code in
                                InnerClassLambdaMetafactory.java:<br>
                              </p>
                              <p>        // If the target class invokes
                                a protected method inherited from a<br>
                                        // superclass in a different
                                package, or does 'invokespecial', the<br>
                                        // lambda class has no access to
                                the resolved method, or does<br>
                                        // 'invokestatic' on a hidden
                                class which cannot be resolved by name.<br>
                                        // Instead, we need to pass the
                                live implementation method handle to<br>
                                        // the proxy class to invoke
                                directly. (javac prefers to avoid this<br>
                                        // situation by generating
                                bridges in the target class)<br>
                                        useImplMethodHandle =
                                (Modifier.isProtected(implInfo.getModifiers())
                                &&<br>
                                                              
                                !VerifyAccess.isSamePackage(targetClass,
                                implInfo.getDeclaringClass())) ||<br>
                                                               implKind
                                == MethodHandleInfo.REF_invokeSpecial ||<br>
                                                               implKind
                                == MethodHandleInfo.REF_invokeStatic
                                && implClass.isHidden();<br>
                              </p>
                              <p>As I am cleaning up the code for
                                upstreaming to mainline, I am going add
                                an equivalent check in the C code to
                                filter out these indy call sites, so
                                they won't be resolved at all during the
                                assembly phase. Otherwise, I will run
                                into problems described in <a href="https://bugs.openjdk.org/browse/JDK-8290417" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://bugs.openjdk.org/browse/JDK-8290417</a><br>
                              </p>
                              <p>Once I get the filtering code working,
                                I will integrate it back to premain.<br>
                              </p>
                              <p>>I am wondering if we can workaround
                                class circularity issues by recording
                                class initialization order<br>
                                >during training run and use that to
                                guide the initialization during assembly
                                phase.<br>
                              </p>
                              <p>In the production run we take different
                                paths than the training run<br>
                              </p>
                              <p>(1) some classes are aot-initialized
                                (especially the enums)<br>
                                (2) some classes make special CDS calls<br>
                              </p>
                              <p>so I am not sure if it's possible to
                                get the same initialization order as in
                                the training run (or assembly phase).</p>
                              <p>(more below)<br>
                              </p>
                              <div>On 9/18/24 9:10 AM, Ashutosh Mehra
                                wrote:<br>
                              </div>
                              <blockquote type="cite">
                                <div dir="ltr">Hi Ioi,
                                  <div><br>
                                  </div>
                                  <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I
                                    was having a similar circularity
                                    issue (but in production time) and I
                                    just added enough classes to make
                                    the NPE go away.<br>
                                  </blockquote>
                                  <div> </div>
                                  <div>
                                    <div>I am wondering if you have a
                                      test case that reproduces the NPE
                                      which prompted you to add these
                                      classes:</div>
                                    <div><br>
                                    </div>
                                    <div><a href="https://urldefense.com/v3/__https://github.com/openjdk/leyden/blob/7781109154bf2af89854c7e13aa3e160bb82608e/src/hotspot/share/cds/aotClassInitializer.cpp*L65-L78__;Iw!!ACWV5N9M2RV99hQ!NYvqLbb_Ib2kSdm2fcYVLGby-AiB2TG7KtC1HQHVKLiM-_kRb5mOt8krV5IZfReaYZ0MPadDfa08hQ$" target="_blank" moz-do-not-send="true">https://github.com/openjdk/leyden/blob/7781109154bf2af89854c7e13aa3e160bb82608e/src/hotspot/share/cds/aotClassInitializer.cpp#L65-L78</a></div>
                                    <div><br>
                                    </div>
                                    <div>I commented this code and ran
                                      the tests under premain but didn't
                                      hit the NPE.</div>
                                    <div><br>
                                    </div>
                                  </div>
                                </div>
                              </blockquote>
                              <p>I forgot what the problem was, but it
                                happened for very simple cases.<br>
                              </p>
                              <p>Thanks</p>
                              <p>- Ioi<br>
                              </p>
                              <p><br>
                              </p>
                              <blockquote type="cite">
                                <div dir="ltr">
                                  <div>
                                    <div>Thanks,</div>
                                    <div>
                                      <div>
                                        <div dir="ltr" class="gmail_signature">
                                          <div dir="ltr">- Ashutosh
                                            Mehra</div>
                                        </div>
                                      </div>
                                      <br>
                                    </div>
                                  </div>
                                </div>
                                <br>
                                <div class="gmail_quote">
                                  <div dir="ltr" class="gmail_attr">On
                                    Tue, Sep 17, 2024 at 1:11 AM <<a href="mailto:ioi.lam@oracle.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">ioi.lam@oracle.com</a>>
                                    wrote:<br>
                                  </div>
                                  <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                                    <div>
                                      <p>Hi Ashutosh,<br>
                                      </p>
                                      <p>So this looks like a potential
                                        bug (or feature) in the core lib
                                        code. When CDS forcefully
                                        initializes a class in an
                                        unexpected (or untested) order,
                                        the "initialization soup" fails.</p>
                                      <p>Perhaps a work-around would be
                                        to make some harmless calls at
                                        the place where CDS was calling
                                        into
                                        MethodType.createArchivedObjects().
                                        E.g., do something like this:</p>
                                      <p><font face="monospace">+    if
(CDSConfig::is_dumping_invokedynamic()) {<br>
                                          +       // call into Java:
                                          jdk.internal.misc::warmupInvokeDynamic();<br>
                                          +   }<br>
                                              // Rewrite and link
                                          classes<br>
                                              log_info(cds)("Rewriting
                                          and linking classes ...");<br>
                                          <br>
                                        </font>Maybe you can add a new
                                        Lambda expressions, MethodHandle
                                        invocations, etc, that would
                                        hopefully cause
                                        PrimitiveClassDescImpl and
                                        friends to be initialized in
                                        their natural order.<br>
                                      </p>
                                      <p>Or call
                                        class.forName("java.lang.constant.ConstantDescs")
                                        ??</p>
                                      <p>BTW, you can see my comments in
AOTClassInitializer::is_forced_preinit_class():<br>
                                        <br>
                                            // TODO:<br>
                                            // This is needed since
                                        JDK-8338532. Without this, when<br>
                                            // archived heap objects are
                                        used, the class init order is
                                        not<br>
                                            // expected by the
                                        jdk/internal/constant bootstrap
                                        code and we<br>
                                            // will get a null pointer
                                        exception.<br>
                                            //<br>
                                            // When bootstraping has
                                        intricated/fragile order, it's
                                        probably<br>
                                            // better to archive all
                                        related classes in an
                                        initialized state<br>
                                            // (i.e., take a snapshot).
                                        The existing approach in<br>
                                            //
                                        heapShared::resolve_or_init_classes_for_subgraph_of()
                                        won't work.<br>
                                           
                                        "jdk/internal/constant/PrimitiveClassDescImpl",<br>
                                           
                                        "jdk/internal/constant/ReferenceClassDescImpl",<br>
                                           
                                        "java/lang/constant/ConstantDescs",<br>
                                            "sun/invoke/util/Wrapper",<br>
                                        <br>
                                        I was having a similar
                                        circularity issue (but in
                                        production time) and I just
                                        added enough classes to make the
                                        NPE go away. For your test case,
                                        if you manage to fix in in the
                                        assembly run but run into NPE in
                                        production run, you might need
                                        to add more classes to this
                                        list. Yes, it's a hack :-(<br>
                                      </p>
                                      <p><br>
                                      </p>
                                      <p>Thanks</p>
                                      <p>- Ioi<br>
                                      </p>
                                      <div>On 9/13/24 7:05 PM, Ashutosh
                                        Mehra wrote:<br>
                                      </div>
                                      <blockquote type="cite">
                                        <div dir="ltr">This is turning
                                          out to be a real example of
                                          class initialization soup!
                                          <div>As mentioned during the
                                            meeting, I am getting NPE in
                                            the assembly phase when
                                            testing the patch [0] that I
                                            proposed in my earlier mail </div>
                                          <div>using a test case
                                            inspired by the Infinispan
                                            code.</div>
                                          <div>NPE occurs when running
                                            the class initializer for <font face="monospace">PrimitiveClassDescImpl </font></div>
                                          <div>
                                            <div>Interestingly, <span style="font-family:monospace">PrimitiveClassDescImpl</span> is
                                              "forcefully" initialized
                                              by <font face="monospace">MetaspaceShared::link_shared_classes()</font>.</div>
                                            <div><br>
                                            </div>
                                            <div>
                                              <div>
                                                <div dir="ltr" class="gmail_signature">
                                                  <div dir="ltr">I
                                                    couldn't get a stack
                                                    trace so I relied on
                                                    exception logs
                                                    (using
                                                    -Xlog:exceptions=trace)
                                                    to find the cause
                                                    which indicate
                                                    following frames on
                                                    the stack:</div>
                                                  <div dir="ltr"><br>
                                                  </div>
                                                  <div dir="ltr"><font face="monospace">[0]
jdk/internal/constant/MethodTypeDescImpl::validateArgument(Ljava/lang/constant/ClassDesc;)Ljava/lang/constant/ClassDesc; @
                                                      bci 1<br>
                                                    </font></div>
                                                  <div dir="ltr"><font face="monospace">[1]
jdk/internal/constant/MethodTypeDescImpl::ofTrusted(Ljava/lang/constant/ClassDesc;[Ljava/lang/constant/ClassDesc;)Ljdk/internal/constant/MethodTypeDescImpl; @
                                                      bci 27<br>
                                                    </font></div>
                                                  <div dir="ltr"><font face="monospace">[2]
java/lang/constant/ConstantDescs::ofConstantBootstrap(Ljava/lang/constant/ClassDesc;Ljava/lang/String;Ljava/lang/constant/ClassDesc;[Ljava/lang/constant/ClassDesc;)Ljava/lang/constant/DirectMethodHandleDesc; @
                                                      bci 47</font></div>
                                                  <div dir="ltr"><font face="monospace">[3]
java/lang/constant/ConstantDescs::<clinit> @ bci 664<br>
                                                    </font></div>
                                                  <div dir="ltr"><font face="monospace">[4]
jdk/internal/constant/PrimitiveClassDescImpl::<init>(Ljava/lang/String;)V @
                                                      bci 1<br>
                                                    </font></div>
                                                  <div dir="ltr"><font face="monospace">[5]
jdk/internal/constant/PrimitiveClassDescImpl::<clinit>(Ljava/lang/String;)V @
                                                      bci 6</font><span style="font-family:monospace"><br>
                                                    </span></div>
                                                  <div dir="ltr"><span style="font-family:monospace"><br>
                                                    </span></div>
                                                  <div dir="ltr">Notice that
                                                    invocation of <font face="monospace">PrimitiveClassDescImpl::<clinit>
                                                    </font>results in
                                                    initialization of <font face="monospace">ConstantDescs</font> class
                                                    (see frame 3).<br>
                                                  </div>
                                                  <div><font face="monospace">ConstantDescs::<clinit> @
                                                      664 </font><font face="arial, sans-serif">corresponds to following java code:</font></div>
                                                  <div><br>
                                                  </div>
                                                  <div><font face="monospace"> 
                                                        public static
                                                      final
                                                      DirectMethodHandleDesc
                                                      BSM_CLASS_DATA_AT<br>
                                                    </font></div>
                                                  <div><font face="monospace"> 
                                                                =
                                                      ofConstantBootstrap(CD_MethodHandles,
                                                      "classDataAt",<br>
                                                                 
                                                      CD_Object,
                                                      CD_int);<br>
                                                    </font></div>
                                                  <div><br>
                                                  </div>
                                                  <div>The last
                                                    parameter CD_int is
                                                    initialized as:</div>
                                                  <div><br>
                                                  </div>
                                                  <div><font face="monospace"> 
                                                        public static
                                                      final ClassDesc
                                                      CD_int =
                                                      PrimitiveClassDescImpl.CD_int;<br>
                                                    </font></div>
                                                  <div><br>
                                                  </div>
                                                  <div>So, its value is
                                                    obtained from <font face="monospace">PrimitiveClassDescImpl.CD_int</font> which
                                                    hasn't been
                                                    initialized properly
                                                    yet. As a result <font face="monospace">ConstantDescs::CD_int
                                                    </font><font face="arial, sans-serif">is assigned</font> null which results in <font face="monospace">MethodTypeDescImpl::validateArgument</font>
                                                    throwing NPE later.</div>
                                                  <div>There is a clear
                                                    class initialization
                                                    circularity
                                                    involving <font face="monospace">PrimitiveClassDescImpl</font>
                                                    and <font face="monospace">ConstantDescs</font>,
                                                    and the result
                                                    depends on which
                                                    class gets
                                                    initialized first.</div>
                                                  <div><br>
                                                  </div>
                                                  <div>Without my patch
                                                    this issue is not
                                                    seen because <font face="monospace">PrimitiveClassDescImpl</font>
                                                    has already been
                                                    initialized by the
                                                    time <font face="monospace">MetaspaceShared::link_shared_classes()</font><font face="arial, sans-serif"> is called.</font></div>
                                                  <div><font face="arial, sans-serif">Its initialization is triggered by the call to </font><font face="monospace">MethodType::createArchivedObjects(). </font></div>
                                                  <div><font face="arial, sans-serif">It also explains why my patch introduced this
                                                      issue because it
                                                      effectively moved
                                                      the call to </font><span style="font-family:monospace">MethodType::createArchivedObjects() </span><font face="arial, sans-serif">after </font><span style="font-family:monospace">MetaspaceShared::link_shared_classes().</span></div>
                                                  <div><span style="font-family:monospace"><br>
                                                    </span></div>
                                                  <div><font face="arial, sans-serif">[0] <a href="https://urldefense.com/v3/__https://github.com/ashu-mehra/leyden/commit/d8f99cce67df1c7b0f7ef8562676df438633a66e__;!!ACWV5N9M2RV99hQ!MnS3LSY2PXCCXbHvdyMfR6Nj57XH7Ey7aZuOLmQ__hhE_RhUrKnkzZ0uP8AwLZYcl8lAhhZK3GwoiA$" target="_blank" moz-do-not-send="true">https://github.com/ashu-mehra/leyden/commit/d8f99cce67df1c7b0f7ef8562676df438633a66e</a></font></div>
                                                  <div><font face="arial, sans-serif"><br>
                                                    </font></div>
                                                  <div><font face="arial, sans-serif">Thanks,</font></div>
                                                  <div><font face="arial, sans-serif">- Ashutosh Mehra</font></div>
                                                </div>
                                              </div>
                                              <br>
                                            </div>
                                          </div>
                                        </div>
                                        <br>
                                        <div class="gmail_quote">
                                          <div dir="ltr" class="gmail_attr">On Wed,
                                            Sep 11, 2024 at 3:12 PM
                                            Ashutosh Mehra <<a href="mailto:asmehra@redhat.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">asmehra@redhat.com</a>> wrote:<br>
                                          </div>
                                          <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                                            <div dir="ltr">Regarding the
                                              WrongMethodTypeException
                                              that I mentioned in my
                                              previous email (see pt 3),
                                              <div>this exception
                                                happens when lambda
                                                proxy class attempts to
                                                invoke the MethodHandle
                                                it obtained from the
                                                classData:</div>
                                              <div><br>
                                              </div>
                                              <div><font face="monospace"> 
                                                  public void
                                                  accept(java.lang.Object);<br>
                                                      descriptor:
                                                  (Ljava/lang/Object;)V<br>
                                                      flags: (0x0001)
                                                  ACC_PUBLIC<br>
                                                      Code:<br>
                                                        stack=3,
                                                  locals=2, args_size=2<br>
                                                           0: ldc      
                                                      #26              
                                                    // Dynamic
                                                  #0:_:Ljava/lang/invoke/MethodHandle;<br>
                                                           2: aload_0<br>
                                                           3: getfield  
                                                     #13                
                                                  // Field
                                                  arg$1:Lorg/wildfly/security/WildFlyElytronBaseProvider;<br>
                                                           6: aload_1<br>
                                                           7: checkcast
                                                      #28              
                                                    // class
                                                  java/security/Provider$Service<br>
                                                          10:
                                                  invokevirtual #34    
                                                              // Method
java/lang/invoke/MethodHandle.invokeExact:(Lorg/wildfly/security/WildFlyElytronBaseProvider;Ljava/security/Provider$Service;)V<br>
                                                          13: return</font><br>
                                              </div>
                                              <div><br>
                                              </div>
                                              <div>
                                                <div>The scenario is
                                                  during the assembly
                                                  phase as part of the
                                                  indy resolution the
                                                  MethodHandle for which
                                                  the exception is
                                                  thrown gets created.</div>
                                                <div>Normally
                                                  MethodHandle's type
                                                  gets added in <font face="monospace">MethodType::internTable</font>
                                                  but by the time indy
                                                  resolution happens,
                                                  JVM has already taken </div>
                                                <div>snapshot of the <font face="monospace">MethodType::internTable</font>
                                                  through an upcall to <font face="monospace">MethodType::createArchivedObjects()</font>.</div>
                                                <div>As a result the
                                                  AOTCache ends up with
                                                  the MethodType object
                                                  which is not in <font face="monospace">AOTHolder.archivedMethodTypes</font>.</div>
                                                <div><br>
                                                </div>
                                                <div>During the
                                                  production run, when
                                                  the jvm invokes the
                                                  MethodHandle, it
                                                  searches for the
                                                  MethodType
                                                  corresponding to the
                                                  signature passed at
                                                  the callsite.</div>
                                                <div>As expected, it
                                                  fails to find it in
                                                  the <font face="monospace">AOTHolder.archivedMethodTypes</font>,
                                                  so it creates a new
                                                  instance of the
                                                  MethodType.</div>
                                                <div>But <font face="monospace">Invokers.checkExactType()</font>
                                                  relies on the
                                                  MethodHandle's type to
                                                  be the same object as
                                                  the MethodType object
                                                  passed as parameter.</div>
                                                <div><br>
                                                </div>
                                                <div><font face="monospace">   
                                                    static void
                                                    checkExactType(M</font><span style="font-family:monospace">ethodHandle mh</span><span style="font-family:monospace">M, MethodType expected) {</span></div>
                                                <div><font face="monospace">   
                                                        MethodType
                                                    targetType =
                                                    mh.type();<br>
                                                            if
                                                    (targetType !=
                                                    expected)<br>
                                                                throw
                                                    newWrongMethodTypeException(targetType,
                                                    expected);<br>
                                                        }</font><br>
                                                </div>
                                                <div><br>
                                                </div>
                                                <div>Hence, it throws <span style="font-family:monospace">WrongMethodTypeException</span><font face="arial, sans-serif"> though the two MT objects have the same
                                                    signature.</font></div>
                                                <div><font face="arial, sans-serif"><br>
                                                  </font></div>
                                                <div><font face="arial, sans-serif">To handle this scenario, I changed the order of
                                                    indy resolution and </font>upcall
                                                  to <font face="monospace">MethodType::createArchivedObjects()</font><font face="arial, sans-serif"> as:</font></div>
                                                <div><font face="arial, sans-serif"><br>
                                                  </font></div>
                                                <div><font face="monospace">diff
                                                    --git
                                                    a/src/hotspot/share/cds/metaspaceShared.cpp
b/src/hotspot/share/cds/metaspaceShared.cpp<br>
                                                    index
                                                    df4bcadefa3..457716cac5b
                                                    100644<br>
                                                    ---
                                                    a/src/hotspot/share/cds/metaspaceShared.cpp<br>
                                                    +++
                                                    b/src/hotspot/share/cds/metaspaceShared.cpp<br>
                                                    @@ -751,6 +751,20 @@
                                                    void
                                                    MetaspaceShared::link_shared_classes(bool
                                                    jcmd_request, TRAPS)
                                                    {<br>
                                                       if
                                                    (CDSConfig::is_dumping_final_static_archive())
                                                    {<br>
                                                       
                                                     FinalImageRecipes::apply_recipes(CHECK);<br>
                                                       }<br>
                                                    +<br>
                                                    +#if
                                                    INCLUDE_CDS_JAVA_HEAP<br>
                                                    +  if
                                                    (CDSConfig::is_dumping_invokedynamic())
                                                    {<br>
                                                    +    // This makes
                                                    sure that the
                                                    MethodType and
                                                    MethodTypeForm
                                                    tables won't be
                                                    updated<br>
                                                    +    // concurrently
                                                    when we are saving
                                                    their contents into
                                                    a side table.<br>
                                                    +  
                                                     assert(CDSConfig::allow_only_single_java_thread(),
                                                    "Required");<br>
                                                    +<br>
                                                    +    JavaValue
                                                    result(T_VOID);<br>
                                                    +  
                                                     JavaCalls::call_static(&result,
vmClasses::MethodType_klass(),<br>
                                                    +                  
                                                           
vmSymbols::createArchivedObjects(),<br>
                                                    +                  
                                                           
vmSymbols::void_method_signature(),<br>
                                                    +                  
                                                            CHECK);<br>
                                                    +  }<br>
                                                    +#endif<br>
                                                     }</font><br>
                                                   </div>
                                                <div>Note that indy
                                                  resolution happens as
                                                  part of <span style="font-family:monospace">FinalImageRecipes::apply_recipes(CHECK) </span><font face="arial, sans-serif">which is now invoked before the upcall to </font><span style="font-family:monospace">createArchivedObjects().</span></div>
                                                <div><font face="arial, sans-serif">With this change I am able to run the
                                                    application without
                                                    any exceptions.</font></div>
                                                <div>My complete patch
                                                  can be seen here: <a href="https://urldefense.com/v3/__https://github.com/ashu-mehra/leyden/commit/d8f99cce67df1c7b0f7ef8562676df438633a66e__;!!ACWV5N9M2RV99hQ!MnS3LSY2PXCCXbHvdyMfR6Nj57XH7Ey7aZuOLmQ__hhE_RhUrKnkzZ0uP8AwLZYcl8lAhhZK3GwoiA$" target="_blank" moz-do-not-send="true">https://github.com/ashu-mehra/leyden/commit/d8f99cce67df1c7b0f7ef8562676df438633a66e</a></div>
                                                <div>I will do more
                                                  testing with this
                                                  patch.</div>
                                                <div><br>
                                                </div>
                                                <div><a class="gmail_plusreply" id="m_-8594911495544208436m_-6235568143876299380m_5385423560619785655m_-6081196208708063630m_-8326742188757259955m_-669397441264475055m_4538222356731470316m_-1862706623606286828plusReplyChip-0" href="mailto:ioi.lam@oracle.com" target="_blank" moz-do-not-send="true">@Ioi
                                                    Lam</a> do you have
                                                  any feedback on this
                                                  patch.<br>
                                                </div>
                                                <div><br>
                                                </div>
                                                <div>Thanks,<br clear="all">
                                                  <div>
                                                    <div dir="ltr" class="gmail_signature">
                                                      <div dir="ltr">-
                                                        Ashutosh Mehra</div>
                                                    </div>
                                                  </div>
                                                  <br>
                                                </div>
                                                <div><br>
                                                </div>
                                              </div>
                                            </div>
                                            <br>
                                            <div class="gmail_quote">
                                              <div dir="ltr" class="gmail_attr">On
                                                Wed, Sep 11, 2024 at
                                                10:14 AM Ashutosh Mehra
                                                <<a href="mailto:asmehra@redhat.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">asmehra@redhat.com</a>> wrote:<br>
                                              </div>
                                              <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                                                <div dir="ltr">Hi
                                                  Andrew,
                                                  <div>Thanks for
                                                    sharing the initial
                                                    investigation.
                                                    <div>I have been
                                                      looking into this
                                                      and have a few of
                                                      things to add to
                                                      your analysis:</div>
                                                    <div><br>
                                                    </div>
                                                    <div>1.  As you
                                                      mentioned the
                                                      classData for the
                                                      lambda
                                                      class WildFlyElytronBaseProvider$$Lambda
                                                      is null.</div>
                                                    <div>The classData
                                                      is stored in the
                                                      mirror object of
                                                      the InstanceKlass
                                                      when the class is
                                                      defined
                                                      through JVM_LookupDefineClass.</div>
                                                    <div>However, when
                                                      we create the
                                                      scratch mirror
                                                      object (which get
                                                      stored in the AOT
                                                      cache) the
                                                      classData is not
                                                      populated.</div>
                                                    <div>See <a href="https://urldefense.com/v3/__https://github.com/openjdk/leyden/blob/d23b9f2d5e3523cc547337da59327ed86a6057a3/src/hotspot/share/classfile/javaClasses.cpp*L1128-L1131__;Iw!!ACWV5N9M2RV99hQ!MnS3LSY2PXCCXbHvdyMfR6Nj57XH7Ey7aZuOLmQ__hhE_RhUrKnkzZ0uP8AwLZYcl8lAhhbKjzG3gw$" target="_blank" moz-do-not-send="true">https://github.com/openjdk/leyden/blob/d23b9f2d5e3523cc547337da59327ed86a6057a3/src/hotspot/share/classfile/javaClasses.cpp#L1128-L1131</a></div>
                                                    <div><br>
                                                    </div>
                                                    <div><font face="monospace"> 
                                                        Handle
                                                        classData; //
                                                        set to null.
                                                        Will be
                                                        reinitialized at
                                                        runtime<br>
                                                          Handle mirror;<br>
                                                          Handle
                                                        comp_mirror;<br>
                                                         
                                                        allocate_mirror(k,
/*is_scratch=*/true, protection_domain, classData, mirror, comp_mirror,
                                                        CHECK);</font><br>
                                                    </div>
                                                    <div><br>
                                                    </div>
                                                    <div>So this
                                                      explains why the
                                                      call to <font face="monospace">classData(caller.lookupClass())</font><font face="arial, sans-serif"> returned null.</font></div>
                                                    <div><br>
                                                    </div>
                                                    <div>2. In the
                                                      mainline there is
                                                      a check
                                                      in InnerClassLambdaMetafactory.java
                                                      for the particular
                                                      code pattern used
                                                      by the
                                                      application.</div>
                                                    <div>If this code
                                                      pattern is found
                                                      then the lambda
                                                      proxy class is not
                                                      included in the
                                                      CDS archive.</div>
                                                    <div>See <a href="https://urldefense.com/v3/__https://github.com/openjdk/leyden/blob/d23b9f2d5e3523cc547337da59327ed86a6057a3/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java*L163-L170__;Iw!!ACWV5N9M2RV99hQ!MnS3LSY2PXCCXbHvdyMfR6Nj57XH7Ey7aZuOLmQ__hhE_RhUrKnkzZ0uP8AwLZYcl8lAhhZl2S9tQg$" target="_blank" moz-do-not-send="true">https://github.com/openjdk/leyden/blob/d23b9f2d5e3523cc547337da59327ed86a6057a3/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java#L163-L170</a></div>
                                                    <div>and <a href="https://urldefense.com/v3/__https://github.com/openjdk/leyden/blob/d23b9f2d5e3523cc547337da59327ed86a6057a3/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java*L246__;Iw!!ACWV5N9M2RV99hQ!MnS3LSY2PXCCXbHvdyMfR6Nj57XH7Ey7aZuOLmQ__hhE_RhUrKnkzZ0uP8AwLZYcl8lAhhYsI3Xx0g$" target="_blank" moz-do-not-send="true">https://github.com/openjdk/leyden/blob/d23b9f2d5e3523cc547337da59327ed86a6057a3/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java#L246</a></div>
                                                    <div><br>
                                                    </div>
                                                    <div><font face="monospace"> 
                                                              // If the
                                                        target class
                                                        invokes a
                                                        protected method
                                                        inherited from a<br>
                                                                //
                                                        superclass in a
                                                        different
                                                        package, or does
                                                        'invokespecial',
                                                        the<br>
                                                                //
                                                        lambda class has
                                                        no access to the
                                                        resolved method,
                                                        or does<br>
                                                                //
                                                        'invokestatic'
                                                        on a hidden
                                                        class which
                                                        cannot be
                                                        resolved by
                                                        name.<br>
                                                                //
                                                        Instead, we need
                                                        to pass the live
                                                        implementation
                                                        method handle to<br>
                                                                // the
                                                        proxy class to
                                                        invoke directly.
                                                        (javac prefers
                                                        to avoid this<br>
                                                                //
                                                        situation by
                                                        generating
                                                        bridges in the
                                                        target class)<br>
                                                               
                                                        useImplMethodHandle
                                                        =
                                                        (Modifier.isProtected(implInfo.getModifiers())
                                                        &&<br>
                                                                       
                                                                     
                                                         !VerifyAccess.isSamePackage(targetClass,
implInfo.getDeclaringClass())) ||<br>
                                                                       
                                                                     
                                                         implKind ==
                                                        MethodHandleInfo.REF_invokeSpecial
                                                        ||<br>
                                                                       
                                                                     
                                                         implKind ==
                                                        MethodHandleInfo.REF_invokeStatic
                                                        &&
                                                        implClass.isHidden();</font><br>
                                                    </div>
                                                    <div><br>
                                                    </div>
                                                    <div>In premain
                                                      lambda proxy
                                                      classes get
                                                      included in the
                                                      AOT cache as a
                                                      result of indy
                                                      resolution and
                                                      that mechanism
                                                      doesn't have this
                                                      kind of check.</div>
                                                    <div><br>
                                                    </div>
                                                    <div>3. For the null
                                                      classData problem
                                                      mentioned above, I
                                                      tried to fix it by
                                                      storing classData
                                                      in the scratch
                                                      mirror using the
                                                      following patch:<br>
                                                      <br>
                                                    </div>
                                                    <div><font face="monospace">diff
                                                        --git
a/src/hotspot/share/classfile/javaClasses.cpp
b/src/hotspot/share/classfile/javaClasses.cpp<br>
                                                        index
                                                        bd8141adbcc..41766e98093
                                                        100644<br>
                                                        ---
                                                        a/src/hotspot/share/classfile/javaClasses.cpp<br>
                                                        +++
                                                        b/src/hotspot/share/classfile/javaClasses.cpp<br>
                                                        @@ -1094,9
                                                        +1094,9 @@ void
java_lang_Class::create_mirror(Klass* k, Handle class_loader,<br>
                                                             }<br>
                                                             if
                                                        (CDSConfig::is_dumping_heap())
                                                        {<br>
                                                               if
                                                        (CDSConfig::is_dumping_protection_domains())
                                                        {<br>
                                                        -      
                                                         create_scratch_mirror(k,
protection_domain, CHECK);<br>
                                                        +      
                                                         create_scratch_mirror(k,
protection_domain, classData, CHECK);<br>
                                                               } else {<br>
                                                        -      
                                                         create_scratch_mirror(k,
                                                        Handle() /* null
protection_domain*/, CHECK);<br>
                                                        +      
                                                         create_scratch_mirror(k,
                                                        Handle() /* null
protection_domain*/, classData, CHECK);<br>
                                                               }<br>
                                                             }<br>
                                                           } else {<br>
                                                        @@ -1117,7
                                                        +1117,7 @@ void
java_lang_Class::create_mirror(Klass* k, Handle class_loader,<br>
                                                         // Note: we
                                                        archive the
                                                        "scratch mirror"
                                                        instead of
                                                        k->java_mirror(),
                                                        because the<br>
                                                         // latter may
                                                        contain
                                                        dumptime-specific
                                                        information that
                                                        cannot be
                                                        archived<br>
                                                         // (e.g.,
                                                        ClassLoaderData*,
                                                        or static fields
                                                        that are
                                                        modified by Java
                                                        code execution).<br>
                                                        -void
                                                        java_lang_Class::create_scratch_mirror(Klass*
                                                        k, Handle
                                                        protection_domain,
                                                        TRAPS) {<br>
                                                        +void
                                                        java_lang_Class::create_scratch_mirror(Klass*
                                                        k, Handle
                                                        protection_domain,
                                                        Handle
                                                        classData,
                                                        TRAPS) {<br>
                                                           if
                                                        (k->class_loader()
                                                        != nullptr
                                                        &&<br>
                                                             
                                                         k->class_loader()
                                                        !=
SystemDictionary::java_platform_loader() &&<br>
                                                             
                                                         k->class_loader()
                                                        !=
SystemDictionary::java_system_loader()) {<br>
                                                        @@ -1125,9
                                                        +1125,11 @@ void
java_lang_Class::create_scratch_mirror(Klass* k, Handle
                                                        protection_domain,<br>
                                                             return;<br>
                                                           }<br>
                                                         <br>
                                                        -  Handle
                                                        classData; //
                                                        set to null.
                                                        Will be
                                                        reinitialized at
                                                        runtime<br>
                                                        +  //Handle
                                                        classData; //
                                                        set to null.
                                                        Will be
                                                        reinitialized at
                                                        runtime<br>
                                                           Handle
                                                        mirror;<br>
                                                           Handle
                                                        comp_mirror;<br>
                                                         
                                                         allocate_mirror(k,
/*is_scratch=*/true, protection_domain, classData, mirror, comp_mirror,
                                                        CHECK);<br>
                                                         <br>
                                                           if
                                                        (comp_mirror()
                                                        != nullptr) {<br>
                                                        diff --git
                                                        a/src/hotspot/share/classfile/javaClasses.hpp
b/src/hotspot/share/classfile/javaClasses.hpp<br>
                                                        index
                                                        bc49a0861a7..7ec2a2556dd
                                                        100644<br>
                                                        ---
                                                        a/src/hotspot/share/classfile/javaClasses.hpp<br>
                                                        +++
                                                        b/src/hotspot/share/classfile/javaClasses.hpp<br>
                                                        @@ -263,7 +263,7
                                                        @@ class
                                                        java_lang_Class
                                                        : AllStatic {<br>
                                                         <br>
                                                           // Archiving<br>
                                                           static void
                                                        serialize_offsets(SerializeClosure*
                                                        f)
                                                        NOT_CDS_RETURN;<br>
                                                        -  static void
                                                        create_scratch_mirror(Klass*
                                                        k, Handle
                                                        protection_domain,
                                                        TRAPS)
                                                        NOT_CDS_JAVA_HEAP_RETURN;<br>
                                                        +  static void
                                                        create_scratch_mirror(Klass*
                                                        k, Handle
                                                        protection_domain,
                                                        Handle
                                                        classData,
                                                        TRAPS)
NOT_CDS_JAVA_HEAP_RETURN;<br>
                                                           static bool
                                                        restore_archived_mirror(Klass
                                                        *k, Handle
                                                        class_loader,
                                                        Handle module,<br>
                                                                       
                                                                       
                                                               Handle
                                                        protection_domain,<br>
                                                                       
                                                                       
                                                               TRAPS)
                                                        NOT_CDS_JAVA_HEAP_RETURN_(false);</font><br>
                                                    </div>
                                                    <div><br>
                                                    </div>
                                                    <div>But this
                                                      resulted in a
                                                      different
                                                      exception:</div>
                                                    <div><br>
                                                    </div>
                                                    <div><font face="monospace">Exception
                                                        in thread "main"
java.lang.ExceptionInInitializerError<br>
                                                        at
                                                        com.redhat.leyden.Main.main(Main.java:7)<br>
                                                        Caused by:
                                                        java.lang.invoke.WrongMethodTypeException:
                                                        handle's method
                                                        type
                                                        (WildFlyElytronBaseProvider,Service)void
                                                        but found
                                                        (WildFlyElytronBaseProvider,Service)void<br>
                                                        at
java.base/java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:521)<br>
                                                        at
                                                        java.base/java.lang.invoke.Invokers.checkExactType(Invokers.java:530)<br>
                                                        at
java.base/java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder)<br>
                                                        at
org.wildfly.security.WildFlyElytronBaseProvider$$Lambda/0x80000000c.accept(Unknown
                                                        Source)<br>
                                                        at
org.wildfly.security.WildFlyElytronBaseProvider.putMakedPasswordImplementations(WildFlyElytronBaseProvider.java:112)<br>
                                                        at
org.wildfly.security.WildFlyElytronBaseProvider.putPasswordImplementations(WildFlyElytronBaseProvider.java:107)<br>
                                                        at
org.wildfly.security.password.WildFlyElytronPasswordProvider.<init>(WildFlyElytronPasswordProvider.java:43)<br>
                                                        at
org.wildfly.security.password.WildFlyElytronPasswordProvider.<clinit>(WildFlyElytronPasswordProvider.java:36)<br>
                                                        ... 1 more</font><br>
                                                    </div>
                                                    <div><font face="monospace"><br>
                                                      </font></div>
                                                    <div>The exception
                                                      message is strange
                                                      because the
                                                      handle's method
                                                      type and the
                                                      expected type are
                                                      both symbolically
                                                      the same.</div>
                                                    <div>I am debugging
                                                      this exception at
                                                      the moment.</div>
                                                    <div> </div>
                                                    <div>Thanks,</div>
                                                    <div>
                                                      <div>
                                                        <div dir="ltr" class="gmail_signature">
                                                          <div dir="ltr">-
                                                          Ashutosh Mehra</div>
                                                        </div>
                                                      </div>
                                                      <br>
                                                    </div>
                                                  </div>
                                                </div>
                                                <br>
                                                <div class="gmail_quote">
                                                  <div dir="ltr" class="gmail_attr">On
                                                    Wed, Sep 11, 2024 at
                                                    6:03 AM Andrew Dinn
                                                    <<a href="mailto:adinn@redhat.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">adinn@redhat.com</a>> wrote:<br>
                                                  </div>
                                                  <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Oops,
                                                    sorry, I debugged
                                                    this a few days ago!
                                                    Correction to a few
                                                    details:<br>
                                                    <br>
                                                    On 11/09/2024 10:39,
                                                    Andrew Dinn wrote:<br>
                                                    > A crash due to
                                                    an NPE was observed
                                                    in the Infinispan
                                                    (Data Grid) server <br>
                                                    > app when
                                                    deployed using the
                                                    Leyden EA. The crash
                                                    still manifests with
                                                    <br>
                                                    > the latest
                                                    premain code. The
                                                    crash happens below
                                                    an application call
                                                    <br>
                                                    > which employs a
                                                    method reference as
                                                    argument<br>
                                                    > <br>
                                                    >         
                                                    putMakedPasswordImplementations(this::putService,
                                                    this);<br>
                                                    <br>
                                                    The called method in
                                                    turn calls
                                                    consumer.accept<br>
                                                    <br>
                                                               
                                                     consumer.accept(new
                                                    Service(provider, <br>
PASSWORD_FACTORY_TYPE, algorithm, <br>
"org.wildfly.security.password.impl.PasswordFactorySpiImpl", emptyList,
                                                    <br>
                                                    emptyMap));<br>
                                                    <br>
                                                    which enters enters
MethodHandleNative::linkDynamicConstant()<br>
                                                    <br>
                                                    > Debugging shows
                                                    that the call to
                                                    linkDynamicConstant()
                                                    returns null.<br>
                                                    > <br>
                                                    > A simple
                                                    reproducer for the
                                                    problem is available
                                                    as a maven project
                                                    on <br>
                                                    > github:<br>
                                                    > <br>
                                                    >    <a href="https://urldefense.com/v3/__https://github.com/tristantarrant/elytron-leyden__;!!ACWV5N9M2RV99hQ!MnS3LSY2PXCCXbHvdyMfR6Nj57XH7Ey7aZuOLmQ__hhE_RhUrKnkzZ0uP8AwLZYcl8lAhhZaZr1akQ$" rel="noreferrer" target="_blank" moz-do-not-send="true">https://github.com/tristantarrant/elytron-leyden</a><br>
                                                    > <br>
                                                    > The ReadMe
                                                    provides an
                                                    explanation of how
                                                    to reproduce the
                                                    problem. I <br>
                                                    > did so and the
                                                    debugged to find out
                                                    some of the details
                                                    of what is <br>
                                                    > happening (see
                                                    below) but did not
                                                    fully clarify the
                                                    problem. Help from <br>
                                                    > someone more
                                                    conversant with the
                                                    ins and outs of
                                                    method handle <br>
                                                    > bootstraps in
                                                    premain would be
                                                    welcome. Details
                                                    follow.<br>
                                                    > <br>
                                                    > regards,<br>
                                                    > <br>
                                                    > <br>
                                                    > Andrew Dinn<br>
                                                    > -----------<br>
                                                    > <br>
                                                    > I downloaded
                                                    the git repo and
                                                    attached the Java
                                                    sources using Maven
                                                    command<br>
                                                    > <br>
                                                    >    $ mvn
                                                    dependency:sources<br>
                                                    > <br>
                                                    > Having
                                                    manifested the crash
                                                    by following the
                                                    instructions in the
                                                    README <br>
                                                    > I reran the
                                                    leyden JVM under gdb
                                                    using the following
                                                    commands to enable <br>
                                                    > Java debugging<br>
                                                    > <br>
                                                    > $ gdb
                                                    ${LEYDEN_HOME}/bin/java<br>
                                                    > (gdb) cd
                                                    /path/to/mvn/project<br>
                                                    > (gdb) run <br>
                                                    >
                                                    -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
                                                    <br>
                                                    > -classpath <br>
                                                    >
/home/adinn/redhat/openjdk/infinispan/elytron-leyden/base/target/elytron-leyden-base-0.0.1-SNAPSHOT.jar:/home/adinn/.m2/repository/org/wildfly/security/wildfly-elytron-credential/<a href="https://urldefense.com/v3/__http://2.5.1.__;!!ACWV5N9M2RV99hQ!MnS3LSY2PXCCXbHvdyMfR6Nj57XH7Ey7aZuOLmQ__hhE_RhUrKnkzZ0uP8AwLZYcl8lAhhauJ-RjcQ$" target="_blank" moz-do-not-send="true">2.5.1.</a>Final/wildfly-elytron-credential-2.5.1.Final.jar:/home/adinn/.m2/repository/org/wildfly/security/wildfly-elytron-base/2.5.1.Final/wildfly-elytron-base-2.5.1.Final.jar
-XX:CacheDataStore=elytron.aot com.redhat.leyden.Main<br>
                                                    > <br>
                                                    > The problem
                                                    manifests at
                                                    WildflyElytronBaseProvider.java:112
                                                    in method <br>
                                                    >
                                                    WildflyElytronBaseProvider::putMakedPasswordImplementations<br>
                                                    <br>
                                                         static void
                                                    putMakedPasswordImplementations(Consumer<Service>
                                                    <br>
                                                    consumer, Provider
                                                    provider) {<br>
                                                             for (String
                                                    algorithm :
                                                    MASKED_ALGORITHMS) {<br>
                                                               
                                                     consumer.accept(new
                                                    Service(provider, <br>
PASSWORD_FACTORY_TYPE, algorithm, <br>
"org.wildfly.security.password.impl.PasswordFactorySpiImpl", emptyList,
                                                    <br>
                                                    emptyMap)); <==
                                                    NPE under this call<br>
                                                             }<br>
                                                    <br>
                                                    <br>
                                                    > The source code
                                                    for this method can
                                                    be found in the
                                                    following source jar<br>
                                                    > <br>
                                                    > <br>
                                                    >
${M2_REPO}/org/wildfly/security/wildfly-elytron-base/2.5.1.Final/wildfly-elytron-base-2.5.1.Final-sources.jar<br>
                                                    > <br>
                                                    > (where M2_REPO
                                                    will normally be
                                                    ~/.m2/repository)<br>
                                                    > <br>
                                                    > Stepping into
                                                    accept eventually
                                                    enters
                                                    MethodHandleNative::linkDynamicConstant
                                                    <br>
                                                    > which in turn
                                                    enters into
                                                    ConstantBootstraps.makeConstant().
                                                    The caller <br>
                                                    > Class at this
                                                    point is a lambda
                                                    class which prints
                                                    as <br>
                                                    >
                                                    org.wildfly.security.WildflyElytronBaseProvider$$Lambda/0x800000000c<br>
                                                    > <br>
                                                    > Several steps
                                                    further the code
                                                    enters
                                                    BootstrapMethodInvoker::invoke
                                                    <br>
                                                    > (below the app
                                                    method call but via
                                                    3 hidden frames)
                                                    with bootstrapMethod
                                                    <br>
                                                    > bound to a
                                                    DirectMethodHandle.
                                                    After several more
                                                    steps this enters <br>
                                                    >
                                                    DirectMethodHandle$Holder.invokeStatic
                                                    which in turn calls
                                                    <br>
                                                    >
                                                    MethodHandles::classData(Lookup,String,Class).<br>
                                                    > <br>
                                                    > At this point
                                                    caller is a
                                                    MethodHandleLookup
                                                    for the lambda class
                                                    <br>
                                                    >
                                                    Lambda/0x800000000c
                                                    mentioned above. The
                                                    following call<br>
                                                    > <br>
                                                    >          
                                                    Object classdata =
                                                    classData(caller.lookupClass());<br>
                                                    > <br>
                                                    > returns null to
DirectMethodHandle$Holder.invokeStatic which pops the <br>
                                                    > same result
                                                    back out to
BootstrapMethodInvoker::invoke at line 90<br>
                                                    > <br>
                                                    > 
                                                                    if
                                                    (type instanceof
                                                    Class<?> c) {<br>
                                                    > 
                                                                       
                                                    result =
                                                    bootstrapMethod.invoke(caller,
                                                    name, c); <br>
                                                    > <== null<br>
                                                    > <br>
                                                    > This null
                                                    result pops back out
                                                    as the value for the
                                                    call to <br>
                                                    >
                                                    BootstrapMethodInvoker.invoke(),
ConstantBootstraps.makeConstant() and <br>
                                                    >
                                                    MethodHandleNative::linkDynamicConstant().<br>
                                                    > <br>
                                                    <br>
                                                  </blockquote>
                                                </div>
                                              </blockquote>
                                            </div>
                                          </blockquote>
                                        </div>
                                      </blockquote>
                                    </div>
                                  </blockquote>
                                </div>
                              </blockquote>
                            </div>
                          </blockquote>
                        </div>
                      </blockquote>
                    </blockquote>
                  </div>
                </blockquote>
              </div>
            </blockquote>
          </div>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>