Author: Danny Milosavljevic Date: 2026-04-08 Subject: Avoid ReadOnlySpan since it's unavailable in mono runtime. Avoid CodePagesEncodingProvider. diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs --- a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs 2026-04-08 05:54:06.286349563 +0000 @@ -536,16 +536,16 @@ // TODO(https://github.com/dotnet/corefx/issues/34126): Remove when System.Collections.Immutable // provides a Span API internal static T[] DangerousGetUnderlyingArray(this ImmutableArray array) - => Unsafe.As, ImmutableArrayProxy>(ref array).MutableArray; + => array.ToArray(); - internal static ReadOnlySpan AsSpan(this ImmutableArray array) + internal static T[] AsSpan(this ImmutableArray array) => array.DangerousGetUnderlyingArray(); internal static ImmutableArray DangerousCreateFromUnderlyingArray(ref T[] array) { var proxy = new ImmutableArrayProxy { MutableArray = array }; array = null; - return Unsafe.As, ImmutableArray>(ref proxy); + return ImmutableArray.CreateRange(array); } internal static Dictionary> ToDictionary(this ImmutableArray items, Func keySelector, IEqualityComparer comparer = null) diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/DiaSymReader/Writer/SymUnmanagedWriter.cs b/src/Compilers/Core/Portable/DiaSymReader/Writer/SymUnmanagedWriter.cs --- a/src/Compilers/Core/Portable/DiaSymReader/Writer/SymUnmanagedWriter.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/DiaSymReader/Writer/SymUnmanagedWriter.cs 2026-04-08 05:53:11.281396854 +0000 @@ -44,7 +44,7 @@ /// Object has been disposed. /// Writes are not allowed to the underlying stream. /// Error occurred while writing PDB data. - public abstract int DefineDocument(string name, Guid language, Guid vendor, Guid type, Guid algorithmId, ReadOnlySpan checksum, ReadOnlySpan source); + public abstract int DefineDocument(string name, Guid language, Guid vendor, Guid type, Guid algorithmId, byte[] checksum, byte[] source); /// /// Defines sequence points. @@ -127,8 +127,8 @@ int moveNextMethodToken, int kickoffMethodToken, int catchHandlerOffset, - ReadOnlySpan yieldOffsets, - ReadOnlySpan resumeOffsets); + int[] yieldOffsets, + int[] resumeOffsets); /// /// Associates custom debug information blob with the current method. diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/DiaSymReader/Writer/SymUnmanagedWriterImpl.cs b/src/Compilers/Core/Portable/DiaSymReader/Writer/SymUnmanagedWriterImpl.cs --- a/src/Compilers/Core/Portable/DiaSymReader/Writer/SymUnmanagedWriterImpl.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/DiaSymReader/Writer/SymUnmanagedWriterImpl.cs 2026-04-08 05:53:11.284206429 +0000 @@ -137,7 +137,7 @@ } } - public override int DefineDocument(string name, Guid language, Guid vendor, Guid type, Guid algorithmId, ReadOnlySpan checksum, ReadOnlySpan source) + public override int DefineDocument(string name, Guid language, Guid vendor, Guid type, Guid algorithmId, byte[] checksum, byte[] source) { if (name == null) { @@ -468,8 +468,8 @@ int moveNextMethodToken, int kickoffMethodToken, int catchHandlerOffset, - ReadOnlySpan yieldOffsets, - ReadOnlySpan resumeOffsets) + int[] yieldOffsets, + int[] resumeOffsets) { if (yieldOffsets == null) throw new ArgumentNullException(nameof(yieldOffsets)); if (resumeOffsets == null) throw new ArgumentNullException(nameof(resumeOffsets)); diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs --- a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs 2026-04-08 05:53:11.288964327 +0000 @@ -180,7 +180,7 @@ /// The sequence of bytes that are likely to be ASCII text. /// True if the sequence contains only characters in the ASCII range. /// The FNV-1a hash of - internal static int GetFNVHashCode(ReadOnlySpan data, out bool isAscii) + internal static int GetFNVHashCode(byte[] data, out bool isAscii) { int hashCode = Hash.FnvOffsetBias; diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/InternalUtilities/LittleEndianReader.cs b/src/Compilers/Core/Portable/InternalUtilities/LittleEndianReader.cs --- a/src/Compilers/Core/Portable/InternalUtilities/LittleEndianReader.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/InternalUtilities/LittleEndianReader.cs 2026-04-08 05:53:11.294122253 +0000 @@ -3,60 +3,58 @@ using System; -using Roslyn.Utilities; -using static System.Buffers.Binary.BinaryPrimitives; -namespace Microsoft.CodeAnalysis +namespace Roslyn.Utilities { - /// - /// A Span-compatible version of . - /// - internal ref struct LittleEndianReader + internal struct LittleEndianReader { - private ReadOnlySpan _span; + private readonly byte[] _data; + private int _offset; - public LittleEndianReader(ReadOnlySpan span) + public LittleEndianReader(byte[] data) { - _span = span; + _data = data; + _offset = 0; } internal uint ReadUInt32() { - var result = ReadUInt32LittleEndian(_span); - _span = _span.Slice(sizeof(uint)); + var result = (uint)(_data[_offset] | _data[_offset+1] << 8 | + _data[_offset+2] << 16 | _data[_offset+3] << 24); + _offset += sizeof(uint); return result; } internal byte ReadByte() { - var result = _span[0]; - _span = _span.Slice(sizeof(byte)); - return result; + return _data[_offset++]; } internal ushort ReadUInt16() { - var result = ReadUInt16LittleEndian(_span); - _span = _span.Slice(sizeof(ushort)); + var result = (ushort)(_data[_offset] | _data[_offset+1] << 8); + _offset += sizeof(ushort); return result; } - internal ReadOnlySpan ReadBytes(int byteCount) + internal byte[] ReadBytes(int byteCount) { - var result = _span.Slice(0, byteCount); - _span = _span.Slice(byteCount); + var result = new byte[byteCount]; + Array.Copy(_data, _offset, result, 0, byteCount); + _offset += byteCount; return result; } internal int ReadInt32() { - var result = ReadInt32LittleEndian(_span); - _span = _span.Slice(sizeof(int)); + var result = _data[_offset] | _data[_offset+1] << 8 | + _data[_offset+2] << 16 | _data[_offset+3] << 24; + _offset += sizeof(int); return result; } - internal byte[] ReadReversed(int byteCount) + internal byte[] ReadReversed(int count) { - var result = ReadBytes(byteCount).ToArray(); - result.ReverseContents(); + var result = ReadBytes(count); + Array.Reverse(result); return result; } } diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/InternalUtilities/StringTable.cs b/src/Compilers/Core/Portable/InternalUtilities/StringTable.cs --- a/src/Compilers/Core/Portable/InternalUtilities/StringTable.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/InternalUtilities/StringTable.cs 2026-04-08 05:53:11.304611873 +0000 @@ -109,7 +109,7 @@ internal string Add(char[] chars, int start, int len) { - var span = chars.AsSpan(start, len); + var span = new string(chars, start, len).ToCharArray(); var hashCode = Hash.GetFNVHashCode(chars, start, len); // capture array to avoid extra range checks @@ -295,7 +295,7 @@ if (e != null) { - if (hash == hashCode && TextEquals(e, chars.AsSpan(start, len))) + if (hash == hashCode && TextEquals(e, new string(chars, start, len).ToCharArray())) { break; } @@ -350,7 +350,7 @@ return e; } - private static string FindSharedEntryASCII(int hashCode, ReadOnlySpan asciiChars) + private static string FindSharedEntryASCII(int hashCode, byte[] asciiChars) { var arr = s_sharedTable; int idx = SharedIdxFromHash(hashCode); @@ -581,7 +581,7 @@ return text; } - internal static string AddSharedUTF8(ReadOnlySpan bytes) + internal static string AddSharedUTF8(byte[] bytes) { bool isAscii; int hashCode = Hash.GetFNVHashCode(bytes, out isAscii); @@ -598,13 +598,13 @@ return AddSharedSlow(hashCode, bytes, isAscii); } - private static string AddSharedSlow(int hashCode, ReadOnlySpan utf8Bytes, bool isAscii) + private static string AddSharedSlow(int hashCode, byte[] utf8Bytes, bool isAscii) { string text; unsafe { - fixed (byte* bytes = &utf8Bytes.GetPinnableReference()) + fixed (byte* bytes = utf8Bytes) { text = Encoding.UTF8.GetString(bytes, utf8Bytes.Length); } @@ -711,7 +711,7 @@ return true; } - internal static bool TextEqualsASCII(string text, ReadOnlySpan ascii) + internal static bool TextEqualsASCII(string text, byte[] ascii) { #if DEBUG for (var i = 0; i < ascii.Length; i++) @@ -736,7 +736,7 @@ return true; } - internal static bool TextEquals(string array, ReadOnlySpan text) - => text.Equals(array.AsSpan(), StringComparison.Ordinal); + internal static bool TextEquals(string array, char[] text) + => string.Equals(new string(text), array, StringComparison.Ordinal); } } diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/InternalUtilities/TextKeyedCache.cs b/src/Compilers/Core/Portable/InternalUtilities/TextKeyedCache.cs --- a/src/Compilers/Core/Portable/InternalUtilities/TextKeyedCache.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/InternalUtilities/TextKeyedCache.cs 2026-04-08 05:53:11.307139611 +0000 @@ -118,7 +118,7 @@ if (text != null && localSlot.HashCode == hashCode) { - if (StringTable.TextEquals(text, chars.AsSpan(start, len))) + if (StringTable.TextEquals(text, new string(chars, start, len).ToCharArray())) { return localSlot.Item; } @@ -155,7 +155,7 @@ if (e != null) { - if (hash == hashCode && StringTable.TextEquals(e.Text, chars.AsSpan(start, len))) + if (hash == hashCode && StringTable.TextEquals(e.Text, new string(chars, start, len).ToCharArray())) { break; } diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs 2026-04-08 05:53:11.309561450 +0000 @@ -3197,7 +3197,7 @@ public unsafe override string GetString(byte* bytes, int byteCount) { - return StringTable.AddSharedUTF8(new ReadOnlySpan(bytes, byteCount)); + var arr = new byte[byteCount]; System.Runtime.InteropServices.Marshal.Copy((System.IntPtr)bytes, arr, 0, byteCount); return StringTable.AddSharedUTF8(arr); } } diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs --- a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs 2026-04-08 05:53:11.272402967 +0000 @@ -573,8 +573,8 @@ } Guid algorithmId; - ReadOnlySpan checksum; - ReadOnlySpan embeddedSource; + byte[] checksum; + byte[] embeddedSource; DebugSourceInfo info = document.GetSourceInfo(); if (!info.Checksum.IsDefault) diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs b/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs --- a/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs 2026-04-08 05:58:24.049035340 +0000 @@ -311,7 +311,7 @@ } // Returns whether we should proceed to the destination after finallies were taken care of. - static bool stepThroughFinally(ControlFlowRegion region, BasicBlockBuilder destination) + bool stepThroughFinally(ControlFlowRegion region, BasicBlockBuilder destination) { int destinationOrdinal = destination.Ordinal; while (!region.ContainsBlock(destinationOrdinal)) diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/StrongName/CryptoBlobParser.cs b/src/Compilers/Core/Portable/StrongName/CryptoBlobParser.cs --- a/src/Compilers/Core/Portable/StrongName/CryptoBlobParser.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/StrongName/CryptoBlobParser.cs 2026-04-08 05:53:11.269852517 +0000 @@ -153,7 +153,7 @@ uint magic, uint bitLen, uint pubExp, - ReadOnlySpan pubKeyData) + byte[] pubKeyData) { var w = new BlobWriter(3 * sizeof(uint) + s_offsetToKeyData + pubKeyData.Length); w.WriteUInt32(AlgorithmId.RsaSign); @@ -250,7 +250,7 @@ /// Helper for RsaCryptoServiceProvider.ExportParameters() /// Copied from https://github.com/dotnet/corefx/blob/5fe5f9aae7b2987adc7082f90712b265bee5eefc/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Shared.cs /// - internal static RSAParameters ToRSAParameters(this ReadOnlySpan cspBlob, bool includePrivateParameters) + internal static RSAParameters ToRSAParameters(this byte[] cspBlob, bool includePrivateParameters) { var br = new LittleEndianReader(cspBlob); diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Core/Portable/Syntax/GreenNode.cs b/src/Compilers/Core/Portable/Syntax/GreenNode.cs --- a/src/Compilers/Core/Portable/Syntax/GreenNode.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Core/Portable/Syntax/GreenNode.cs 2026-04-08 05:59:21.736658738 +0000 @@ -649,11 +649,11 @@ // Separated out stack processing logic so that it does not unintentionally refer to // "this", "leading" or "trailing". - processStack(writer, stack); + processStack_inner(writer, stack); stack.Free(); return; - static void processStack( + void processStack_inner( TextWriter writer, ArrayBuilder<(GreenNode node, bool leading, bool trailing)> stack) { diff -ruN '--exclude=*.resx' '--exclude=*.xlf' '--exclude=*.xml' '--exclude=*.rsp' '--exclude=srm-src-patched' '--exclude=*.resources' '--exclude=bootstrap-*' '--exclude=*.dll' '--exclude=*.exe' '--exclude=srm-strings.cs' '--exclude=generated' a/src/Compilers/Shared/DesktopBuildClient.cs b/src/Compilers/Shared/DesktopBuildClient.cs --- a/src/Compilers/Shared/DesktopBuildClient.cs 2019-07-09 03:30:24.000000000 +0000 +++ b/src/Compilers/Shared/DesktopBuildClient.cs 2026-04-08 05:53:11.316016422 +0000 @@ -33,7 +33,7 @@ { // Register encodings for console // https://github.com/dotnet/roslyn/issues/10785 - System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); + // not available in Mono } var client = new DesktopBuildClient(language, compileFunc, analyzerAssemblyLoader);