Hi Johannes,
I'm glad to see this prototype. Converting dynamic proxy to hidden
classes has a few challenges as JDK-8242888 describes.
1) the serialization specification w.r.t. dynamic proxies
We need to look into the implication to the specification and whether
the default serialization mechanism should (or should not) support
dynamic proxies if it's defined as hidden classes.
2) how to get a Lookup on a package for the dynamic proxy class to be
injected in without injecting a shim class (i.e. your anchor class)?
Frameworks don't always have the access to inject a class in a package
defined to a class loader. Dynamic proxies are a use case to determine
what functionality is needed to avoid spinning a shim class.
3) protection domain
The current spec of Proxy class is defined with null protection domain
(same protection domain as the bootstrap class loader).
Lookup::defineHiddenClass defines the hidden class in the same
protection domain as the defining class loader. This requires to
understand deeper the compatibility risks and what and how
applications/libraries depend on this behavior.
That's all the feedbacks I can share so far. We need to have a clear
idea w.r.t. serialization spec and compatibility risk to existing code
w.r.t. protection domain and explore other options.
W.r.t. AOT tests, AOT has been disabled in openjdk build [1] and that
may be the reason why these tests fail.
Mandy
[1] https://github.com/openjdk/jdk/pull/960
On 12/17/20 2:07 PM, Johannes Kuhn wrote:
Now that class data support for hidden classes in master, I decided to
tackle JDK-8229959 again.
JDK-8229959: Convert proxy class to use constant dynamic [1]
JDK-8242888: Convert dynamic proxy to hidden classes [2]
The idea is simple: Define proxies as hidden classes, pass the methods
as class data, and access it from the Proxy with the
MethodHandles.classDataAt() BSM.
The current prototype[3] works - and aside from one test for jshell
that expects a stack trace element containing "jdk.proxy" as a stack
trace element (hidden classes, duh), no new tests did fail with "make
test-tier1".
Also, the aot tests fail ("link.exe not found"), if someone has some
instructions how to get them properly run on windows, I'm very
interested. But they are not new failures.
Problems I did run into:
I need a lookup for a class in a package to define a hidden class.
---------------------------
Solution: I inject an anchor class, obtain a lookup on it, and use
that. The anchor is reused for the same package, and named pkg +
".$ProxyAnchor".
I need to return both the class data & created bytecode back to Proxy
from ProxyGenerator
---------------------------
Solution: Added a record-like class that contains both bytecode as
well as the class data.
Serialization of proxies did break.
---------------------------
Serializing the proxy descriptor was not a problem - the problem is
how the constructor for serialization works.
It spins a MagicConstructorAccessor subclass - which requires for the
created class to have a binary name. Hidden classes don't have one.
Solution: MethodHandles don't have this limitation, so I hacked a
shared secret into JavaLangInvokeAccess to create such a MethodHandle,
and replaced the Reflection.generateConstructor() implementation to
use a ConstructorAccessor that delegates to that MethodHandle.
---------------------------
In all, this is a prototype - for now, I want some feedback on the
approach. Also a broader view - making it work is one thing.
Checking all the right boxes in all the different areas an other.
Some parts might still be a bit sloppy, but I want to know if there is
merit if I follow the current path and polish it up.
- Johannes
PS.: I decided to use a draft PR - as with my last approaches I had
problems when I did commit more stuff.
[1]: https://bugs.openjdk.java.net/browse/JDK-8229959
[2]: https://bugs.openjdk.java.net/browse/JDK-8242888
[3]: https://github.com/openjdk/jdk/pull/1830/files