Skip to content

Commit 76610ec

Browse files
Use Utf8Span for type system names (#128969)
Contributes to #122363. This addresses two issues with the current "the exchange type for UTF-8 strings is `ReadOnlySpan<byte>`": * Debugger now shows the strings: the `ToString` is more meaningful than the one on `ReadOnlySpan<T>`. * We can now use `==` to compare strings, no more `x.SequenceEqual("y"u8)` Migrate type system name surfaces and related callers from `ReadOnlySpan<byte>` to `Utf8StringRef`, adding helper APIs to keep call sites explicit and avoid unnecessary span conversions. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 5626020 commit 76610ec

130 files changed

Lines changed: 680 additions & 450 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66

7+
using Internal.Text;
78
using Internal.Runtime.CompilerServices;
89
using Internal.Runtime.TypeLoader;
910

@@ -91,7 +92,7 @@ public override MethodNameAndSignature NameAndSignature
9192
}
9293
}
9394

94-
public override ReadOnlySpan<byte> Name
95+
public override Utf8Span Name
9596
{
9697
get
9798
{

src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
<Compile Include="$(LibrariesProjectRoot)\System.Private.CoreLib\src\System\Runtime\CompilerServices\IntrinsicAttribute.cs">
5555
<Link>IntrinsicAttribute.cs</Link>
5656
</Compile>
57+
<Compile Include="$(CompilerCommonPath)\Internal\Text\Utf8Span.cs">
58+
<Link>Internal\Text\Utf8Span.cs</Link>
59+
</Compile>
5760
<Compile Include="$(CompilerCommonPath)\TypeSystem\Canon\ArrayType.Canon.cs">
5861
<Link>Internal\TypeSystem\ArrayType.Canon.cs</Link>
5962
</Compile>

src/coreclr/tools/Common/Compiler/AsyncContinuationType.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Diagnostics;
77
using System.Text;
88

9+
using Internal.Text;
910
using Internal.TypeSystem;
1011

1112
namespace ILCompiler
@@ -21,8 +22,8 @@ public sealed partial class AsyncContinuationType : MetadataType
2122
public GCPointerMap PointerMap { get; }
2223

2324
public override DefType[] ExplicitlyImplementedInterfaces => [];
24-
public override ReadOnlySpan<byte> Name => Encoding.UTF8.GetBytes(DiagnosticName);
25-
public override ReadOnlySpan<byte> Namespace => [];
25+
public override Utf8Span Name => Encoding.UTF8.GetBytes(DiagnosticName);
26+
public override Utf8Span Namespace => Array.Empty<byte>();
2627

2728
// We don't lay these out using MetadataType metadata.
2829
// Autolayout (which we'd get due to GC pointers) would likely not match what codegen expects.
@@ -49,9 +50,9 @@ public AsyncContinuationType(MetadataType continuationBaseType, GCPointerMap poi
4950

5051
public override bool HasCustomAttribute(string attributeNamespace, string attributeName) => false;
5152
public override IEnumerable<MetadataType> GetNestedTypes() => [];
52-
public override MetadataType GetNestedType(ReadOnlySpan<byte> name) => null;
53+
public override MetadataType GetNestedType(Utf8Span name) => null;
5354
protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() => [];
54-
public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(ReadOnlySpan<byte> name) => [];
55+
public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(Utf8Span name) => [];
5556

5657
protected override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer)
5758
{

src/coreclr/tools/Common/Compiler/Dataflow/TypeExtensions.cs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,5 @@ public static bool IsDeclaredOnType(this MethodDesc method, string fullTypeName)
5353
return method.OwningType.IsTypeOf(fullTypeName);
5454
}
5555

56-
public static bool StringEquals(this ReadOnlySpan<byte> utf8bytes, string value)
57-
{
58-
if (utf8bytes.Length < value.Length)
59-
return false;
60-
61-
for (int i = 0; i < value.Length; i++)
62-
{
63-
int ch = utf8bytes[i];
64-
if (ch > 0x7F)
65-
return System.Text.Encoding.UTF8.GetString(utf8bytes) == value;
66-
67-
// We are assuming here that valid UTF8 encoded byte > 0x7F cannot map to a character with code point <= 0x7F
68-
if (ch != value[i])
69-
return false;
70-
}
71-
72-
return utf8bytes.Length == value.Length; // All char ANSI, all matching
73-
}
7456
}
7557
}

src/coreclr/tools/Common/Compiler/InstructionSetSupport.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public static string GetHardwareIntrinsicId(TargetArchitecture architecture, Typ
6161
return "";
6262

6363
// 64-bit ISA variants are not included in the mapping dictionary, so we use the containing type instead
64-
if (potentialType.Name.SequenceEqual("X64"u8) || potentialType.Name.SequenceEqual("Arm64"u8))
64+
if (potentialType.Name == "X64"u8 || potentialType.Name == "Arm64"u8)
6565
{
6666
if (architecture is TargetArchitecture.X64 or TargetArchitecture.ARM64)
6767
potentialType = potentialType.ContainingType;
@@ -79,12 +79,12 @@ public static string GetHardwareIntrinsicId(TargetArchitecture architecture, Typ
7979

8080
if (architecture is TargetArchitecture.X64 or TargetArchitecture.X86)
8181
{
82-
if (!potentialType.Namespace.SequenceEqual("System.Runtime.Intrinsics.X86"u8))
82+
if (potentialType.Namespace != "System.Runtime.Intrinsics.X86"u8)
8383
return "";
8484
}
8585
else if (architecture is TargetArchitecture.ARM64 or TargetArchitecture.ARM)
8686
{
87-
if (!potentialType.Namespace.SequenceEqual("System.Runtime.Intrinsics.Arm"u8))
87+
if (potentialType.Namespace != "System.Runtime.Intrinsics.Arm"u8)
8888
return "";
8989
}
9090
else if (architecture is TargetArchitecture.LoongArch64)

src/coreclr/tools/Common/Compiler/Int128FieldLayoutAlgorithm.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristi
8484
public static bool IsIntegerType(DefType type)
8585
{
8686
return type.IsIntrinsic
87-
&& type.Namespace.SequenceEqual("System"u8)
88-
&& (type.Name.SequenceEqual("Int128"u8) || type.Name.SequenceEqual("UInt128"u8));
87+
&& type.Namespace == "System"u8
88+
&& (type.Name == "Int128"u8 || type.Name == "UInt128"u8);
8989
}
9090
}
9191
}

src/coreclr/tools/Common/Compiler/MethodExtensions.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using ILCompiler.DependencyAnalysis;
6+
using Internal.Text;
67
using Internal.TypeSystem;
78
using Internal.TypeSystem.Ecma;
89

@@ -159,11 +160,11 @@ public static bool ReturnsTaskOrValueTask(this MethodSignature method)
159160

160161
if (ret is MetadataType md
161162
&& md.Module == method.Context.SystemModule
162-
&& md.Namespace.SequenceEqual("System.Threading.Tasks"u8))
163+
&& md.Namespace == "System.Threading.Tasks"u8)
163164
{
164-
ReadOnlySpan<byte> name = md.Name;
165-
if (name.SequenceEqual("Task"u8) || name.SequenceEqual("Task`1"u8)
166-
|| name.SequenceEqual("ValueTask"u8) || name.SequenceEqual("ValueTask`1"u8))
165+
Utf8Span name = md.Name;
166+
if (name == "Task"u8 || name == "Task`1"u8
167+
|| name == "ValueTask"u8 || name == "ValueTask`1"u8)
167168
{
168169
return true;
169170
}

src/coreclr/tools/Common/Compiler/NativeAotNameMangler.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ public override Utf8String CompilationUnitPrefix
4040
public override Utf8String SanitizeName(Utf8String s)
4141
=> SanitizeName(s.AsSpan());
4242

43-
private static Utf8String SanitizeName(ReadOnlySpan<byte> s)
43+
private static Utf8String SanitizeName(Utf8Span n)
4444
{
45+
ReadOnlySpan<byte> s = n.AsSpan();
46+
4547
Utf8StringBuilder sb = null;
4648
for (int i = 0; i < s.Length; i++)
4749
{
@@ -98,7 +100,7 @@ private static bool ContainsUtf8ReplacementCharacter(ReadOnlySpan<byte> bytes)
98100
return bytes.IndexOf(replacementCharacter) >= 0;
99101
}
100102

101-
private Utf8String SanitizeNameWithHash(Utf8String literal, byte[] hash = null)
103+
private static Utf8String SanitizeNameWithHash(Utf8String literal, byte[] hash = null)
102104
{
103105
Utf8String mangledName = SanitizeName(literal);
104106

@@ -242,7 +244,7 @@ static void AppendTypeName(Utf8StringBuilder sb, MetadataType t)
242244
}
243245
else
244246
{
245-
ReadOnlySpan<byte> ns = t.Namespace;
247+
Utf8Span ns = t.Namespace;
246248
if (ns.Length > 0)
247249
sb.Append(SanitizeName(ns)).Append('_');
248250
}

src/coreclr/tools/Common/Compiler/TypeMapMetadata.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Diagnostics;
77
using System.Reflection.Metadata;
88
using ILCompiler.DependencyAnalysis;
9+
using Internal.Text;
910
using Internal.IL;
1011
using Internal.IL.Stubs;
1112
using Internal.TypeSystem;
@@ -26,13 +27,13 @@ private enum TypeMapAttributeKind
2627
private static TypeMapAttributeKind LookupTypeMapType(TypeDesc attrType)
2728
{
2829
var typeDef = attrType.GetTypeDefinition() as MetadataType;
29-
if (typeDef != null && typeDef.Namespace.SequenceEqual("System.Runtime.InteropServices"u8))
30+
if (typeDef != null && typeDef.Namespace == "System.Runtime.InteropServices"u8)
3031
{
31-
if (typeDef.Name.SequenceEqual("TypeMapAssemblyTargetAttribute`1"u8))
32+
if (typeDef.Name == "TypeMapAssemblyTargetAttribute`1"u8)
3233
return TypeMapAttributeKind.TypeMapAssemblyTarget;
33-
else if (typeDef.Name.SequenceEqual("TypeMapAttribute`1"u8))
34+
else if (typeDef.Name == "TypeMapAttribute`1"u8)
3435
return TypeMapAttributeKind.TypeMap;
35-
else if (typeDef.Name.SequenceEqual("TypeMapAssociationAttribute`1"u8))
36+
else if (typeDef.Name == "TypeMapAssociationAttribute`1"u8)
3637
return TypeMapAttributeKind.TypeMapAssociation;
3738
}
3839
return TypeMapAttributeKind.None;
@@ -66,7 +67,7 @@ public ThrowingMethodStub(TypeDesc owningType, TypeDesc typeMapGroup, bool exter
6667
}
6768

6869
public TypeSystemException Exception { get; }
69-
public override ReadOnlySpan<byte> Name => _name;
70+
public override Utf8Span Name => _name;
7071
public override MethodIL EmitIL()
7172
{
7273
#if READYTORUN
@@ -78,7 +79,7 @@ public override MethodIL EmitIL()
7879

7980
protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer)
8081
{
81-
return Name.SequenceCompareTo(other.Name);
82+
return Name.AsSpan().SequenceCompareTo(other.Name.AsSpan());
8283
}
8384

8485
public override bool IsPInvoke => false;

src/coreclr/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
2727

2828
LayoutInt alignment;
2929

30-
if (defType.Name.SequenceEqual("Vector64`1"u8))
30+
if (defType.Name == "Vector64`1"u8)
3131
{
3232
alignment = new LayoutInt(8);
3333
}
34-
else if (defType.Name.SequenceEqual("Vector128`1"u8))
34+
else if (defType.Name == "Vector128`1"u8)
3535
{
3636
if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
3737
{
@@ -43,7 +43,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
4343
alignment = new LayoutInt(16);
4444
}
4545
}
46-
else if (defType.Name.SequenceEqual("Vector256`1"u8))
46+
else if (defType.Name == "Vector256`1"u8)
4747
{
4848
if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
4949
{
@@ -76,7 +76,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
7676
}
7777
else
7878
{
79-
Debug.Assert(defType.Name.SequenceEqual("Vector512`1"u8));
79+
Debug.Assert(defType.Name == "Vector512`1"u8);
8080

8181
if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
8282
{
@@ -164,11 +164,11 @@ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristi
164164
public static bool IsVectorType(DefType type)
165165
{
166166
return type.IsIntrinsic &&
167-
type.Namespace.SequenceEqual("System.Runtime.Intrinsics"u8) &&
168-
(type.Name.SequenceEqual("Vector64`1"u8) ||
169-
type.Name.SequenceEqual("Vector128`1"u8) ||
170-
type.Name.SequenceEqual("Vector256`1"u8) ||
171-
type.Name.SequenceEqual("Vector512`1"u8));
167+
type.Namespace == "System.Runtime.Intrinsics"u8 &&
168+
(type.Name == "Vector64`1"u8 ||
169+
type.Name == "Vector128`1"u8 ||
170+
type.Name == "Vector256`1"u8 ||
171+
type.Name == "Vector512`1"u8);
172172
}
173173
}
174174
}

0 commit comments

Comments
 (0)