From be3c1f7dd86469151b6344727506655fd5ce9faf Mon Sep 17 00:00:00 2001 From: Anthony Abate Date: Thu, 2 Jan 2020 23:35:19 -0500 Subject: [PATCH] work around for bug in Jitter / System.Memory See: https://github.com/dotnet/coreclr/issues/27590 --- .../src/Apache.Arrow/ArrowBuffer.Builder.cs | 6 +-- .../Apache.Arrow/Extensions/SpanExtensions.cs | 47 +++++++++++++++++++ .../StreamExtensions.netstandard.cs | 6 +-- .../Flatbuf/FlatBuffers/ByteBuffer.cs | 5 +- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs b/csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs index 699f72a0eeefb..2d2986acedbe9 100644 --- a/csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs +++ b/csharp/src/Apache.Arrow/ArrowBuffer.Builder.cs @@ -62,7 +62,7 @@ public Builder Append(T value) public Builder Append(ReadOnlySpan source) { EnsureCapacity(source.Length); - source.CopyTo(Span.Slice(Length, source.Length)); + source.CopyToFix(Span.Slice(Length, source.Length)); Length += source.Length; return this; } @@ -111,7 +111,7 @@ public ArrowBuffer Build(MemoryAllocator allocator = default) if (memoryOwner != null) { - Memory.Slice(0, currentBytesLength).CopyTo(memoryOwner.Memory); + Memory.Slice(0, currentBytesLength).CopyToFix(memoryOwner.Memory); } return new ArrowBuffer(memoryOwner); @@ -140,7 +140,7 @@ private void Reallocate(int length) if (length != 0) { var memory = new Memory(new byte[length]); - Memory.CopyTo(memory); + Memory.CopyToFix(memory); Memory = memory; } diff --git a/csharp/src/Apache.Arrow/Extensions/SpanExtensions.cs b/csharp/src/Apache.Arrow/Extensions/SpanExtensions.cs index b759f38060703..be78d4168ca03 100644 --- a/csharp/src/Apache.Arrow/Extensions/SpanExtensions.cs +++ b/csharp/src/Apache.Arrow/Extensions/SpanExtensions.cs @@ -14,18 +14,65 @@ // limitations under the License. using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Apache.Arrow { public static class SpanExtensions { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span CastTo(this Span span) where T: struct => MemoryMarshal.Cast(span); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ReadOnlySpan CastTo(this ReadOnlySpan span) where T: struct => MemoryMarshal.Cast(span); + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyToFix(this ReadOnlySpan source, Span target) + { + CopyToFix(source, 0, target, 0, source.Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyToFix(this ReadOnlySpan source, T[] target) + { + CopyToFix(source, 0, target, 0, source.Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyToFix(this Span source, Span target) + { + CopyToFix(source, 0, target, 0, source.Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyToFix(this Memory source, Memory target) + { + CopyToFix(source.Span, 0, target.Span, 0, source.Length); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyToFix(ReadOnlySpan source, int sourceOffset, Span target, int targetOffset, int length) + { + for (int i = 0; i < length; ++i) + { + target[targetOffset + i] = source[sourceOffset + i]; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyToFix(ReadOnlySpan source, int sourceOffset, T[] target, int targetOffset, int length) + { + for (int i = 0; i < length; ++i) + { + target[targetOffset + i] = source[sourceOffset + i]; + } + } } } diff --git a/csharp/src/Apache.Arrow/Extensions/StreamExtensions.netstandard.cs b/csharp/src/Apache.Arrow/Extensions/StreamExtensions.netstandard.cs index ce23bd1eb7bd5..c3b33c62f8d47 100644 --- a/csharp/src/Apache.Arrow/Extensions/StreamExtensions.netstandard.cs +++ b/csharp/src/Apache.Arrow/Extensions/StreamExtensions.netstandard.cs @@ -37,7 +37,7 @@ public static int Read(this Stream stream, Memory buffer) try { int result = stream.Read(sharedBuffer, 0, buffer.Length); - new Span(sharedBuffer, 0, result).CopyTo(buffer.Span); + new Span(sharedBuffer, 0, result).CopyToFix(buffer.Span); return result; } finally @@ -63,7 +63,7 @@ async ValueTask FinishReadAsync(Task readTask, byte[] localBuffer, Mem try { int result = await readTask.ConfigureAwait(false); - new Span(localBuffer, 0, result).CopyTo(localDestination.Span); + new Span(localBuffer, 0, result).CopyToFix(localDestination.Span); return result; } finally @@ -83,7 +83,7 @@ public static ValueTask WriteAsync(this Stream stream, ReadOnlyMemory buff else { byte[] sharedBuffer = ArrayPool.Shared.Rent(buffer.Length); - buffer.Span.CopyTo(sharedBuffer); + buffer.Span.CopyToFix(sharedBuffer); return FinishWriteAsync(stream.WriteAsync(sharedBuffer, 0, buffer.Length, cancellationToken), sharedBuffer); } } diff --git a/csharp/src/Apache.Arrow/Flatbuf/FlatBuffers/ByteBuffer.cs b/csharp/src/Apache.Arrow/Flatbuf/FlatBuffers/ByteBuffer.cs index 91cd5cccb647f..fb1e70c7438cb 100644 --- a/csharp/src/Apache.Arrow/Flatbuf/FlatBuffers/ByteBuffer.cs +++ b/csharp/src/Apache.Arrow/Flatbuf/FlatBuffers/ByteBuffer.cs @@ -41,6 +41,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using Apache.Arrow; #if ENABLE_SPAN_T using System.Buffers.Binary; @@ -833,7 +834,7 @@ public int Put(int offset, T[] x) AssertOffsetAndLength(offset, numBytes); // if we are LE, just do a block copy #if ENABLE_SPAN_T - MemoryMarshal.Cast(x).CopyTo(_buffer.Span.Slice(offset, numBytes)); + MemoryMarshal.Cast(x).CopyToFix(_buffer.Span.Slice(offset, numBytes)); #else Buffer.BlockCopy(x, 0, _buffer.Buffer, offset, numBytes); #endif @@ -872,7 +873,7 @@ public int Put(int offset, Span x) offset -= numBytes; AssertOffsetAndLength(offset, numBytes); // if we are LE, just do a block copy - MemoryMarshal.Cast(x).CopyTo(_buffer.Span.Slice(offset, numBytes)); + MemoryMarshal.Cast(x).CopyToFix(_buffer.Span.Slice(offset, numBytes)); } else {