ClassFileTransformer does not apply to anonymous classes

Vladimir Ivanov vladimir.x.ivanov at
Tue Jan 26 12:29:30 UTC 2016

> what bothers me about instrumenting a lambda expression's target
> method is the difficulty of locating the method that contains the code
> and setting it into context. This is a lot of work to do since one
> needs to first locate any invokedynamic call sites and interpret the
> connection via the LambdaMetafactory. This is difficult to instrument
> without greater efforts and does not feel like a clean solution.
> Many real life instrumentations are based on the assumption of being
> able to instrument any class of a given subtype or other any other
> class property. For example, one would want to instrument any class
> that implements InputStream to discover a resource leak. If the
> interface is however functional and implemented as a lambda
> expression, a tool that manipulating all class files of this type
> stops working. At the same time, end users do not really understand
> the difference of their former anonymous class that is now expressed a
> lambda expression and perceive the beaviour as a regression.
I agree, it becomes more complex without the ability to instrument any 
class: not only you have to enumerate all loaded lasses, but also 
inspect all lambda expressions. It means dedicated support for lambda 
expressions, but IMO the complications are far from insurmountable and 
makes the design cleaner. Otherwise, you have to support reliable 
instrumentation of VM anonymous classes, which is harder (again, IMO).

Also, you still need dedicated support for lambdas to be able to 
instrument them individually. Ability to instrument VM anonymous classes 
doesn't cover that (only the case of instrument all classes fulfilling 
some requirement).

But I'd like to hear your opinion about that. Have you tried to 
instrument lambda expression bodies instead of tweaking 
LambdaMetafactory implementation?

> I have myself implemented a custom solution for my code generation
> library that instruments the LambdaMetafactory to apply class file
> transformers to these classes manually. This does however show two
> disadvantages:
> 1. javac creates the target method of a lambda expression as a private
> method. The only way to implement a lambda expression legally in byte
> code is by loading the generated implementation anonymously what
> requires non-public API. While it is possible to call
> Unsafe::defineAnonymousClass from the instrumented LambdaMetafactory,
> it is again required to use non-standardized APIs which might fail on
> differing implementations of the JVM.
No, U::dAC usage is just an implementation detail. It is not required 
for lambda expression support. What is crucial is the ability to 
construct appropriate method handle to the method which represents the 
body. That's where invokedynamic bootstrap methods helps. Lookup object 
(1st argument [1]) has enough privileges to construct method handles to 
any methods (even private) in the caller. After that you are free to 
decide how to wrap the method handle to the lambda body.

> 2. At the same time, there is no standardized way to receive all
> ClassFileTransformers that are currently registered on the VM. this
> also requires calls into internal APIs that are not necessarily
> supported on other platforms.
> I fully understand the hesitation to support this from a technical
> point of view but in reality, people are already dependant on this
> feature and disallowing the instrumentation of lambda classes will
> only inspire work-arrounds that reduce the stability of software using
> this APIs that does currently work without problems for non-lambda
> classes.
As your experience demonstrates, instrumentation support of VM anonymous 
classes is far from production quality. If anybody heavily relies on it, 
then they should face the same problems. But you are the first who 
stumbled upon and reported them. So, it seems we are lucky and can 
decide what is the correct behavior (and not just stick with how it 
works now).

> Best regards, Rafael
> PS: While implementing my solution, I found that the LambdaMetafactory
> of the Open JDK creates private, final methods for the serialization
> bits. The methods should however not be final as they are already
> private.
There's no such thing as too much safety, right? ;-)

Best regards,
Vladimir Ivanov

[1] public class LambdaMetafactory {

public static CallSite metafactory(
   MethodHandles.Lookup caller,
   String invokedName,
   MethodType invokedType,
   MethodType samMethodType,
   MethodHandle implMethod,
   MethodType instantiatedMethodType)

> 2016-01-23 13:55 GMT+01:00 Remi Forax <forax at>:
>> I agree with Vladimir,
>> You should not be able to transform/redefine a VM anonymous class because the transformer will certainly mess up with the order of the constant pool entries.
>> Slightly off-topic, about ASM, when you create a ClassWriter [1], you can pass a ClassReader of an existing class, in that case ASM copy the constant pool from the class reader to the class writer so the constant pool is preserved.
>> Rémi
>> [1],%20int%29
>> ----- Mail original -----
>>> De: "Vladimir Ivanov" <vladimir.x.ivanov at>
>>> À: "Rafael Winterhalter" <rafael.wth at>
>>> Cc: "Coleen Phillimore" <coleen.phillimore at>, core-libs-dev at, "serguei.spitsyn at
>>> Spitsyn" <serguei.spitsyn at>, "Daniel Daugherty" <daniel.daugherty at>
>>> Envoyé: Vendredi 22 Janvier 2016 18:47:31
>>> Objet: Re: ClassFileTransformer does not apply to anonymous classes
>>> Rafael,
>>> First of all, I'd like to agree on the terminology. There's some
>>> confusion there. Anonymous term is ambiguous in Java. There are
>>> anonymous classes on language level and there's
>>> Unsafe.defineAnonymousClass() which produce anonymous-in-VM-sense
>>> classes. I prefer to call them VM anonymous classes to avoid confusion.
>>> I assume that whenever you use anonymous you assume "VM anonymous".
>>>> thank you for your response. While I completely understand your view
>>>> from a VM implementor's point of view, as a practicioner I would
>>>> recommend against it. Not being able to instrument lambda expressions
>>>> puts a severe limitation onto using the instrumentation API
>>>> alltogether. For example, a monitoring application that promises to
>>>> record all invocations of a method of a certain interface that only
>>>> works 95% of the time is not 5% less usefull but might no longer be
>>>> useful at all. People have build large applications based on the
>>>> assumption that all user application code can be instrumented and such
>>>> a regression would hurt them. For example, until today, over 30 people
>>>> that use my code generation framework reached out to me and reported
>>>> the reported behavior as a bug in my library and people are only
>>>> starting to migrate their applications to Java 8. The outcome is
>>>> simply not intuitive as using a lambda expression over an anonyous
>>>> inner class should not change an application's behavior.
>>> Can you elaborate on that point, please?
>>> I don't see any problems with instrumenting user code. Javac represents
>>> lambda expression body as a private static method of the enclosing
>>> class, which can be instrumented. VM anonymous classes are used only as
>>> a mechanism to glue functional interfaces and lambda expressions
>>> together at runtime.
>>> For example:
>>>      static void f(Runnable r) {; }
>>>      f(() -> {});
>>> Test::f (7 bytes)
>>>     @ 1   Test$$Lambda$1/791452441::run (4 bytes)   inline (hot)
>>>       @ 0   Test::lambda$main$0 (1 bytes)   inline (hot)
>>> Why do you need to instrument Test$$Lambda$1/... and not
>>> Test::lambda$main$0?
>>>> The currently used workaround that people use is to instrument the
>>>> LambdaMetaFactory class itself to apply the transformer manually when
>>>> it is being created. This solution is spreading as a standard approach
>>>> and I am sure that forbidding a redefinition alltogether would only
>>>> inspire to other workarrounds for being able to migrate running code
>>>> to the next Java version.
>>> It doesn't sound like a workaround, but as a solution for a different
>>> problem.
>>> If there's a need to gather profile for every lambda expression
>>> instantiation site (indy call), then redefining bootstrap method is the
>>> right way to go IMO. It allows to intercept and customize indy call site
>>> binding.
>>> What does sound as a workaround is an attempt to instrument classes
>>> produced by LambdaMetaFactory. Right now, it generates a fresh VM
>>> anonymous class on every request, but it is an implementation detail and
>>> not a requirement.
>>> For example, LambdaMetaFactory can reuse wrappers on per-functional
>>> interface basis. It would provide significant footprint savings for
>>> lambda expression-rich code bases (usually, there are much more
>>> instantiations than functional interface flavors).
>>>> Furthermore, I do not think that not being able to patch constant pool
>>>> indices in the generated code introduces any problems in practice.
>>>> Most real-world instrumentation only appends new constant pool entries
>>>> without interfering with the existant pool. Rather, I would like to
>>>> see an exception being raised if one attempts to change the original
>>>> constant pool without me being able to consider this from a technical
>>>> perspective. I think this would serve to be sufficient for most
>>>> people.
>>> If you care only about lambda expressions, then constant pool patching
>>> shouldn't be a problem (AFAIR it isn't used for lambda expressions). But
>>> in a more generic case (even for java.lang.invoke purposes), the
>>> coupling between class file and CP patches is very tight and can be
>>> easily broken with benign class file transformations. Considering ASM
>>> library, I'm not sure that even simple instrumentations preserve
>>> original constant pool structure.
>>> Probably, VM can do some structural checks on CP to forbid any
>>> modifications except appends, but there are still aliasing problems -
>>> sharing doesn't work (even for string constants), so new code shouldn't
>>> use original CP entries.
>>> I'd prefer to avoid such increase in complexity in VM implementation.
>>>> I really hope that there is a way to allow for patching anonymously
>>>> loaded classes even without exposing the constant pool patches.
>>>   From VM implementation perspective I don't see any problems with
>>> allowing class file redefinition for VM anonymous classes. What I want
>>> to do is to discourage from doing so. Again - it is very fragile and
>>> there's little we can do to fix that.
>>>> So far, thank you for looking into this. I am sure this a more complex
>>>> matter than what I am able to comprehend. I appreciate that you are
>>>> taking the time to consider my opinion!
>>> Best regards,
>>> Vladimir Ivanov

More information about the core-libs-dev mailing list