Annotating lambda expressions
Remi Forax
forax at univ-mlv.fr
Sun Jul 12 17:19:43 UTC 2015
On 07/12/2015 07:00 PM, Ron Pressler wrote:
> Yes, but only method definitions, not method bodies; that's a very big
> difference.
yes, very true,
note that you only need to read the method body of methods that uses an
invokedynamic.
while there is no way to know if a method uses an invokedynamic, without
reading all the instructions but in the class:
- the constant pool will contain at least one
CONSTANT_Invokedynamic_info entry,
- the attributes of the class will contain a BootstrapMethods attribute.
that said, both these info are not exposed publicly by ASM.
Rémi
[1]
http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.10
[2]
http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23
>
>
> On Sat, Jul 11, 2015 at 4:39 PM, Remi Forax <forax at univ-mlv.fr
> <mailto:forax at univ-mlv.fr>> wrote:
>
> On 07/11/2015 03:02 PM, Ron Pressler wrote:
>>
>> On Sat, Jul 11, 2015 at 3:59 PM, Ron Pressler
>> <ron at paralleluniverse.co <mailto:ron at paralleluniverse.co>> wrote:
>>
>> Thanks for the bootstrap argument tip! Will use that as a
>> workaround.
>>
>>
>> ... although it does require scanning the entire bytecode for the
>> entire project (to find the indy callsites) rather than just
>> looking for annotated methods...
>
> ??
> finding annotated methods requires to scan the entire project too ?
>
>
>>
>> R
>
> R
>
>>
>> On Sat, Jul 11, 2015 at 12:26 PM, Remi Forax
>> <forax at univ-mlv.fr <mailto:forax at univ-mlv.fr>> wrote:
>>
>> On 07/11/2015 10:57 AM, Ron Pressler wrote:
>>> That's a very nice idea (in fact, we can do
>>> foo((@Special Runnable) ()->{...}), as well and get ASM
>>> to invoke a nice visitInsnAnnotation event), but it
>>> doesn't help, as I have no way of finding the method
>>> implementing the lambda by analyzing the bytecode.
>>
>> The method corresponding to the body of the lambda is one
>> arguments of the bootstrap method of invokedynamic.
>> see
>> http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html
>> <http://cr.openjdk.java.net/%7Ebriangoetz/lambda/lambda-translation.html>
>> (this translation scheme is not required to be used by
>> compilers but in practice javac and ecj uses it and
>> scalac will use it too)
>>
>>> My suggestion says, "however the compiler chooses to
>>> represent the lambda, please apply the annotation to the
>>> implementing method, wherever it is". I think that the
>>> language spec at least implicitly forces the compiler to
>>> implement a lambda as a method /somewhere/ (as opposed
>>> to, say, javac inlining the expression, as Kotlin does
>>> with inline functions).
>>
>> see above.
>>
>>>
>>> The ability to attach introspectable metadata to a
>>> lambda expression that then travels with it to the
>>> implementing method -- wherever the compiler may choose
>>> to place it -- is extremely useful, and trumps, IMO,
>>> "purity" concerns re annotating expressions vs
>>> declarations, (esp. since we've already established that
>>> some expressions -- like cast and new -- are
>>> annotatable, and rightly so).
>>
>> cast and new are not annotatable, the type of a cast or a
>> new are.
>>
>>> Without this, we miss something important Java gives us,
>>> which is the ability to attach metadata to a method
>>> body. I fully understand the distinction that the
>>> annotation is applied to the /declaration/ rather than
>>> the body itself, but that doesn't take away from the
>>> fact that a useful ability does not transfer to lambdas
>>> while it could be easily done.
>>>
>>> Ron
>>
>> Rémi
>>
>>
>>>
>>> On Sat, Jul 11, 2015 at 10:38 AM, Remi Forax
>>> <forax at univ-mlv.fr <mailto:forax at univ-mlv.fr>> wrote:
>>>
>>> On 07/10/2015 11:41 PM, Ron Pressler wrote:
>>>> I see no problem with cast annotations not being
>>>> retrievable via straightforward reflection just as
>>>> I see no problem annotating the generated method
>>>> (which should always exist /somewhere/): in both
>>>> cases, those annotations are intended for use by
>>>> tools that analyze the entire project's
>>>> source/bytecode (e.g. for
>>>> typechecking/instrumentation) rather than by
>>>> specific reflective queries.
>>>>
>>>> What bothers me is that a capability that was
>>>> trivial with inner classes is now lost when using
>>>> lambdas.
>>>
>>> you can easily add a pattern recognizable by
>>> source/bytecode tools to do what you want,
>>> let suppose you have a static method like this:
>>> static <T> T annotate(Class<? extends Annotation>
>>> annotation, T lambda) { return lambda; }
>>>
>>> to annotate a lambda, your example can be written
>>> like this:
>>> foo(annotate(Special.class, () -> { ...}))
>>>
>>> in the bytecode it will be translated to something
>>> like this:
>>> ldc Special.class
>>> invokedynamic ()Runnable
>>> LambdaMetafactory + method handle ref on the lambda body
>>> invokestatic Bar.annotate(Class, Object)Object
>>> checkcast Runnable
>>> invokevirtual Baz.foo(Runnable)...
>>>
>>> which is easy to recognize.
>>>
>>>>
>>>> Ron Pressler
>>>> paralleluniverse.co <http://paralleluniverse.co/>
>>>> @puniverseco <https://twitter.com/puniverseco> on
>>>> Twitter
>>>
>>> Rémi
>>>
>>>
>>>>
>>>> On Fri, Jul 10, 2015 at 10:38 PM, Alex Buckley
>>>> <alex.buckley at oracle.com
>>>> <mailto:alex.buckley at oracle.com>> wrote:
>>>>
>>>> On 7/10/2015 2:31 AM, Maurizio Cimadamore wrote:
>>>>
>>>> On 10/07/15 09:43, Ron Pressler wrote:
>>>>
>>>> (Related to
>>>> http://mail.openjdk.java.net/pipermail/compiler-dev/2015-January/009220.html)
>>>>
>>>> It is useful to add an annotation to a
>>>> lambda expression -- as in
>>>> foo(@Special () -> { ...}) -- which
>>>> will be applied to the static
>>>> method implementing the lambda (not to
>>>> the interface the lambda
>>>> implements). This would allow
>>>> instrumentation tools operating on
>>>> method implementations to handle
>>>> lambdas. So far, AFAICT, this is not
>>>> possible (or am I wrong?).
>>>>
>>>> This is not possible, currently - as Remi
>>>> said; you have annotations on
>>>> declarations (i.e. variable, classes,
>>>> methods) - you have annotation on
>>>> types (i.e. type of a cast, type argument,
>>>> etc.) - but you don't have
>>>> annotations on _expressions_.
>>>> I take it that, under the current
>>>> translation scheme, there seems to be
>>>> a plausible description for what should
>>>> happen when the lambda is
>>>> annotated; but what if the lambda is turned
>>>> into a method reference (by
>>>> some IDE refactoring, or human
>>>> intervention) ? In that case it is not
>>>> guaranteed that there would still be a
>>>> physical place where to put the
>>>> annotation (unless we tell the compiler to
>>>> 'expand' all annotated method
>>>> references).
>>>>
>>>>
>>>> Yes, the problem with
>>>> annotations-on-expressions is not the language
>>>> grammar but the storage of the annotations in
>>>> the class file. With no standard way of
>>>> translating source expressions to bytecode,
>>>> there can be no standard API for retrieving
>>>> annotations-on-expressions from bytecode. More
>>>> broadly, there has never been a standard
>>>> reflective API capable of inspecting method bodies.
>>>>
>>>> This explains why JSR 308 stayed away from
>>>> annotations-on-expressions -- we were not in a
>>>> position to let them be read back. It was
>>>> already bad enough that some
>>>> annotations-on-types are stored in the class
>>>> file at the level of individual bytecodes (e.g.
>>>> an annotation on the type of a cast) so are not
>>>> retrievable by any standard reflective API.
>>>>
>>>> Alex
>>>>
>>>>
>>>
>>>
>>
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150712/97c89221/attachment-0001.html>
More information about the compiler-dev
mailing list