Implementing MethodHandleProxies#asInterfaceInstance with hidden classes

- liangchenblue at gmail.com
Wed Aug 25 12:05:50 UTC 2021


Thanks Remi,
I strongly agree. In fact, with the ability to implement multiple
methods in an invoke proxy (presumably through passing a list of name
and handle pairs, and the impl method descriptors are stored in
handles' method types), we can allow implementing any number of
interfaces (even ones with language-wise conflicting methods like
String getValue() and Long getValue()) and perform better
initialization-time verifications (compared to invocation handlers,
where users often forget to implement object methods and the proxy
breaks only when it is sent into a hash set)

My current vision is a proxy factory method that takes a list of
interfaces and a list of method implementations, each represented by a
pair of name and method handle. However, I don't know well about
native compilation, so I wonder if this structure would serve native
optimization well, or if it has any other drawbacks. Please enlighten
me.

On Wed, Aug 25, 2021 at 5:22 AM Remi Forax <forax at univ-mlv.fr> wrote:
>
> ----- Original Message -----
> > From: "-" <liangchenblue at gmail.com>
> > To: "Brian Goetz" <brian.goetz at oracle.com>, "core-libs-dev" <core-libs-dev at openjdk.java.net>
> > Sent: Lundi 23 Août 2021 08:34:17
> > Subject: Re: Implementing MethodHandleProxies#asInterfaceInstance with hidden classes
>
> > Thanks for the quick reply!
> >
> > The main drawback, API wise, with LMF is that it does not accept
> > non-direct method handles [1], while the MHP is able accept any method
> > handle, such as native ones from JEP 389 [2]. LMF also lacks the
> > ability to restore a method handle from a wrapper instance. Using LMF
> > also requires user discretion on which methods to implement, and the
> > lookup's required privileges may change too. In general, MHP would be
> > more runtime-oriented and transient compared to LMF.
> >
> > I am inclined toward a separate bytecode generation implementation for
> > the improved MHP asInterfaceInstance, somewhat similar to what's in
> > JEP 416's implementation [3]. The extra bridges for all compatible
> > methods, accessors to backing method handle/interface, potential to
> > expand to abstract classes, different hidden class modes would reduce
> > the commonalities between the two implementations and make
> > refactorings on LMF to support these MHP functionalities costly.
>
> In my opinion, what is missing is a java.lang.invoke.Proxy, the equivalent of java.lang.reflect.Proxy but using defineHiddenClass + a bootstrap method + method handles instead of the InvocationHandler + j.l.r.Method. With that, implementing java.lang.invoke.MethodHandleProxies on top of of java.lang.invoke.Proxy is just a matter of wiring.
>
> As you said, there is a need for a more dynamic version of the LambdaMetafactory.
> I believe it should work with any interfaces not only functional interfaces.
> This would avoid statically typed langages like Kotlin or Scala, or injection frameworks like Weld, Spring or Guice to generate a lot of proxy classes and it should be straightforward enough so static compilers like graal native image or Android d8 can generate the proxy classes at compile time to support "native" compilation (the same way lambdas are currently supported).
> So we get best of both worlds, efficient dynamic proxies at runtime AND supports of "native" compilation.
>
> Rémi
>
> >
> > [1]
> > https://github.com/openjdk/jdk/blob/b690f29699180149d33b6a83de10697790587a87/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java#L141
> > [2] https://openjdk.java.net/jeps/389#The-C-linker
> > [3]
> > https://github.com/openjdk/jdk/blob/cff856f9df89293cbc8f2f1e977148cd6ece4f85/src/java.base/share/classes/jdk/internal/reflect/ClassByteBuilder.java
> >
> >
> > On Sun, Aug 22, 2021 at 9:26 PM Brian Goetz <brian.goetz at oracle.com> wrote:
> >>
> >> This was an early attempt at the functionality provided by LambdaMetafactory.
> >> It could probably be reimplemented on top of that, but probably could be
> >> deprecated in favor of LMF as well.
> >>
> >> Sent from my iPad
> >>
> >> > On Aug 22, 2021, at 10:08 PM, liangchenblue at gmail.com wrote:
> >> >
> >> > Currently, java.lang.invoke.MethodHandleProxies#asInterfaceInstance [1] is
> >> > implemented with java.lang.reflect.Proxy. After looking at its public API,
> >> > including Javadoc, it seems that MethodHandleProxies would benefit from a
> >> > hidden class implementation without changing its public API definition
> >> > (including Javadocs).
> >> >
> >> > Recently, there is JEP 416 [2] for reimplementing reflection based on
> >> > method handles. This implementation utilizes hidden classes with method
> >> > handles passed in classdata and retrieved to condy, which allows generic
> >> > method handles (beyond regular constable ones) to be optimized in method
> >> > calls. Similarly, for MethodHandleProxies, hidden classes allow the
> >> > implementations to detach from classloaders and be freely recyclable; they
> >> > can use class data to store the adapted method handles (which can
> >> > significantly speed up invocations); and it can allow it to support
> >> > implementing single-abstract-method abstract classes in the future (as
> >> > discussed in its Javadoc) as well, with only minor tweaks.
> >> >
> >> > Does this sound feasible? I want to ensure it is a good idea before any
> >> > implementation is attempted. If there is any issue with this vision, please
> >> > don't hesitate to point it out. Feel free to comment, too! If this looks
> >> > good, I hope an issue can be created for it.
> >> >
> >> > Best
> >> >
> >> > [1]
> >> > https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/invoke/MethodHandleProxies.html
> > > > [2] https://openjdk.java.net/jeps/416


More information about the core-libs-dev mailing list