JDK-8025636 : Hide lambda proxy frames in stacktraces
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: svc
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-09-30
  • Updated: 2018-10-17
  • Resolved: 2015-02-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u60Fixed 9 b52Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
[From Brian Goetz]

public class Foo {
 public static void main(String[] args) {
   Runnable r = () -> { throw new RuntimeException(); };
   r.run();
 }
}

which produces:

Exception in thread "main" java.lang.RuntimeException
	at Foo.lambda$0(Foo.java:3)
	at Foo$$Lambda$1.run(Unknown Source)
	at Foo.main(Foo.java:4)

Here, Foo$$Lambda$1 is a synthetic class generated by the bootstrap of the lambda factory call site.  (Lambdas are created by invoking an invokedynamic callsite, which returns the lambda.  The bootstrap spins classes as necessary.)  

Ideally the user would want to see the calling line (r.run()) and the callee (the lambda) and nothing in between.
Comments
From: Alex Buckley <alex.buckley@oracle.com> Officially, annotations are not checked when a class file is loaded or verified. Core Reflection is the only actor who cares about the well-formedness of Runtime[In]VisibleAnnotations attributes + the accessibility of annotation types referenced therein. Practically, @java.lang.invoke.LambdaForm$Hidden is the second annotation that HotSpot cares to observe in a class file, along with @sun.misc.Contended. Because HotSpot detects these annotations in a very low level manner (string comparison), there's no issue of annotation type visibility or accessibility. More broadly, there is no problem with a JVM implementation taking quality-of-service hints from proprietary annotations, provided there's no change to user-visible linkage (which there isn't). Consider that prior to SE 5.0 introducing Runtime[In]VisibleAnnotations, we would have been using proprietary attributes for this kind of stuff, and JVMS 4.7.1 explicitly allowed that. [...] Alex
03-02-2015

From: John Rose <john.r.rose@oracle.com> ... Annotations like @Hidden amount to strings inside the classfile. They are not resolved and instances are not reified, unless you run reflective machinery. So why do anonymous classes (like LMF products) "hook up" to @Hidden? It is not the case that they need to access anything in java.lang.invoke; they just mention the string of the annotation name. Why isn't this a big security hole or attractive nuisance? Because the JVM ignores such annotations unless the loaded class is specifically trusted, on the boot class path or in an extension class loader. And anonymous classes also have the privilege of mentioning annotations like @Hidden and having the JVM "listen". The relevant line of code is: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/file/8ff882030755/src/share/vm/classfile/classFileParser.cpp#l1772 This is not an accessibility test, it is rather a significance test: Is the JVM willing to accept a mention of one of the internally significant annotations? If we ever let untrusted users create anonymous classes, we will have to re-evaluate this policy (and sharpen it). But I think we won't do that. ��� John
03-02-2015

Proposed patch: diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -295,6 +295,7 @@ new ForwardingMethodGenerator(mv).generate(mt); } } + mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true); if (isSerializable) generateSerializationFriendlyMethods();
30-01-2015

So I modified java.lang.invoke.InnerClassLambdaMetafactory.spinInnerClass() to add the Ljava/lang/invoke/LambdaForm$Hidden; annotation to the SAM method. I thought this would result in some kind of class loading problem since Ljava/lang/invoke/LambdaForm$Hidden; is not accessible outside java/lang/invoke/LambdaForm, but it didn't. I don't know if this is a bug or a feature? The only place where we look for the annotation is inside the JVM and there we don't care about accessibility, so it may be that this is ok. The frame was removed from the stack trace.
29-01-2015

[~sla] That sounds like the right move.
22-01-2015

Making it accessible would change the exported API for java.lang.invoke. Can we use an new, accessible annotation in a less public package? Something in the jdk.runtime module?
22-01-2015

I'm happy to do the LambdaForm$Hidden route on the generated proxy class, exception that LambdaForm$Hidden is not accessible.
16-01-2015

Based on Brian's comments here and in 8016334 it seems that the desire is to hide them all. But that seems undesirable as well - as you show above all you see is: Exception in thread "main" java.lang.RuntimeException at Foo.main(Foo.java:4) which doesn't tell you where in run() the exception happened. Unfortunately we are in new territory here. The current implementation strategy for lambda's introduces synthetic methods all the way through but it seems some would be useful in the stacktrace - as per 8016334, and really as in this case. So we do have to special case things (the same way reflection special cases the stacktrace elements). Bottom line: this seems to be a dup of 8016334 and the methods to be hidden need to be annotated as such. Brian: need some follow up from you on this :)
03-10-2013

That would work, but feels like a special case. It's not going to be obvious from reading the code why synthetic methods aren't hidden as well. I think I would prefer the suggestion in JDK-8016334 in that case.
03-10-2013

Wasn't Brian's original comment referring to the methods of a synthetic class, as opposed to just synthetic methods? So can we just hide synthetic class methods?
03-10-2013

Is it possible that lambda methods should not be regarded as synthetic? They are present in the source file, after all.
02-10-2013

So, hiding synthetic methods has the unfortunate side effect of hiding the actual lambda method in the above example. Foo.lambda$0 is marked as synthetic. The resulting stack trace is: Exception in thread "main" java.lang.RuntimeException at Foo.main(Foo.java:4) which is probably not what you want. I don't know how to hide Foo$$Lambda$1.run() but not Foo.lambda$0().
02-10-2013

There is already code in the JVM to hide methods which are annotated with java/lang/invoke/LambdaForm$Hidden. These can be forced to show up with -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames. There is also a bug for using this annotation on the synthetic lambda method: JDK-8016334. The generated class above is marked synthetic, and it would be more general to hide all synthetic frames. I am suggesting that we do the following: - Set Method:is_hidden() for all synthetic methods (and methods in synthetic classes). This will cause these frames to be removed from Java stack traces (unless +ShowHiddenFrames). - Change the thread dump (Threads::print_on) to also respect Method::is_hidden() (unless +ShowHiddenFrames). - Change the Diagnostic Command "Thread.print" to include an option to print hidden frames (overrides ShowHiddenFrames)
30-09-2013