On Sun, 17 Apr 2022 16:17:30 GMT, liach <d...@openjdk.java.net> wrote:

> Convert dynamic proxies to hidden classes. Modifies the serialization of 
> proxies (requires change in "Java Object Serialization Specification"). Makes 
> the proxies hidden in stack traces. Removes duplicate logic in proxy building.
> 
> The main compatibility changes and their rationales are:
> 1. Modification to the serialization specification: In the "An instance of 
> the class is allocated... The contents restored appropriately" section, I 
> propose explicitly state that handling of proxies are unspecified as to allow 
> implementation freedom, though I've seen deliberate attempts for proxies to 
> implement interfaces with `readResolve` in order to control their 
> serialization behavior.
>    - This is for the existing generated constructor accessor is 
> bytecode-based, which cannot refer to hidden classes.
>    - An alternative is to preserve the behavior, where the serialization 
> constructor calls `invokespecial` on the closest serializable superclass' 
> no-arg constructor, like in #1830 by @DasBrain.
>    - My rationale against preservation is such super calls are unsafe and 
> should be discouraged in the long term. Calling the existing constructor with 
> a dummy argument, as in my implementation, would be more safe.
> 2. The disappearance of proxies in stack traces.
>    - Same behavior exists in lambda expressions: For instance, in 
> `((Runnable) () -> { throw new Error(); }).run();`, the `run` method, 
> implemented by the lambda, will not appear in the stack trace, and isn't too 
> problematic.
> 
> A summary of the rest of the changes:
> 1. Merged the two passes of determining module and package of the proxy into 
> one. This reduced a lot of code and allowed anchor class (for hidden class 
> creation) selection be done together as well.
> 2. Exposed internal API for obtaining a full-privileged lookup to the rest of 
> `java.base`. This API is intended for implementation of legacy (pre 
> `MethodHandles.Lookup`) caller sensitive public APIs so they don't need more 
> complex tricks to obtain proper permissions as lookups.
> 3. Implements [8229959](https://bugs.openjdk.java.net/browse/JDK-8229959): 
> passes methods computed by proxy generator as class data to the hidden proxy 
> class to reduce generated proxy class size and improve performance.
> 
> In addition, since this change is somewhat large, should we keep the old 
> proxy generator as well and have it toggled through a command-line flag (like 
> the old v49 proxy generator or the old reflection implementation)?
> 
> Please feel free to comment or review. This change definitely requires a CSR, 
> but I have yet to determine what specifications should be changed.

About deserializing Proxies, this is currently done in 3 steps:

1. Finding the class
2. Allocating a new instance and invoke the constructor of the **first 
non-serializable superclass**
3. Setting the fields of the instance

Only step 2 is problematic here:

1. For a proxy, the class is serialized using a TC_PROXYCLASSDESC. when 
deserialized it invokes `Proxy.getProxyClass` 
(https://github.com/openjdk/jdk/blob/13fb1eed52f1a9152242119969a9d4a0c0627513/src/java.base/share/classes/java/io/ObjectInputStream.java#L891).
  
    For this step, it doesn't matter if `Proxy.getProxyClass` returns a normal 
class or a hidden class.
2. Allocating and calling the constructor:  
     This part is currently implemented by spinning a class. The generated 
bytecode looks more or less like this:

        anew ProxyClass
        invokespecial Object.<init>()

    The big lie here is that methods and constructors are different - but 
constructors are just methods, and the verifier makes sure that a constructor 
is called only once, exactly once, and that uninitialized instances don't 
escape.

    This doesn't work for hidden classes - as the hidden class can not be named 
in an other class.  
    But MethodHandles can do this. Here is one of my old prototypes, based on a 
prototype for implementing reflection using MethodHandles from Mandy Chung: 
https://github.com/dasbrain/jdk/compare/ae45c5de7fc635df4dc86b764405158c245d2765...fbb0a63436f696a85e7039c0e109c379dfa1edce

3. Setting the fields uses deep reflection.   
    But the hidden class themself doesn't have any fields - just it's 
superclass `java.lang.reflect.Proxy.h`.  
    This is not a problem if the class can be instantiated at all (see step 2).

-------------

PR: https://git.openjdk.java.net/jdk/pull/8278

Reply via email to