On Tue, 20 Oct 2020 23:42:31 GMT, Mandy Chung <mch...@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