-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Proposal: RuntimeHelpers.GetRawData #28001
Comments
Would love to have this actually. Typically, the fact that we don't have access today to JitHelpers.GetRawSzArrayData(this Array array) is annoying because there are many optimizations that CoreCLR can do internally on arrays that we can't do on our own..... @MichalStrehovsky, what would be the story to calculate the offset field? I'm not a fan of the convoluted code we have to go through today like this:
Wondering if as part of the CLR change required for interface static methods, if we should not introduce more IL opcodes for these kind of scenarios... 🤔 |
Thinking more seriously about this, I'm worried that we could miss an opportunity here (we don't have the occasion to have breaking changes to the IL), so should we think more broadly about what would be relevant to bring to these CLR changes? @jkotas what do you think? |
I think that The fast field accessors that are shown in example usage should be first class public APIs exposed by the runtime. I believe we have some related issues about this. I do not think we want everybody to be implementing their own version of them from low-level building blocks. We want them to be owned by the runtime so that we can optimize the heck out of them, without compromising type safety.
I do not think this proposal requires any changes to the IL. Also, note that interface static methods are not a breaking change. It would be a breaking change if existing programs stopped working which is not the case. The fact that new features require new runtimes is not a breaking change. |
Yeah, I was not asking about this issue in particular. For example, calculating the offset of a field from a root object is "quite common" for low level access so a |
What are the scenarios you need the offsets for? I would rather look at what you are trying to do and see what is the best way to address it. Offsets are way too low-level. |
For example: an animation engine, instead of having full codegen for accessing fields of structured data (which incurs an indirect call and hurts instruction cache in the end with too many of them) you can use instead field offsets to manipulate the data efficiently. Today, we need to use the code I showed above to calculate the offset, which incurs to allocate a temporary object to calculate this offset and calling multiple methods from Unsafe, while this offset is accessible from the JIT/AOT compiler relatively easily. In C# this could translate to something like |
Would the type safe field accessors work for this? I would like to have a type safe default that would be used in most cases, and have unsafe escape hatch for cases where the type safety check is too expensive. |
Not sure I know this, do you have an example how does it work? |
E.g. We can introduce a fully type safe field accessor like this:
|
Oh right, this is what I would use in the end once I have the offset. My concern is more for the calculation of |
There would be a factory method to get the FieldAccessor from the FieldInfo or RuntimeFieldHandle. The factory would be a slower method - it would validate the types. |
As long as we can avoid using reflection (and allocating lots of managed memory) to fetch this token, I'm fine with this approach. I assume that we would have proper support in Roslyn to do a ldtoken via something like |
Right. |
And for a cross-cutting feature like this, we can look forward to having it available in .NET Core 5 or 6 :). I'm proposing to expose a low level building block like this to address the needs people have right now. It's similar to the function pointer support that C# is adding - they could have waited for static delegates, but they want to address problems people are having now, as opposed to selling them on how great things will be 3 years from now. ML.net is using Reflection.Emit because of what appears to be a lack of building blocks: dotnet/machinelearning#1736 |
But I thought that |
So what would We would not need to wait for
Not really. It would be ugly for static delegates to solve all the problems (e.g. around interop) that the function pointers are solving. |
I opened https://github.com/dotnet/corefx/issues/36133 to track the SzArray-specific helper method. |
@MichalStrehovsky We can get this in S.P.C first right? This and also GetObjectSize and HasReferences. |
Yes, exposing this as a private API on |
Following up this conversation with @MichalStrehovsky, it'd be nice if we also had an API just like I know multidimensional arrays in general are not used that often, but I do think they could use some more love from the new APIs ( Partially related: it'd be nice if I can create issues for these various points, but I thought quickly running this by you guys to get some early feedback could be useful to avoid creating many (potentially unnecessary) issues 😄 |
Just wanted to make sure this wont work with Or do you expect some trick/api/pattern to work well in this specific case when mutating struct in-place-like? |
If you want to modify struct in-place, there's |
@MichalStrehovsky according to documentation on Setting that aside i wonder if it would be possible to introduce an overload like |
Given the timeline for 5.0 and the state of this issue, I don't see it making in. Moving to 6.0. |
Closing; assuming #45152 supersedes this. |
Reopening per #45152 (comment). |
The suggestion at #45152 (comment) also had a way to return an object. Assuming we want to do that with this PR, I suggest we'll also want to:
namespace System.Runtime.CompilerServices;
public class Unsafe
{
+ public static object? GetObject(Type type, ref byte reference, nuint offset = 0);
+ public static T? GetObject<T>(ref byte reference, nuint offset = 0);
} |
I don't know what's the use case for such API - do we have a use for something like this in CoreLib? We certainly have uses for |
A reference implementation of a |
Looking at this again, #45152 (comment) and #28001 (comment) each propose a very different API. How does #28001 (comment) differ from Foo x = Unsafe.GetObject<Foo>(ref myRef, 123);
Foo x = Unsafe.As<byte, Foo>(ref Unsafe.AddByteOffset(ref myRef, 123)); |
Proposal
I suggest we add the following method to System.Runtime.CompilerServices.RuntimeHelpers:
Given an object instance
o
, this would return a managed reference to the first field of the type (or first element of an array ifo
is an array, or first character of a string ifo
is string). This can be implemented the same way JitHelpers.GetPinningHelper is implemented within the CLR and would have similar use.Alternatives considered
We could place the helper in System.Runtime.CompilerServices.Unsafe, but that would be troublesome for variable-length types (arrays and string). If we ever add new ones (such as the Utf8string prototype), the API might not do what the user expects. This API needs to be versioned with the underlying runtime.
Example Usage
Create a strongly typed reflection-free field getter and setter:
The text was updated successfully, but these errors were encountered: