Skip to content

Commit 041933f

Browse files
authored
Add {ReadOnly}Span ctor (internal for now) that takes a ref and no length (#67447)
* Add {ReadOnly}Span ctor (internal for now) that takes an in and no length * Address PR feedback * Fix native references to _pointer
1 parent 135053e commit 041933f

24 files changed

+109
-89
lines changed

src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ public override bool IsCollectible
268268

269269
char c = Type.Delimiter;
270270
string resourceName = nameSpace != null && name != null ?
271-
string.Concat(nameSpace, new ReadOnlySpan<char>(ref c, 1), name) :
271+
string.Concat(nameSpace, new ReadOnlySpan<char>(in c), name) :
272272
string.Concat(nameSpace, name);
273273

274274
return GetManifestResourceStream(resourceName);

src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ public override MethodImplAttributes GetMethodImplementationFlags()
338338
}
339339

340340
StackAllocedArguments stackArgs = default;
341-
Span<object?> arguments = CheckArguments(ref stackArgs, new ReadOnlySpan<object?>(ref parameter, 1), binder, invokeAttr, culture, sig.Arguments);
341+
Span<object?> arguments = CheckArguments(ref stackArgs, new ReadOnlySpan<object?>(in parameter), binder, invokeAttr, culture, sig.Arguments);
342342

343343
bool wrapExceptions = (invokeAttr & BindingFlags.DoNotWrapExceptions) == 0;
344344
return RuntimeMethodHandle.InvokeMethod(obj, arguments, Signature, constructor: false, wrapExceptions);

src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal static unsafe byte ConvertToNative(char managedChar, bool fBestFit, boo
3535

3636
internal static char ConvertToManaged(byte nativeChar)
3737
{
38-
var bytes = new ReadOnlySpan<byte>(ref nativeChar, 1);
38+
var bytes = new ReadOnlySpan<byte>(in nativeChar);
3939
string str = Encoding.Default.GetString(bytes);
4040
return str[0];
4141
}

src/coreclr/jit/importer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -4080,7 +4080,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
40804080
// For Span<T>
40814081
// Comma
40824082
// BoundsCheck(index, s->_length)
4083-
// s->_pointer + index * sizeof(T)
4083+
// s->_reference + index * sizeof(T)
40844084
//
40854085
// For ReadOnlySpan<T> -- same expansion, as it now returns a readonly ref
40864086
//

src/coreclr/jit/morphblock.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,7 @@ void MorphCopyBlockHelper::MorphStructCases()
895895
}
896896
else if (m_srcDoFldAsg && srcFldIsProfitable)
897897
{
898-
// Check for the symmetric case (which happens for the _pointer field of promoted spans):
898+
// Check for the symmetric case (which happens for the _reference field of promoted spans):
899899
//
900900
// [000240] -----+------ /--* lclVar struct(P) V18 tmp9
901901
// /--* byref V18._value (offs=0x00) -> V30

src/coreclr/vm/object.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ class Span
748748
{
749749
private:
750750
/* Keep fields below in sync with managed Span / ReadOnlySpan layout. */
751-
KIND* _pointer;
751+
KIND* _reference;
752752
unsigned int _length;
753753

754754
public:
@@ -762,7 +762,7 @@ class Span
762762
LIMITED_METHOD_CONTRACT;
763763
SUPPORTS_DAC;
764764
_ASSERTE(index < GetLength());
765-
return _pointer[index];
765+
return _reference[index];
766766
}
767767

768768
// Gets the length (in elements) of this span.

src/libraries/System.Private.CoreLib/src/System/Array.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,12 @@ public static void Copy(Array sourceArray, long sourceIndex, Array destinationAr
239239
return InternalGetValue(GetFlattenedIndex(new ReadOnlySpan<int>(indices)));
240240
}
241241

242-
public unsafe object? GetValue(int index)
242+
public object? GetValue(int index)
243243
{
244244
if (Rank != 1)
245245
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_Need1DArray);
246246

247-
return InternalGetValue(GetFlattenedIndex(new ReadOnlySpan<int>(&index, 1)));
247+
return InternalGetValue(GetFlattenedIndex(new ReadOnlySpan<int>(in index)));
248248
}
249249

250250
public object? GetValue(int index1, int index2)
@@ -263,12 +263,12 @@ public static void Copy(Array sourceArray, long sourceIndex, Array destinationAr
263263
return InternalGetValue(GetFlattenedIndex(stackalloc int[] { index1, index2, index3 }));
264264
}
265265

266-
public unsafe void SetValue(object? value, int index)
266+
public void SetValue(object? value, int index)
267267
{
268268
if (Rank != 1)
269269
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_Need1DArray);
270270

271-
InternalSetValue(value, GetFlattenedIndex(new ReadOnlySpan<int>(&index, 1)));
271+
InternalSetValue(value, GetFlattenedIndex(new ReadOnlySpan<int>(in index)));
272272
}
273273

274274
public void SetValue(object? value, int index1, int index2)

src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public static CompareInfo GetCompareInfo(string name!!)
110110

111111
public static bool IsSortable(char ch)
112112
{
113-
return IsSortable(MemoryMarshal.CreateReadOnlySpan(ref ch, 1));
113+
return IsSortable(new ReadOnlySpan<char>(in ch));
114114
}
115115

116116
public static bool IsSortable(string text!!)
@@ -785,7 +785,7 @@ public int IndexOf(string source, char value, CompareOptions options)
785785
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
786786
}
787787

788-
return IndexOf(source, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options);
788+
return IndexOf(source, new ReadOnlySpan<char>(in value), options);
789789
}
790790

791791
public int IndexOf(string source, string value, CompareOptions options)
@@ -865,7 +865,7 @@ public unsafe int IndexOf(string source, char value, int startIndex, int count,
865865
}
866866
}
867867

868-
int result = IndexOf(sourceSpan, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options);
868+
int result = IndexOf(sourceSpan, new ReadOnlySpan<char>(in value), options);
869869
if (result >= 0)
870870
{
871871
result += startIndex;
@@ -1118,7 +1118,7 @@ public int LastIndexOf(string source, char value, CompareOptions options)
11181118
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
11191119
}
11201120

1121-
return LastIndexOf(source, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options);
1121+
return LastIndexOf(source, new ReadOnlySpan<char>(in value), options);
11221122
}
11231123

11241124
public int LastIndexOf(string source, string value, CompareOptions options)
@@ -1213,7 +1213,7 @@ public int LastIndexOf(string source, char value, int startIndex, int count, Com
12131213
ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
12141214
}
12151215

1216-
int retVal = LastIndexOf(sourceSpan, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options);
1216+
int retVal = LastIndexOf(sourceSpan, new ReadOnlySpan<char>(in value), options);
12171217
if (retVal >= 0)
12181218
{
12191219
retVal += startIndex;

src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ private static StringBuilder FormatCustomized(
715715
if (nextChar >= 0 && nextChar != '%')
716716
{
717717
char nextCharChar = (char)nextChar;
718-
StringBuilder origStringBuilder = FormatCustomized(dateTime, MemoryMarshal.CreateReadOnlySpan<char>(ref nextCharChar, 1), dtfi, offset, result);
718+
StringBuilder origStringBuilder = FormatCustomized(dateTime, new ReadOnlySpan<char>(in nextCharChar), dtfi, offset, result);
719719
Debug.Assert(ReferenceEquals(origStringBuilder, result));
720720
tokenLen = 2;
721721
}

src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ private static StringBuilder FormatCustomized(TimeSpan value, ReadOnlySpan<char>
437437
if (nextChar >= 0 && nextChar != (int)'%')
438438
{
439439
char nextCharChar = (char)nextChar;
440-
StringBuilder origStringBuilder = FormatCustomized(value, MemoryMarshal.CreateReadOnlySpan<char>(ref nextCharChar, 1), dtfi, result);
440+
StringBuilder origStringBuilder = FormatCustomized(value, new ReadOnlySpan<char>(in nextCharChar), dtfi, result);
441441
Debug.Assert(ReferenceEquals(origStringBuilder, result));
442442
tokenLen = 2;
443443
}

src/libraries/System.Private.CoreLib/src/System/Guid.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ private static bool TryParseExactD(ReadOnlySpan<char> guidString, ref GuidResult
385385
return false;
386386
}
387387

388-
Span<byte> bytes = MemoryMarshal.AsBytes(new Span<GuidResult>(ref result, 1));
388+
Span<byte> bytes = MemoryMarshal.AsBytes(new Span<GuidResult>(ref result));
389389
int invalidIfNegative = 0;
390390
bytes[0] = DecodeByte(guidString[6], guidString[7], ref invalidIfNegative);
391391
bytes[1] = DecodeByte(guidString[4], guidString[5], ref invalidIfNegative);
@@ -471,7 +471,7 @@ private static bool TryParseExactN(ReadOnlySpan<char> guidString, ref GuidResult
471471
return false;
472472
}
473473

474-
Span<byte> bytes = MemoryMarshal.AsBytes(new Span<GuidResult>(ref result, 1));
474+
Span<byte> bytes = MemoryMarshal.AsBytes(new Span<GuidResult>(ref result));
475475
int invalidIfNegative = 0;
476476
bytes[0] = DecodeByte(guidString[6], guidString[7], ref invalidIfNegative);
477477
bytes[1] = DecodeByte(guidString[4], guidString[5], ref invalidIfNegative);

src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public virtual void Write(char ch)
194194
buffer = rented;
195195
}
196196

197-
int actualByteCount = _encoding.GetBytes(MemoryMarshal.CreateReadOnlySpan(ref ch, 1), buffer);
197+
int actualByteCount = _encoding.GetBytes(new ReadOnlySpan<char>(in ch), buffer);
198198
OutStream.Write(buffer.Slice(0, actualByteCount));
199199

200200
if (rented != null)

src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,10 @@ protected unsafe void SetLengthCore(long value)
202202
}
203203
}
204204

205-
public sealed override unsafe int ReadByte()
205+
public sealed override int ReadByte()
206206
{
207-
byte b;
208-
return Read(new Span<byte>(&b, 1)) != 0 ? b : -1;
207+
byte b = 0;
208+
return Read(new Span<byte>(ref b)) != 0 ? b : -1;
209209
}
210210

211211
public sealed override int Read(byte[] buffer, int offset, int count) =>
@@ -229,8 +229,8 @@ public sealed override int Read(Span<byte> buffer)
229229
return r;
230230
}
231231

232-
public sealed override unsafe void WriteByte(byte value) =>
233-
Write(new ReadOnlySpan<byte>(&value, 1));
232+
public sealed override void WriteByte(byte value) =>
233+
Write(new ReadOnlySpan<byte>(in value));
234234

235235
public override void Write(byte[] buffer, int offset, int count) =>
236236
Write(new ReadOnlySpan<byte>(buffer, offset, count));

src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs

+25-15
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace System
2323
public readonly ref struct ReadOnlySpan<T>
2424
{
2525
/// <summary>A byref or a native ptr.</summary>
26-
internal readonly ByReference<T> _pointer;
26+
internal readonly ByReference<T> _reference;
2727
/// <summary>The number of elements this ReadOnlySpan contains.</summary>
2828
private readonly int _length;
2929

@@ -41,7 +41,7 @@ public ReadOnlySpan(T[]? array)
4141
return; // returns default
4242
}
4343

44-
_pointer = new ByReference<T>(ref MemoryMarshal.GetArrayDataReference(array));
44+
_reference = new ByReference<T>(ref MemoryMarshal.GetArrayDataReference(array));
4545
_length = array.Length;
4646
}
4747

@@ -75,7 +75,7 @@ public ReadOnlySpan(T[]? array, int start, int length)
7575
ThrowHelper.ThrowArgumentOutOfRangeException();
7676
#endif
7777

78-
_pointer = new ByReference<T>(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */));
78+
_reference = new ByReference<T>(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */));
7979
_length = length;
8080
}
8181

@@ -102,17 +102,27 @@ public unsafe ReadOnlySpan(void* pointer, int length)
102102
if (length < 0)
103103
ThrowHelper.ThrowArgumentOutOfRangeException();
104104

105-
_pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
105+
_reference = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
106106
_length = length;
107107
}
108108

109+
// TODO https://github.com/dotnet/runtime/issues/67445: Make this public.
110+
/// <summary>Creates a new <see cref="ReadOnlySpan{T}"/> of length 1 around the specified reference.</summary>
111+
/// <param name="reference">A reference to data.</param>
112+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
113+
internal ReadOnlySpan(in T reference)
114+
{
115+
_reference = new ByReference<T>(ref Unsafe.AsRef(in reference));
116+
_length = 1;
117+
}
118+
109119
// Constructor for internal use only.
110120
[MethodImpl(MethodImplOptions.AggressiveInlining)]
111-
internal ReadOnlySpan(ref T ptr, int length)
121+
internal ReadOnlySpan(ref T reference, int length)
112122
{
113123
Debug.Assert(length >= 0);
114124

115-
_pointer = new ByReference<T>(ref ptr);
125+
_reference = new ByReference<T>(ref reference);
116126
_length = length;
117127
}
118128

@@ -133,7 +143,7 @@ public ref readonly T this[int index]
133143
{
134144
if ((uint)index >= (uint)_length)
135145
ThrowHelper.ThrowIndexOutOfRangeException();
136-
return ref Unsafe.Add(ref _pointer.Value, (nint)(uint)index /* force zero-extension */);
146+
return ref Unsafe.Add(ref _reference.Value, (nint)(uint)index /* force zero-extension */);
137147
}
138148
}
139149

@@ -251,7 +261,7 @@ public ref readonly T GetPinnableReference()
251261
{
252262
// Ensure that the native code has just one forward branch that is predicted-not-taken.
253263
ref T ret = ref Unsafe.NullRef<T>();
254-
if (_length != 0) ret = ref _pointer.Value;
264+
if (_length != 0) ret = ref _reference.Value;
255265
return ref ret;
256266
}
257267

@@ -274,7 +284,7 @@ public void CopyTo(Span<T> destination)
274284

275285
if ((uint)_length <= (uint)destination.Length)
276286
{
277-
Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (uint)_length);
287+
Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length);
278288
}
279289
else
280290
{
@@ -295,7 +305,7 @@ public bool TryCopyTo(Span<T> destination)
295305
bool retVal = false;
296306
if ((uint)_length <= (uint)destination.Length)
297307
{
298-
Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (uint)_length);
308+
Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length);
299309
retVal = true;
300310
}
301311
return retVal;
@@ -307,7 +317,7 @@ public bool TryCopyTo(Span<T> destination)
307317
/// </summary>
308318
public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right) =>
309319
left._length == right._length &&
310-
Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
320+
Unsafe.AreSame<T>(ref left._reference.Value, ref right._reference.Value);
311321

312322
/// <summary>
313323
/// For <see cref="ReadOnlySpan{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
@@ -317,7 +327,7 @@ public override string ToString()
317327
{
318328
if (typeof(T) == typeof(char))
319329
{
320-
return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _pointer.Value), _length));
330+
return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _reference.Value), _length));
321331
}
322332
return $"System.ReadOnlySpan<{typeof(T).Name}>[{_length}]";
323333
}
@@ -335,7 +345,7 @@ public ReadOnlySpan<T> Slice(int start)
335345
if ((uint)start > (uint)_length)
336346
ThrowHelper.ThrowArgumentOutOfRangeException();
337347

338-
return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, (nint)(uint)start /* force zero-extension */), _length - start);
348+
return new ReadOnlySpan<T>(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), _length - start);
339349
}
340350

341351
/// <summary>
@@ -358,7 +368,7 @@ public ReadOnlySpan<T> Slice(int start, int length)
358368
ThrowHelper.ThrowArgumentOutOfRangeException();
359369
#endif
360370

361-
return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, (nint)(uint)start /* force zero-extension */), length);
371+
return new ReadOnlySpan<T>(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), length);
362372
}
363373

364374
/// <summary>
@@ -372,7 +382,7 @@ public T[] ToArray()
372382
return Array.Empty<T>();
373383

374384
var destination = new T[_length];
375-
Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _pointer.Value, (uint)_length);
385+
Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference.Value, (uint)_length);
376386
return destination;
377387
}
378388
}

src/libraries/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ private static ResourceSet InternalGetResourceSetFromSerializedData(Stream store
343343

344344
char c = Type.Delimiter;
345345
string resourceName = nameSpace != null && name != null ?
346-
string.Concat(nameSpace, new ReadOnlySpan<char>(ref c, 1), name) :
346+
string.Concat(nameSpace, new ReadOnlySpan<char>(in c), name) :
347347
string.Concat(nameSpace, name);
348348

349349
string? canonicalName = null;

0 commit comments

Comments
 (0)