-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
An arbitrary array/span of references #38488
Comments
Is the core issue related to the language here? I do have to say, the concentration of unsafe code and undocumented keywords in the usage example is higher than most people are perhaps used to, even considering the advanced nature of the API. |
Repathing this to the GC, because I'm pretty sure it would require a significant GC overhaul to support arrays / spans of ref structs. @Maoni0 would be able to provide a better analysis. |
Tagging subscribers to this area: @Maoni0 |
@SingleAccretion Similarly to Edit: Note that spans of ref struct would be helpful to have in this case, but it could be implemented as a span of pointers to ref structs (TypedReferences) located on the stack. |
Oh, well, you probably already know this, but this makes it extremely unlikely for this to even be considered. The bar for language features is very high, and this one:
Also of note here is that as a platform .NET is kind of moving away from late binding/reflection, so... |
That is unfortunate to hear. The reflection API is basically stuck in .NET 1 in its capabilities, everything being either |
As long as these
Correct, this would need language support to be a safe, widely usable construct. It does not require any special language support if this was an low-level building block that requires you to know the rules to use it safely. CoreRT has an internal building block like that: https://github.com/dotnet/corert/search?q=LocalVariableSet. Before he left, Ati looked into turning it into a public API as one of the possible strategies to make Reflection Invoke faster. Related: #26186 |
Then we can spin up an internal prototype perhaps using #12832 as a test case. It'll look a bit rough without compiler support, but it should at least tell us whether or not the scenario works. |
Closing this issue in favor of #75349 which will support a stack-based only approach. @IllidanS4 thanks for the API suggestions. Those APIs are effectively block until we can get support for generic parameters for byref-like types. |
Background and Motivation
In scenarios like reflection or interaction with other languages or platforms, there is not a generically usable and performant way to handle variable number of arbitrary arguments. C# provides syntax like
params object[]
orparams T[]
(and might supportparams Span<T>
in the future), but that works best in cases where the parameters are homogenous.ref
parameters are especially cumbersome to translate toparams
, as it requires copying the value back and forth in case the called method modifies it.Prime targets are
Delegate.DynamicInvoke
orMethodInfo.Invoke
. Here the call could be translated to invoking a method with any number of parameters, normal ofref
. Calling a method with a singleref int
argument requires 3 heap allocations – one for the array, one for boxing the argument as the input, and one for boxing the argument as the output.This proposal tries to provide a way to solve this issue, without significant modifications to the runtime, and if that is deemed inappropriate, to instigate discussion about other and better options.
Proposed API
The core of this proposal is a type that is conceptually similar to
Span<TypedReference*>
, if that were a valid type.This is also an example implementation in C# (if returning
TypedReference
was possible in case of the indexer). Methods ofSpan<T>
could also be ported toByRefSpan
.Usage Examples
Cooperation from specific languages is needed to make the usage of this type more "beautiful", but this prepares the ground:
In a potential future where C# supports
params ByRefSpan
, the boilerplate code inCaller
could easily be simplified toDynamicMethod(ref arg1, ref arg2, ref arg3)
;Alternative Designs
At first I experimented with simple
stackalloc TypedReference[3]
, but the runtime doesn't track stack space allocated this way (meaning GC ignores any references to objects in it), so until such a change is made (which would enable things likestackalloc (int, string)[10]
and more), or until it is possible to have a fixed-size by-value array as a local variable or another way to statically group locals together as a span, individualTypedReference
variables must be used and the double reference is needed. In essence, a tuple type like(TypedReference, TypedReference, TypedReference)
would be needed.There is also place for
ByRefSpan<T>
storingT**
in a similar fashion. However, there is no way in C# I am aware of to use such a type, so first something like the internalByReference<T>
has to be exposed.Another option is to resurrect and improve
__arglist
,RuntimeTypeHandle
andArgIterator
, however those are less efficient and exist only for interaction with unmanaged code. Being able to constructByRefSpan
fromRuntimeArgumentHandle
would be nice though.Risks
This type is used to store a pointer to potentially stack-allocated data, like
Span<T>
, but the risks of a value escaping the stack are solved by usingref struct
. The only other risks stem from the way this type is used, which would, hopefully, be mitigated by improvements in the language.The text was updated successfully, but these errors were encountered: