You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
DynamicProxy currently emits one dedicated invocation type for each method that can proceed to a target method. Looking at C# 9's function pointers (delegate*) made me wonder if they could possibly replace those invocation types.
Case example
Say we have this type with a generic method that we want to proxy:
A Foo_Method<> invocation type inheriting from InheritanceInvocation, whose InvokeMethodOnTarget method implementation delegates to FooProxy.Method_callback:
Proposal: more efficient code generation using delegate*
What we could do instead is:
Still emit FooProxy.Method_callback, as is.
Instead of the FooMethod<> invocation type, emit another method FooProxy.Method_invokeOnTarget<> directly inside the proxy type.
Add a new pre-defined invocation type Invocation (not its final name, obviously) to this library that will work for any proxied method – i. e. it might eventually even replace the existing CompositionInvocation and InheritanceInvocation.
Starting with (3), that general pre-defined invocation type might look as follows (uninteresting parts not shown):
publicunsafesealedclassInvocation:IInvocation{privatereadonlydelegate*<object,Invocation,void>invokeMethodOnTarget;publicInvocation(delegate*<object,Invocation,void>invokeMethodOnTarget,objectproxy,object?[]arguments, ...){this.invokeMethodOnTarget=invokeMethodOnTarget;Proxy=proxy;Arguments=arguments;
...}publicobjectProxy{get;}publicobject?[]Arguments{get;}privatevoidInvokeMethodOnTarget(){if(invokeMethodOnTarget==null)thrownewInvalidOperationException("There is no target to proceed to.");invokeMethodOnTarget(Proxy!,this);}}
That is, it receives a function pointer invokeMethodOnTarget that the invocation can use to proceed to the target method (whatever that may be).
Regarding (1) and (2), the emitted code for the Foo proxy type might look roughly as follows:
publicunsafeclassFooProxy:Foo{publicoverridevoidMethod<T2>(stringarg1,T2arg2){newInvocation(&Method_invokeOnTarget<T2>,this,arguments:[arg1,arg2], ...).Proceed();}// DynamicProxy already emits this (albeit with `public` visibility, which would no longer be necessary):privatevoidMethod_callback<T2>(stringarg1,T2arg2){base.Method(arg1,arg2);}// This is the new method that would replace the separate `Foo_Method` invocation type:privatestaticvoidMethod_invokeOnTarget<T>(objectproxyObject,Invocationinvocation){((FooProxy)proxyObject).Method_callback((string)invocation.Arguments[0],(T2)invocation.Arguments[1]);}}
Possible advantages
Fewer types and method emitted would likely result in faster runtime performance during proxy type generation.
Same amount of allocations and less virtual method dispatch might result in marginally better runtime performance during proxy object calls – Invocation.InvokeMethodOnTarget does not need to be virtual, and could even be inlined.
Fewer pre-defined types needed in DynamicProxy – it's possible that the general-purpose Invocation type could replace all others (such as InheritanceInvocation and CompositionInvocation.
Possibly less complexity in generic type parameter handling. We don't need to transplant type parameters from a method to a class type; we'd only be emitting sibling methods next to the proxied method that have its exact same generic type parameters – this might possibly benefit Improve code generation performance/caching using open generic types #448.
This looks feasible to me, but I haven't done any deeper digging to see what problems might surface with this approach.
DynamicProxy currently emits one dedicated invocation type for each method that can proceed to a target method. Looking at C# 9's function pointers (
delegate*) made me wonder if they could possibly replace those invocation types.Case example
Say we have this type with a generic method that we want to proxy:
Current code generation
Because
Method<>is not abstract and can be proceeded to, DynamicProxy emits two additional things for it:A method
FooProxy.Method_callbackthat calls the base method implementation:A
Foo_Method<>invocation type inheriting fromInheritanceInvocation, whoseInvokeMethodOnTargetmethod implementation delegates toFooProxy.Method_callback:Proposal: more efficient code generation using
delegate*What we could do instead is:
FooProxy.Method_callback, as is.FooMethod<>invocation type, emit another methodFooProxy.Method_invokeOnTarget<>directly inside the proxy type.Invocation(not its final name, obviously) to this library that will work for any proxied method – i. e. it might eventually even replace the existingCompositionInvocationandInheritanceInvocation.Starting with (3), that general pre-defined invocation type might look as follows (uninteresting parts not shown):
That is, it receives a function pointer
invokeMethodOnTargetthat the invocation can use to proceed to the target method (whatever that may be).Regarding (1) and (2), the emitted code for the
Fooproxy type might look roughly as follows:Possible advantages
Invocation.InvokeMethodOnTargetdoes not need to be virtual, and could even be inlined.Invocationtype could replace all others (such asInheritanceInvocationandCompositionInvocation.This looks feasible to me, but I haven't done any deeper digging to see what problems might surface with this approach.