Hi Rafael, why not providing a LambdaInterceptor as asked ? My point is that a lambda should be considered as a feature by itself instead as a way to create a class that implement an interface at runtime. If you do that, your code will still work when future release (maybe a point release), the implementation of the lambda proxy class will change.
BTW, i maybe wrong, but as far as remember, the first release of Java 8 was not using vm anonymous classes for lambdas. regards, Rémi ----- Mail original ----- > De: "Rafael Winterhalter" <rafael....@gmail.com> > À: "Rémi Forax" <fo...@univ-mlv.fr> > Cc: "Vladimir Ivanov" <vladimir.x.iva...@oracle.com>, "Coleen Phillimore" > <coleen.phillim...@oracle.com>, > core-libs-dev@openjdk.java.net, "serguei.spit...@oracle.com Spitsyn" > <serguei.spit...@oracle.com>, "Daniel > Daugherty" <daniel.daughe...@oracle.com> > Envoyé: Mardi 26 Janvier 2016 10:30:54 > Objet: Re: ClassFileTransformer does not apply to anonymous classes > > Maybe this is a more graphic example of a problem that end-users > currently face: > http://stackoverflow.com/questions/33912026/intercepting-calls-to-java-8-lambda-expressions-using-byte-buddy > > 2016-01-26 10:02 GMT+01:00 <fo...@univ-mlv.fr>: > > Hello, > > > > ----- Mail original ----- > >> De: "Rafael Winterhalter" <rafael....@gmail.com> > >> À: "Remi Forax" <fo...@univ-mlv.fr> > >> Cc: "Vladimir Ivanov" <vladimir.x.iva...@oracle.com>, "Coleen Phillimore" > >> <coleen.phillim...@oracle.com>, > >> core-libs-dev@openjdk.java.net, "serguei.spit...@oracle.com Spitsyn" > >> <serguei.spit...@oracle.com>, "Daniel > >> Daugherty" <daniel.daughe...@oracle.com> > >> Envoyé: Lundi 25 Janvier 2016 20:24:01 > >> Objet: Re: ClassFileTransformer does not apply to anonymous classes > >> > >> Hi Vladmir, hello Remi, > >> > >> 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. > > > > The lambda body is analyzed because the body is translated to a static > > method (which can be non static BTW) which is part of the class that uses > > the lambda. > > The lambda proxy is a runtime artifact and the way it is currently > > implemented will likely to change in the future, using a vm anonymous > > class is a workaround of the fact that there is currently no way to load a > > function/method without a class. You should not try to analyze the lambda > > proxy, it doesn't contain codes but it's a straw glue between the > > interface and the body of the lambda. > > > >> > >> 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. > > > > The invokedynamic corresponding to a lambda creation contains a link to the > > private method, it's i believe all you need, but i'm not sure because what > > you're doing exactly is fuzy for me. > > > >> > >> 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. > > > > again, there is no such thing as a lambda class, trying to see a lambda as > > an anonymous class will never fully work. > > a lambda is a lambda, you have the link between the functional interface > > and the lambda body encoded into the invokedynamic which is used to create > > the lambda, you should not try to get more information, because as i said, > > it may change. > > > >> > >> 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. > > > > yes, private is enough but it's not a big deal. > > > >> > > > > regards, > > Rémi > > > >> > >> 2016-01-23 13:55 GMT+01:00 Remi Forax <fo...@univ-mlv.fr>: > >> > 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] > >> > http://asm.ow2.org/asm50/javadoc/user/org/objectweb/asm/ClassWriter.html#ClassWriter%28org.objectweb.asm.ClassReader,%20int%29 > >> > > >> > ----- Mail original ----- > >> >> De: "Vladimir Ivanov" <vladimir.x.iva...@oracle.com> > >> >> À: "Rafael Winterhalter" <rafael....@gmail.com> > >> >> Cc: "Coleen Phillimore" <coleen.phillim...@oracle.com>, > >> >> core-libs-dev@openjdk.java.net, "serguei.spit...@oracle.com > >> >> Spitsyn" <serguei.spit...@oracle.com>, "Daniel Daugherty" > >> >> <daniel.daughe...@oracle.com> > >> >> 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) { r.run(); } > >> >> 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 > >> >> > >> >