Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;

using Internal.Text;
using Internal.Runtime.CompilerServices;
using Internal.Runtime.TypeLoader;

Expand Down Expand Up @@ -91,7 +92,7 @@ public override MethodNameAndSignature NameAndSignature
}
}

public override ReadOnlySpan<byte> Name
public override Utf8Span Name
{
get
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
<Compile Include="$(LibrariesProjectRoot)\System.Private.CoreLib\src\System\Runtime\CompilerServices\IntrinsicAttribute.cs">
<Link>IntrinsicAttribute.cs</Link>
</Compile>
<Compile Include="$(CompilerCommonPath)\Internal\Text\Utf8Span.cs">
<Link>Internal\Text\Utf8Span.cs</Link>
</Compile>
<Compile Include="$(CompilerCommonPath)\TypeSystem\Canon\ArrayType.Canon.cs">
<Link>Internal\TypeSystem\ArrayType.Canon.cs</Link>
</Compile>
Expand Down
9 changes: 5 additions & 4 deletions src/coreclr/tools/Common/Compiler/AsyncContinuationType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Text;

using Internal.Text;
using Internal.TypeSystem;

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

public override DefType[] ExplicitlyImplementedInterfaces => [];
public override ReadOnlySpan<byte> Name => Encoding.UTF8.GetBytes(DiagnosticName);
public override ReadOnlySpan<byte> Namespace => [];
public override Utf8Span Name => Encoding.UTF8.GetBytes(DiagnosticName);
public override Utf8Span Namespace => Array.Empty<byte>();

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

public override bool HasCustomAttribute(string attributeNamespace, string attributeName) => false;
public override IEnumerable<MetadataType> GetNestedTypes() => [];
public override MetadataType GetNestedType(ReadOnlySpan<byte> name) => null;
public override MetadataType GetNestedType(Utf8Span name) => null;
protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() => [];
public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(ReadOnlySpan<byte> name) => [];
public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(Utf8Span name) => [];

protected override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer)
{
Expand Down
18 changes: 0 additions & 18 deletions src/coreclr/tools/Common/Compiler/Dataflow/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,5 @@ public static bool IsDeclaredOnType(this MethodDesc method, string fullTypeName)
return method.OwningType.IsTypeOf(fullTypeName);
}

public static bool StringEquals(this ReadOnlySpan<byte> utf8bytes, string value)
{
if (utf8bytes.Length < value.Length)
return false;

for (int i = 0; i < value.Length; i++)
{
int ch = utf8bytes[i];
if (ch > 0x7F)
return System.Text.Encoding.UTF8.GetString(utf8bytes) == value;

// We are assuming here that valid UTF8 encoded byte > 0x7F cannot map to a character with code point <= 0x7F
if (ch != value[i])
return false;
}

return utf8bytes.Length == value.Length; // All char ANSI, all matching
}
}
}
6 changes: 3 additions & 3 deletions src/coreclr/tools/Common/Compiler/InstructionSetSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static string GetHardwareIntrinsicId(TargetArchitecture architecture, Typ
return "";

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

if (architecture is TargetArchitecture.X64 or TargetArchitecture.X86)
{
if (!potentialType.Namespace.SequenceEqual("System.Runtime.Intrinsics.X86"u8))
if (potentialType.Namespace != "System.Runtime.Intrinsics.X86"u8)
return "";
}
else if (architecture is TargetArchitecture.ARM64 or TargetArchitecture.ARM)
{
if (!potentialType.Namespace.SequenceEqual("System.Runtime.Intrinsics.Arm"u8))
if (potentialType.Namespace != "System.Runtime.Intrinsics.Arm"u8)
return "";
}
else if (architecture is TargetArchitecture.LoongArch64)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristi
public static bool IsIntegerType(DefType type)
{
return type.IsIntrinsic
&& type.Namespace.SequenceEqual("System"u8)
&& (type.Name.SequenceEqual("Int128"u8) || type.Name.SequenceEqual("UInt128"u8));
&& type.Namespace == "System"u8
&& (type.Name == "Int128"u8 || type.Name == "UInt128"u8);
}
}
}
9 changes: 5 additions & 4 deletions src/coreclr/tools/Common/Compiler/MethodExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using ILCompiler.DependencyAnalysis;
using Internal.Text;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

Expand Down Expand Up @@ -142,11 +143,11 @@ public static bool ReturnsTaskOrValueTask(this MethodSignature method)

if (ret is MetadataType md
&& md.Module == method.Context.SystemModule
&& md.Namespace.SequenceEqual("System.Threading.Tasks"u8))
&& md.Namespace == "System.Threading.Tasks"u8)
{
ReadOnlySpan<byte> name = md.Name;
if (name.SequenceEqual("Task"u8) || name.SequenceEqual("Task`1"u8)
|| name.SequenceEqual("ValueTask"u8) || name.SequenceEqual("ValueTask`1"u8))
Utf8Span name = md.Name;
if (name == "Task"u8 || name == "Task`1"u8
|| name == "ValueTask"u8 || name == "ValueTask`1"u8)
{
return true;
}
Expand Down
8 changes: 5 additions & 3 deletions src/coreclr/tools/Common/Compiler/NativeAotNameMangler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ public override Utf8String CompilationUnitPrefix
public override Utf8String SanitizeName(Utf8String s)
=> SanitizeName(s.AsSpan());

private static Utf8String SanitizeName(ReadOnlySpan<byte> s)
private static Utf8String SanitizeName(Utf8Span n)
{
ReadOnlySpan<byte> s = n.AsSpan();

Utf8StringBuilder sb = null;
for (int i = 0; i < s.Length; i++)
{
Expand Down Expand Up @@ -98,7 +100,7 @@ private static bool ContainsUtf8ReplacementCharacter(ReadOnlySpan<byte> bytes)
return bytes.IndexOf(replacementCharacter) >= 0;
}

private Utf8String SanitizeNameWithHash(Utf8String literal, byte[] hash = null)
private static Utf8String SanitizeNameWithHash(Utf8String literal, byte[] hash = null)
{
Utf8String mangledName = SanitizeName(literal);

Expand Down Expand Up @@ -242,7 +244,7 @@ static void AppendTypeName(Utf8StringBuilder sb, MetadataType t)
}
else
{
ReadOnlySpan<byte> ns = t.Namespace;
Utf8Span ns = t.Namespace;
if (ns.Length > 0)
sb.Append(SanitizeName(ns)).Append('_');
}
Expand Down
13 changes: 7 additions & 6 deletions src/coreclr/tools/Common/Compiler/TypeMapMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Reflection.Metadata;
using ILCompiler.DependencyAnalysis;
using Internal.Text;
using Internal.IL;
using Internal.IL.Stubs;
using Internal.TypeSystem;
Expand All @@ -26,13 +27,13 @@ private enum TypeMapAttributeKind
private static TypeMapAttributeKind LookupTypeMapType(TypeDesc attrType)
{
var typeDef = attrType.GetTypeDefinition() as MetadataType;
if (typeDef != null && typeDef.Namespace.SequenceEqual("System.Runtime.InteropServices"u8))
if (typeDef != null && typeDef.Namespace == "System.Runtime.InteropServices"u8)
{
if (typeDef.Name.SequenceEqual("TypeMapAssemblyTargetAttribute`1"u8))
if (typeDef.Name == "TypeMapAssemblyTargetAttribute`1"u8)
return TypeMapAttributeKind.TypeMapAssemblyTarget;
else if (typeDef.Name.SequenceEqual("TypeMapAttribute`1"u8))
else if (typeDef.Name == "TypeMapAttribute`1"u8)
return TypeMapAttributeKind.TypeMap;
else if (typeDef.Name.SequenceEqual("TypeMapAssociationAttribute`1"u8))
else if (typeDef.Name == "TypeMapAssociationAttribute`1"u8)
return TypeMapAttributeKind.TypeMapAssociation;
}
return TypeMapAttributeKind.None;
Expand Down Expand Up @@ -66,7 +67,7 @@ public ThrowingMethodStub(TypeDesc owningType, TypeDesc typeMapGroup, bool exter
}

public TypeSystemException Exception { get; }
public override ReadOnlySpan<byte> Name => _name;
public override Utf8Span Name => _name;
public override MethodIL EmitIL()
{
#if READYTORUN
Expand All @@ -78,7 +79,7 @@ public override MethodIL EmitIL()

protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer)
{
return Name.SequenceCompareTo(other.Name);
return Name.AsSpan().SequenceCompareTo(other.Name.AsSpan());
}

public override bool IsPInvoke => false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp

LayoutInt alignment;

if (defType.Name.SequenceEqual("Vector64`1"u8))
if (defType.Name == "Vector64`1"u8)
{
alignment = new LayoutInt(8);
}
else if (defType.Name.SequenceEqual("Vector128`1"u8))
else if (defType.Name == "Vector128`1"u8)
{
if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
{
Expand All @@ -43,7 +43,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
alignment = new LayoutInt(16);
}
}
else if (defType.Name.SequenceEqual("Vector256`1"u8))
else if (defType.Name == "Vector256`1"u8)
{
if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
{
Expand Down Expand Up @@ -76,7 +76,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
}
else
{
Debug.Assert(defType.Name.SequenceEqual("Vector512`1"u8));
Debug.Assert(defType.Name == "Vector512`1"u8);

if (defType.Context.Target.Architecture == TargetArchitecture.ARM)
{
Expand Down Expand Up @@ -164,11 +164,11 @@ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristi
public static bool IsVectorType(DefType type)
{
return type.IsIntrinsic &&
type.Namespace.SequenceEqual("System.Runtime.Intrinsics"u8) &&
(type.Name.SequenceEqual("Vector64`1"u8) ||
type.Name.SequenceEqual("Vector128`1"u8) ||
type.Name.SequenceEqual("Vector256`1"u8) ||
type.Name.SequenceEqual("Vector512`1"u8));
type.Namespace == "System.Runtime.Intrinsics"u8 &&
(type.Name == "Vector64`1"u8 ||
type.Name == "Vector128`1"u8 ||
type.Name == "Vector256`1"u8 ||
type.Name == "Vector512`1"u8);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ public static ushort ComputeFlagsEx(TypeDesc type)

if (type is MetadataType mdType &&
mdType.Module == mdType.Context.SystemModule &&
(mdType.Name.SequenceEqual("WeakReference"u8) || mdType.Name.SequenceEqual("WeakReference`1"u8)) &&
mdType.Namespace.SequenceEqual("System"u8))
(mdType.Name == "WeakReference"u8 || mdType.Name == "WeakReference`1"u8) &&
mdType.Namespace == "System"u8)
{
flagsEx |= (ushort)EETypeFlagsEx.HasEagerFinalizerFlag;
}
Expand Down Expand Up @@ -273,8 +273,8 @@ private static bool HasCriticalFinalizer(TypeDesc type)

if (type is MetadataType mdType &&
mdType.Module == mdType.Context.SystemModule &&
mdType.Name.SequenceEqual("CriticalFinalizerObject"u8) &&
mdType.Namespace.SequenceEqual("System.Runtime.ConstrainedExecution"u8))
mdType.Name == "CriticalFinalizerObject"u8 &&
mdType.Namespace == "System.Runtime.ConstrainedExecution"u8)
return true;

type = type.BaseType;
Expand Down
69 changes: 69 additions & 0 deletions src/coreclr/tools/Common/Internal/Text/Utf8Span.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// 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.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Text;

namespace Internal.Text
{
public readonly ref struct Utf8Span
{
private readonly ReadOnlySpan<byte> _value;

public Utf8Span(ReadOnlySpan<byte> value) => _value = value;

public int Length => _value.Length;

public bool IsEmpty => _value.IsEmpty;

public ReadOnlySpan<byte> AsSpan() => _value;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion for the member: this could be a "Span" property ( public ReadOnlySpan<byte> Span => _value; ) similar to https://learn.microsoft.com/en-us/dotnet/api/system.readonlymemory-1.span?view=net-10.0#system-readonlymemory-1-span

Because it reads weird to have an AsSpan method on a type that is already named with the Span suffix.


public byte[] ToArray() => _value.ToArray();

public bool StartsWith(Utf8Span value) => _value.StartsWith(value.AsSpan());

public bool EndsWith(Utf8Span value) => _value.EndsWith(value.AsSpan());

// This is deliberately not a == operator because we don't want to make it easy
// to accidentally do UTF-8 vs UTF-16 string comparisons.
public bool StringEquals(string value)
{
if (_value.Length < value.Length)
return false;

for (int i = 0; i < value.Length; i++)
{
int ch = _value[i];
if (ch > 0x7F)
return Encoding.UTF8.GetString(_value) == value;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is perf critical, but it feel that a single char at the end of the utf8 _value could cause this branch to re-evaluate the complete string. Would it make sense to Slice the remaining parts of _value and value?


// We are assuming here that valid UTF8 encoded byte > 0x7F cannot map to a character with code point <= 0x7F
if (ch != value[i])
return false;
}

return _value.Length == value.Length; // All char ANSI, all matching
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would make sense to branch on the equality of _value.Length == value.Length and in case of equality use Ascii.Equals (which is vectorized) and otherwise do the loop.

}

public override bool Equals(object obj) => false;

public override int GetHashCode()
{
HashCode h = default;
h.AddBytes(_value);
return h.ToHashCode();
}

public override string ToString() => Encoding.UTF8.GetString(_value);

public static implicit operator Utf8Span(ReadOnlySpan<byte> s) => new Utf8Span(s);

public static bool operator ==(Utf8Span left, Utf8Span right)
=> left._value.SequenceEqual(right._value);

public static bool operator !=(Utf8Span left, Utf8Span right)
=> !left._value.SequenceEqual(right._value);
}
}
2 changes: 2 additions & 0 deletions src/coreclr/tools/Common/Internal/Text/Utf8String.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public Utf8String(string s)
_value = Encoding.UTF8.GetBytes(s);
}

public static implicit operator Utf8Span(Utf8String s) => s._value;

public int Length => _value.Length;

public ReadOnlySpan<byte> AsSpan() => _value;
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/tools/Common/Internal/Text/Utf8StringBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public Utf8StringBuilder Append(Utf8String value)
return Append(value.AsSpan());
}

public Utf8StringBuilder Append(Utf8Span value)
{
return Append(value.AsSpan());
}

public Utf8StringBuilder Append(ReadOnlySpan<byte> value)
{
Ensure(value.Length);
Expand Down
Loading
Loading