Description
API proposal
namespace System.Runtime.CompilerServices
{
public sealed class RuntimeHelpers
{
[Obsolete("Use string.GetPinnableReference() instead.")]
public static int OffsetToStringData { get; }
}
}
Justification
The RuntimeHelpers.OffsetToStringData
property is the last remaining public API which exposes the concept of the string
object containing inline UTF-16 data just after the object header. It's used by compilers to pin string
instances, generally (but not always) using the following pseudocode:
fixed string fixedLocal = theStringInstance;
char* pchStr = (char*)((byte*)theStringInstance + RuntimeHelpers.OffsetToStringData);
// use 'pchStr' here
Because of this pattern throughout existing libraries, adding support for things like string compaction (where the backing data might be ASCII instead of UTF-16) becomes difficult and error-prone.
In .NET Core 3.0, we added an API string.GetPinnableReference()
which takes advantage of the new pattern-based fixed
statement support added in C# 7.3. This new API would allow us to intercept the call immediately before the pin operation, allowing the runtime to fix up the data as necessary. When targeting netcoreapp3.0, the compiler will prefer the new GetPinnableReference
API over the old RuntimeHelpers
API.
As more and more DLLs are built which target netcoreapp3.0+, we should gradually see the ecosystem move over to the new API, allowing us to experiment with changing the internal layout of the string
type once a critical mass of DLLs has migrated away from the old APIs.
Since the main consumer of the old API is the C# compiler itself, I don't anticipate most code bases seeing new warnings after upgrade. The compiler will automatically prefer the new API anyway. The reason I propose obsoleting the old API is so tooling authors and devs writing ref emit code or otherwise manipulating IL directly will see the warning and know that they should instead be calling a new more future-proof API.