RFR: 8159746: (proxy) Support for default methods
Mandy Chung
mchung at openjdk.java.net
Thu Oct 22 00:28:11 UTC 2020
On Tue, 20 Oct 2020 23:42:31 GMT, Mandy Chung <mchung at openjdk.org> wrote:
>> Hi Mandy,
>>
>> You're right. I haven't thought of what one can do with a Lookup for one proxy class when other proxy classes are co-located in the same module and/or package. So instead of a Lookup, we could use some other more targeted "capability". Here's alternative API no.2 that uses special SuperInvoker callback interface passed as argument to invocation handler:
>>
>> https://github.com/mlchung/jdk/pull/4
>>
>> Each proxy class has its own SuperInvoker instance, assigned to static final field of generated proxy class like Method objects, which is passed to invocation handler in the same way as the selected Method object. Invocation handler can use this SuperInvoker instance to invoke the super default method on the proxy. SuperInvoker can verify that the passed-in proxy is of the correct class very quickly. Also the cache of transformed method handles per Method is embedded in the SuperInvoker itself instead of using ClassValue to hold it, so overhead for super invocations is further reduced:
>>
>> Mandy's original:
>>
>> Benchmark Mode Cnt Score Error Units
>> ProxyBench.implClass avgt 5 3.709 ± 0.026 ns/op
>> ProxyBench.implProxy avgt 5 926.215 ± 11.835 ns/op
>>
>>
>> Peter's performance patch:
>>
>> Benchmark Mode Cnt Score Error Units
>> ProxyBench.implClass avgt 5 3.777 ± 0.005 ns/op
>> ProxyBench.implProxy avgt 5 27.579 ± 0.250 ns/op
>>
>>
>> Static method moved to InvocationHandler + added access check
>>
>> Benchmark Mode Cnt Score Error Units
>> ProxyBench.implClass avgt 5 3.740 ± 0.004 ns/op
>> ProxyBench.implProxy avgt 5 34.226 ± 0.125 ns/op
>> ProxyBench.ppImplClass avgt 5 3.780 ± 0.004 ns/op
>> ProxyBench.ppImplProxy avgt 5 147.318 ± 1.422 ns/op
>>
>>
>> Alternative API #1 with access check in newProxyInstance and Lookup parameter
>>
>> Benchmark Mode Cnt Score Error Units
>> ProxyBench.implClass avgt 5 3.782 ± 0.013 ns/op
>> ProxyBench.implProxy avgt 5 32.493 ± 0.192 ns/op
>> ProxyBench.ppImplClass avgt 5 3.749 ± 0.002 ns/op
>> ProxyBench.ppImplProxy avgt 5 30.565 ± 0.190 ns/op
>>
>>
>> Alternative API #2 with SuperInvoker parameter
>>
>> Benchmark Mode Cnt Score Error Units
>> ProxyBench.implClass avgt 5 3.777 ± 0.003 ns/op
>> ProxyBench.implProxy avgt 5 20.282 ± 0.585 ns/op
>> ProxyBench.ppImplClass avgt 5 3.752 ± 0.002 ns/op
>> ProxyBench.ppImplProxy avgt 5 19.790 ± 0.335 ns/op
>>
>> So what do you think about this one?
>
> Hi Peter, thanks for coming with these alternatives. The need for new `InvocationHandler2` and `InvocationHandler2.SuperInvoker` APIs and the complexity of `plevart:proxy-default-method-alt-api2` look unpleasing in order to keep the invocation of default methods in lambdas. I prefer the `DelegatingInvocationHandler` abstract class approach without caller-sensitive method.
Hi Peter, Alan
I have prototyped two alternatives ([mlchung:proxy-default-method-3](https://github.com/mlchung/jdk/tree/proxy-default-method-3)).
1. `DelegatingInvocationHandler` abstract class with:
protected final Object invokeDefault(Object proxy, Method method, Object... params)
2. `NewInvocationHandler` functional interface
public Object invoke(DefaultMethodInvoker invoker, Object proxy, Method method, Object... args) throws Throwable;
/**
* {@inheritDoc}
*/
public default Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
return invoke(DefaultMethodInvoker.getInvoker(proxy, this), proxy, method, args);
}
public final class DefaultMethodInvoker {
public final Object invoke(Object proxy, Method method, Object... args)
throws InvocationTargetException
}
Similar idea as yours SuperInvoker. But I think this is less complicated
and DefaultMethodInvoker is a final class rather than an interface.
The generated proxy class will keep invoking `InvocationHandler::invoke`
(no change in `ProxyGenerator`). `NewInvocationHandler` allows the use of lambdas.
I like `DelegatingInvocationHandler` which is simple and clean but not
a functional interface. `NewInvocationHandler` is a functional interface
with the need of `DefaultMethodInvoker` to bridge between an invocation
handler and an accessed check proxy object.
Thoughts? I'm leaning toward `DelegatingInvocationHandler`.
We need to decide on the exception if access checks fails on
`Proxy::newProxyInstance` and `Proxy::getInvocationHandler`
if the invocation handler needs the ability to invoke default
methods.
-------------
PR: https://git.openjdk.java.net/jdk/pull/313
More information about the core-libs-dev
mailing list