Browse Source

Use for(...) dst[c]=src[c] loop on arm due to a JIT bug

pull/9817/head
Nikita Tsukanov 4 years ago
parent
commit
c099e2fd2c
  1. 53
      src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs

53
src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Avalonia.Rendering.Composition.Animations;
using Avalonia.Rendering.Composition.Server;
@ -27,6 +28,37 @@ public record struct BatchStreamSegment<TData>
public int ElementCount { get; set; }
}
// Unsafe.ReadUnaligned/Unsafe.WriteUnaligned are broken on arm,
// see https://github.com/dotnet/runtime/issues/80068
static unsafe class UnalignedMemoryHelper
{
public static T ReadUnaligned<T>(byte* src) where T : unmanaged
{
#if NET6_0_OR_GREATER
Unsafe.SkipInit<T>(out var rv);
#else
T rv;
#endif
UnalignedMemcpy((byte*)&rv, src, Unsafe.SizeOf<T>());
return rv;
}
public static void WriteUnaligned<T>(byte* dst, T value) where T : unmanaged
{
UnalignedMemcpy(dst, (byte*)&value, Unsafe.SizeOf<T>());
}
[MethodImpl(MethodImplOptions.NoInlining)]
static unsafe void UnalignedMemcpy(byte* dst, byte* src, int count)
{
for (var c = 0; c < count; c++)
{
dst[c] = src[c];
}
}
}
internal class BatchStreamWriter : IDisposable
{
private readonly BatchStreamData _output;
@ -74,7 +106,15 @@ internal class BatchStreamWriter : IDisposable
var size = Unsafe.SizeOf<T>();
if (_currentDataSegment.Data == IntPtr.Zero || _currentDataSegment.ElementCount + size > _memoryPool.BufferSize)
NextDataSegment();
Unsafe.WriteUnaligned<T>((byte*)_currentDataSegment.Data + _currentDataSegment.ElementCount, item);
var ptr = (byte*)_currentDataSegment.Data + _currentDataSegment.ElementCount;
// Unsafe.ReadUnaligned/Unsafe.WriteUnaligned are broken on arm32,
// see https://github.com/dotnet/runtime/issues/80068
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm)
UnalignedMemoryHelper.WriteUnaligned(ptr, item);
else
*(T*)ptr = item;
_currentDataSegment.ElementCount += size;
}
@ -125,7 +165,16 @@ internal class BatchStreamReader : IDisposable
if (_memoryOffset + size > _currentDataSegment.ElementCount)
throw new InvalidOperationException("Attempted to read more memory then left in the current segment");
var rv = Unsafe.ReadUnaligned<T>((byte*)_currentDataSegment.Data + _memoryOffset);
var ptr = (byte*)_currentDataSegment.Data + _memoryOffset;
T rv;
// Unsafe.ReadUnaligned/Unsafe.WriteUnaligned are broken on arm32,
// see https://github.com/dotnet/runtime/issues/80068
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm)
rv = UnalignedMemoryHelper.ReadUnaligned<T>(ptr);
else
rv = *(T*)ptr;
_memoryOffset += size;
if (_memoryOffset == _currentDataSegment.ElementCount)
{

Loading…
Cancel
Save