forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Convert MemoryMarshal.GetArrayDataReference to a JIT intrinsic
Converts MemoryMarshal.GetArrayDataReference to an always expand JIT intrinsic and removes the VM intrinsics. Introduces JIT tests validating the correct behaviour. Fixes invalid codegen samples from: dotnet#58312 (comment)
- Loading branch information
1 parent
712b878
commit 521aa0e
Showing
9 changed files
with
18,173 additions
and
8,904 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
src/tests/JIT/Intrinsics/MemoryMarshalGetArrayDataReference.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace MemoryMarshalGetArrayDataReferenceTest | ||
{ | ||
class Program | ||
{ | ||
private static int _errors = 0; | ||
|
||
unsafe static int Main(string[] args) | ||
{ | ||
delegate*<byte[], ref byte> ptrByte = &MemoryMarshal.GetArrayDataReference<byte>; | ||
delegate*<string[], ref string> ptrString = &MemoryMarshal.GetArrayDataReference<string>; | ||
|
||
byte[] testByteArray = new byte[1]; | ||
IsTrue(Unsafe.AreSame(ref MemoryMarshal.GetArrayDataReference(testByteArray), ref testByteArray[0])); | ||
IsTrue(Unsafe.AreSame(ref ptrByte(testByteArray), ref testByteArray[0])); | ||
|
||
string[] testStringArray = new string[1]; | ||
IsTrue(Unsafe.AreSame(ref MemoryMarshal.GetArrayDataReference(testStringArray), ref testStringArray[0])); | ||
IsTrue(Unsafe.AreSame(ref ptrString(testStringArray), ref testStringArray[0])); | ||
|
||
IsFalse(Unsafe.IsNullRef(ref MemoryMarshal.GetArrayDataReference(Array.Empty<byte>()))); | ||
IsFalse(Unsafe.IsNullRef(ref MemoryMarshal.GetArrayDataReference(Array.Empty<string>()))); | ||
IsFalse(Unsafe.IsNullRef(ref MemoryMarshal.GetArrayDataReference(Array.Empty<Half>()))); | ||
IsFalse(Unsafe.IsNullRef(ref MemoryMarshal.GetArrayDataReference(Array.Empty<Vector128<byte>>()))); | ||
IsFalse(Unsafe.IsNullRef(ref MemoryMarshal.GetArrayDataReference(Array.Empty<StructWithByte>()))); | ||
IsFalse(Unsafe.IsNullRef(ref MemoryMarshal.GetArrayDataReference(Array.Empty<SimpleEnum>()))); | ||
IsFalse(Unsafe.IsNullRef(ref MemoryMarshal.GetArrayDataReference(Array.Empty<GenericStruct<byte>>()))); | ||
IsFalse(Unsafe.IsNullRef(ref MemoryMarshal.GetArrayDataReference(Array.Empty<GenericStruct<string>>()))); | ||
|
||
IsFalse(Unsafe.IsNullRef(ref ptrByte(Array.Empty<byte>()))); | ||
IsFalse(Unsafe.IsNullRef(ref ptrString(Array.Empty<string>()))); | ||
|
||
ThrowsNRE(() => { _ = ref MemoryMarshal.GetArrayDataReference<byte>(null); }); | ||
ThrowsNRE(() => { _ = ref MemoryMarshal.GetArrayDataReference<string>(null); }); | ||
ThrowsNRE(() => { _ = ref MemoryMarshal.GetArrayDataReference<Half>(null); }); | ||
ThrowsNRE(() => { _ = ref MemoryMarshal.GetArrayDataReference<Vector128<byte>>(null); }); | ||
ThrowsNRE(() => { _ = ref MemoryMarshal.GetArrayDataReference<StructWithByte>(null); }); | ||
ThrowsNRE(() => { _ = ref MemoryMarshal.GetArrayDataReference<SimpleEnum>(null); }); | ||
ThrowsNRE(() => { _ = ref MemoryMarshal.GetArrayDataReference<GenericStruct<byte>>(null); }); | ||
ThrowsNRE(() => { _ = ref MemoryMarshal.GetArrayDataReference<GenericStruct<string>>(null); }); | ||
|
||
ThrowsNRE(() => { _ = ref ptrByte(null); }); | ||
ThrowsNRE(() => { _ = ref ptrString(null); }); | ||
|
||
// from https://github.com/dotnet/runtime/issues/58312#issuecomment-993491291 | ||
[MethodImpl(MethodImplOption.NoInlining)] | ||
static int Problem1(StructWithByte[] a) | ||
{ | ||
MemoryMarshal.GetArrayDataReference(a).Byte = 1; | ||
|
||
a[0].Byte = 2; | ||
|
||
return MemoryMarshal.GetArrayDataReference(a).Byte; | ||
} | ||
|
||
Equals(Problem(new StructWithByte[] { new StructWithByte { Byte = 1 } }), 2); | ||
|
||
[MethodImpl(MethodImplOption.NoInlining)] | ||
static int Problem2(byte[] a) | ||
{ | ||
if (MemoryMarshal.GetArrayDataReference(a) == 1) | ||
{ | ||
a[0] = 2; | ||
if (MemoryMarshal.GetArrayDataReference(a) == 1) | ||
{ | ||
return -1; | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
Equals(Problem2(new byte[] { 1 }), 0); | ||
|
||
return 100 + _errors; | ||
} | ||
|
||
[MethodImpl(MethodImplOption.NoInlining)] | ||
static void Equals<T>(T left, T right, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "") | ||
{ | ||
if (EqualityComparer<T>.Default.Equals(left, right)) | ||
{ | ||
Console.WriteLine($"{file}:L{line} test failed (expected: equal, actual: {left}-{right})."); | ||
_errors++; | ||
} | ||
} | ||
|
||
[MethodImpl(MethodImplOption.NoInlining)] | ||
static void IsTrue(bool expression, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "") | ||
{ | ||
if (!expression) | ||
{ | ||
Console.WriteLine($"{file}:L{line} test failed (expected: true)."); | ||
_errors++; | ||
} | ||
} | ||
|
||
[MethodImpl(MethodImplOption.NoInlining)] | ||
static void IsFalse(bool expression, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "") | ||
{ | ||
if (expression) | ||
{ | ||
Console.WriteLine($"{file}:L{line} test failed (expected: false)."); | ||
_errors++; | ||
} | ||
} | ||
|
||
[MethodImpl(MethodImplOption.NoInlining)] | ||
static void ThrowsNRE(Action action, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "") | ||
{ | ||
try | ||
{ | ||
action(); | ||
} | ||
catch (NullReferenceException) | ||
{ | ||
return; | ||
} | ||
catch (Exception exc) | ||
{ | ||
Console.WriteLine($"{file}:L{line} {exc}"); | ||
} | ||
Console.WriteLine($"Line {line}: test failed (expected: NullReferenceException)"); | ||
_errors++; | ||
} | ||
|
||
public struct GenericStruct<T> | ||
{ | ||
public T field; | ||
} | ||
|
||
public enum SimpleEnum | ||
{ | ||
A,B,C | ||
} | ||
|
||
struct StructWithByte | ||
{ | ||
public byte Byte; | ||
} | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/tests/JIT/Intrinsics/MemoryMarshalGetArrayDataReference_r.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
<DebugType>None</DebugType> | ||
<Optimize /> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="MemoryMarshalGetArrayDataReference.cs" /> | ||
</ItemGroup> | ||
</Project> |
13 changes: 13 additions & 0 deletions
13
src/tests/JIT/Intrinsics/MemoryMarshalGetArrayDataReference_ro.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
<DebugType>None</DebugType> | ||
<Optimize>True</Optimize> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="MemoryMarshalGetArrayDataReference.cs" /> | ||
</ItemGroup> | ||
</Project> |