Skip to content
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

Pinning a string should prefer string.GetPinnableReference over RuntimeHelpers.GetOffsetToStringData #9251

Closed
GrabYourPitchforks opened this issue May 20, 2020 · 1 comment
Labels
Area-Compiler-CodeGen IlxGen, ilwrite and things at the backend Feature Request Theme-Performance
Milestone

Comments

@GrabYourPitchforks
Copy link
Member

In .NET Core 3.0 we introduced the method string.GetPinnableReference, which retrieves a readonly char& pointing to the first character of the string's data. (If the string is empty, it returns a reference to the null terminator.)

It is preferred for compilers to use this method instead of RuntimeHelpers.GetOffsetToStringData when pinning string instances. The GetOffsetToStringData method assumes that the character data is inline with the string object itself. We want to experiment with breaking this assumption in future versions of .NET, and we need to get compilers off of this API and onto the preferred GetPinnableReference method instead.

If the application is targeting a previous version of .NET - one that doesn't include string.GetPinnableReference - then the compiler should continue to fall back to GetOffsetToStringData.

Repro steps

#nowarn "9"
let foo(s : string) =
    use ptr = fixed s
    ptr

Expected IL

.method private hidebysig static 
	char* foo (
		string s
	) cil managed 
{
	// Method begins at RVA 0x2050
	// Code size 16 (0x10)
	.maxstack 1
	.locals init (
		[0] char& pinned
	)

	IL_0000: ldarg.0
	IL_0001: brtrue.s IL_0006

	IL_0003: ldc.i4.0
	IL_0004: conv.u
	IL_0005: ret

	IL_0006: ldarg.0
	IL_0007: call instance char& modreq([System.Runtime]System.Runtime.InteropServices.InAttribute) [System.Runtime]System.String::GetPinnableReference()
	IL_000c: stloc.0
	IL_000d: ldloc.0
	IL_000e: conv.u
	IL_000f: ret
} // end of method Program::foo

Actual IL

.method public static 
	char* foo (
		string s
	) cil managed 
{
	// Method begins at RVA 0x2050
	// Code size 16 (0x10)
	.maxstack 4
	.locals init (
		[0] string pinned
	)

	IL_0000: ldarg.0
	IL_0001: stloc.0
	IL_0002: ldarg.0
	IL_0003: brfalse.s IL_000e

	IL_0005: ldarg.0
	IL_0006: conv.i
	IL_0007: call int32 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
	IL_000c: add
	IL_000d: ret

	IL_000e: ldarg.0
	IL_000f: ret
} // end of method Program::foo
@jwosty
Copy link
Contributor

jwosty commented Aug 26, 2023

This is done #15697

@kerams kerams closed this as completed Aug 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compiler-CodeGen IlxGen, ilwrite and things at the backend Feature Request Theme-Performance
Projects
Archived in project
Development

No branches or pull requests

6 participants