<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">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.<br clear="all"></blockquote><div><br></div><div>I verified that this change fixes the error in the testcase. Thanks for fixing this issue.</div><div><br></div><div>- Ashutosh Mehra<br></div><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Sep 24, 2024 at 1:01 PM <<a href="mailto:ioi.lam@oracle.com">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"><u></u>
<div>
<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 href="https://github.com/iklam/jdk/commit/df72d0ba8dc799767521c939a531c4128e58c636" target="_blank">https://github.com/iklam/jdk/commit/df72d0ba8dc799767521c939a531c4128e58c636</a><br>
</p>
<p>Thanks</p>
<p>- Ioi<br>
</p>
<p><br>
</p>
<p><a href="https://github.com/iklam/jdk/commit/df72d0ba8dc799767521c939a531c4128e58c636" target="_blank">https://github.com/iklam/jdk/commit/df72d0ba8dc799767521c939a531c4128e58c636</a><br>
</p>
<div>On 9/24/24 8:24 AM, Ashutosh Mehra
wrote:<br>
</div>
<blockquote type="cite">
<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$" target="_blank">https://github.com/ashu-mehra/leyden-testcase/</a></div>
<div><br>
</div>
<div>Thanks,<br>
<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 Mon, Sep 23, 2024 at
11:24 PM <<a href="mailto:ioi.lam@oracle.com" target="_blank">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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">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_5728834885895654793m_-8594911495544208436m_-6235568143876299380m_5385423560619785655m_-6081196208708063630m_-8326742188757259955m_-669397441264475055m_4538222356731470316m_-1862706623606286828plusReplyChip-0" href="mailto:ioi.lam@oracle.com" target="_blank">@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">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">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">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">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">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">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">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>
</div>
</blockquote></div>