<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://github.com/ashu-mehra/leyden-testcase/">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">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>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://github.com/iklam/jdk/commit/eafaa9731ae89b93f3e20702fc4d5a12cb070149" 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://github.com/tristantarrant/elytron-leyden" 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://github.com/iklam/jdk/blob/5cc31ed60cc9597d63b86f20b95c964d4d1a6b84/src/hotspot/share/cds/aotClassInitializer.cpp#L66-L84" 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_-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>