From d3672725b19462e312cf6a8e552816cdd2a1018f Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 15 Feb 2017 21:15:08 -0800 Subject: [PATCH 1/3] Adding the static-delegate proposal. --- proposals/static-delegates.md | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 proposals/static-delegates.md diff --git a/proposals/static-delegates.md b/proposals/static-delegates.md new file mode 100644 index 0000000000..5c03244f1c --- /dev/null +++ b/proposals/static-delegates.md @@ -0,0 +1,72 @@ +# Static Delegates + +* [x] Proposed +* [ ] Prototype: Not Started +* [ ] Implementation: Not Started +* [ ] Specification: Not Started + +## Summary +[summary]: #summary + +Provide a general-purpose, lightweight callback capability to the C# language. + +## Motivation +[motivation]: #motivation + +Today, users have the ability to create callbacks using the `System.Delegate` type. However, these are fairly heavyweight (such as requiring a heap allocation and always having handling for chaining callbacks together). + +Additionally, `System.Delegate` does not provide the best interop with unmanaged function pointers, namely due being non-blittable and requiring marshalling anytime it crosses the managed/unmanaged boundary. + +With a few minor tweaks, we could provide a new type of delegate that is lightweight, general-purpose, and interops well with native code. + +## Detailed design +[design]: #detailed-design + +One would declare a static delegate via the following: + +```C# +static delegate int Func() +``` + +One could additionally attribute the declaration with something similar to `System.Runtime.InteropServices.UnmanagedFunctionPointer` so that the calling convention, string marshalling, and set last error behavior can be controlled. NOTE: Using `System.Runtime.InteropServices.UnmanagedFunctionPointer` itself will not work, as it is only usable on Delegates. + +The declaration would get translated into an internal representation by the compiler that is similar to the following + +```C# +struct +{ + IntPtr pFunction; + + static int Func(); +} +``` + +That is to say, it is internally represented by a struct that has a single member of type `IntPtr` (such a struct is blittable and does not incur any heap allocations). The member contains the address of the function that is to be the callback. Additionally, the type declares a method matching the method signature of the callback. + +The value of the static delegate can only be bound to a static method that matches the signature of the callback. + +Chaining callbacks together is not supported. + +Invocation of the callback would be implemented by the `calli` instruction. + + +## Drawbacks +[drawbacks]: #drawbacks + +TBD + +## Alternatives +[alternatives]: #alternatives + +TBD + +## Unresolved questions +[unresolved]: #unresolved-questions + +What parts of the design are still TBD? + +## Design meetings + +Link to design notes that affect this proposal, and describe in one sentence for each what changes they led to. + + From 6b8bd95f8b4e474785f09bd3efe3e56c27283be0 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 16 Feb 2017 07:19:41 -0800 Subject: [PATCH 2/3] Adding a couple of drawbacks to the static-delegates proposal. --- proposals/static-delegates.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proposals/static-delegates.md b/proposals/static-delegates.md index 5c03244f1c..a912108fbc 100644 --- a/proposals/static-delegates.md +++ b/proposals/static-delegates.md @@ -53,7 +53,9 @@ Invocation of the callback would be implemented by the `calli` instruction. ## Drawbacks [drawbacks]: #drawbacks -TBD +Static Delegates would not work with existing APIs that use regular delegates (one would need to wrap said static delegate in a regular delegate of the same signature). + +Additional work would be needed to make Static Delegate readily usable in the core framework. ## Alternatives [alternatives]: #alternatives From e23c9e0ebdcef2a5ceafa16ce7b652335edd5c41 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 16 Feb 2017 08:02:34 -0800 Subject: [PATCH 3/3] Clarifying on some points in the static-delegates proposal. --- proposals/static-delegates.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/proposals/static-delegates.md b/proposals/static-delegates.md index a912108fbc..436524b669 100644 --- a/proposals/static-delegates.md +++ b/proposals/static-delegates.md @@ -33,15 +33,20 @@ One could additionally attribute the declaration with something similar to `Syst The declaration would get translated into an internal representation by the compiler that is similar to the following ```C# -struct +struct e__StaticDelegate { IntPtr pFunction; - static int Func(); + static int WellKnownCompilerName(); } ``` -That is to say, it is internally represented by a struct that has a single member of type `IntPtr` (such a struct is blittable and does not incur any heap allocations). The member contains the address of the function that is to be the callback. Additionally, the type declares a method matching the method signature of the callback. +That is to say, it is internally represented by a struct that has a single member of type `IntPtr` (such a struct is blittable and does not incur any heap allocations): +* The member contains the address of the function that is to be the callback. +* The type declares a method matching the method signature of the callback. +* The name of the struct should not be user-constructable (as we do with other internally generated backing structures). + * For example: fixed size buffers generate a struct with a name in the format of `e__FixedBuffer` (`<` and `>` are part of the identifier and make the identifier not constructable in C#, but still useable in IL). +* The name of the method declaration should be a well known name used across all static delegate types (this allows the compiler to know the name to look for when determining the signature). The value of the static delegate can only be bound to a static method that matches the signature of the callback. @@ -49,11 +54,11 @@ Chaining callbacks together is not supported. Invocation of the callback would be implemented by the `calli` instruction. - ## Drawbacks [drawbacks]: #drawbacks Static Delegates would not work with existing APIs that use regular delegates (one would need to wrap said static delegate in a regular delegate of the same signature). +* Given that `System.Delegate` is represented internally as a set of `object` and `IntPtr` fields (http://source.dot.net/#System.Private.CoreLib/src/System/Delegate.cs), it would be possible to allow implicit conversion of a static delegate to a `System.Delegate` that has a matching method signature. It would also be possible to provide an explicit conversion in the opposite direction, provided the `System.Delegate` conformed to all the requirements of being a static delegate. Additional work would be needed to make Static Delegate readily usable in the core framework.