Skip to content

Commit f501153

Browse files
Sergio0694jkotas
andauthored
Optimize 'ConvertOrWidenPrimitivesEnumsAndPointersIfPossible' (#101858)
* Optimize 'ConvertOrWidenPrimitivesEnumsAndPointersIfPossible' * Add missing U4 -> U8 widening flag * Skip type checks when unboxing * Centralized boxing operations * Remove unnecessary code to handle enums * Combine 'Char' cases with 'UInt16' ones * Deduplicate the implementation between array and reflection --------- Co-authored-by: Jan Kotas <jkotas@microsoft.com>
1 parent c5c7f0d commit f501153

File tree

2 files changed

+204
-306
lines changed

2 files changed

+204
-306
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs

Lines changed: 17 additions & 246 deletions
Original file line numberDiff line numberDiff line change
@@ -526,255 +526,26 @@ private static unsafe void CopyImplPrimitiveTypeWithWidening(Array sourceArray,
526526
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_ConstrainedCopy);
527527
}
528528

529-
fixed (byte* pSrcArray = &MemoryMarshal.GetArrayDataReference(sourceArray), pDstArray = &MemoryMarshal.GetArrayDataReference(destinationArray))
530-
{
531-
byte* srcData = pSrcArray + (nuint)sourceIndex * srcElementSize;
532-
byte* data = pDstArray + (nuint)destinationIndex * destElementSize;
529+
ref byte srcData = ref Unsafe.AddByteOffset(ref MemoryMarshal.GetArrayDataReference(sourceArray), (nuint)sourceIndex * srcElementSize);
530+
ref byte dstData = ref Unsafe.AddByteOffset(ref MemoryMarshal.GetArrayDataReference(destinationArray), (nuint)destinationIndex * destElementSize);
533531

534-
if (sourceElementType == destElementType)
535-
{
536-
// Multidim arrays and enum->int copies can still reach this path.
537-
SpanHelpers.Memmove(ref *data, ref *srcData, (nuint)length * srcElementSize);
538-
return;
539-
}
532+
if (sourceElementType == destElementType)
533+
{
534+
// Multidim arrays and enum->int copies can still reach this path.
535+
SpanHelpers.Memmove(ref dstData, ref srcData, (nuint)length * srcElementSize);
536+
return;
537+
}
540538

541-
ulong dummyElementForZeroLengthCopies = 0;
542-
// If the element types aren't identical and the length is zero, we're still obliged to check the types for widening compatibility.
543-
// We do this by forcing the loop below to copy one dummy element.
544-
if (length == 0)
545-
{
546-
srcData = (byte*)&dummyElementForZeroLengthCopies;
547-
data = (byte*)&dummyElementForZeroLengthCopies;
548-
length = 1;
549-
}
539+
if (!InvokeUtils.CanPrimitiveWiden(destElementType, sourceElementType))
540+
{
541+
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
542+
}
550543

551-
for (int i = 0; i < length; i++, srcData += srcElementSize, data += destElementSize)
552-
{
553-
// We pretty much have to do some fancy datatype mangling every time here, for
554-
// converting w/ sign extension and floating point conversions.
555-
switch (sourceElementType)
556-
{
557-
case EETypeElementType.Byte:
558-
{
559-
switch (destElementType)
560-
{
561-
case EETypeElementType.Single:
562-
*(float*)data = *(byte*)srcData;
563-
break;
564-
565-
case EETypeElementType.Double:
566-
*(double*)data = *(byte*)srcData;
567-
break;
568-
569-
case EETypeElementType.Char:
570-
case EETypeElementType.Int16:
571-
case EETypeElementType.UInt16:
572-
*(short*)data = *(byte*)srcData;
573-
break;
574-
575-
case EETypeElementType.Int32:
576-
case EETypeElementType.UInt32:
577-
*(int*)data = *(byte*)srcData;
578-
break;
579-
580-
case EETypeElementType.Int64:
581-
case EETypeElementType.UInt64:
582-
*(long*)data = *(byte*)srcData;
583-
break;
584-
585-
default:
586-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
587-
}
588-
break;
589-
}
590-
591-
case EETypeElementType.SByte:
592-
switch (destElementType)
593-
{
594-
case EETypeElementType.Int16:
595-
*(short*)data = *(sbyte*)srcData;
596-
break;
597-
598-
case EETypeElementType.Int32:
599-
*(int*)data = *(sbyte*)srcData;
600-
break;
601-
602-
case EETypeElementType.Int64:
603-
*(long*)data = *(sbyte*)srcData;
604-
break;
605-
606-
case EETypeElementType.Single:
607-
*(float*)data = *(sbyte*)srcData;
608-
break;
609-
610-
case EETypeElementType.Double:
611-
*(double*)data = *(sbyte*)srcData;
612-
break;
613-
614-
default:
615-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
616-
}
617-
break;
618-
619-
case EETypeElementType.UInt16:
620-
case EETypeElementType.Char:
621-
switch (destElementType)
622-
{
623-
case EETypeElementType.Single:
624-
*(float*)data = *(ushort*)srcData;
625-
break;
626-
627-
case EETypeElementType.Double:
628-
*(double*)data = *(ushort*)srcData;
629-
break;
630-
631-
case EETypeElementType.UInt16:
632-
case EETypeElementType.Char:
633-
*(ushort*)data = *(ushort*)srcData;
634-
break;
635-
636-
case EETypeElementType.Int32:
637-
case EETypeElementType.UInt32:
638-
*(uint*)data = *(ushort*)srcData;
639-
break;
640-
641-
case EETypeElementType.Int64:
642-
case EETypeElementType.UInt64:
643-
*(ulong*)data = *(ushort*)srcData;
644-
break;
645-
646-
default:
647-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
648-
}
649-
break;
650-
651-
case EETypeElementType.Int16:
652-
switch (destElementType)
653-
{
654-
case EETypeElementType.Int32:
655-
*(int*)data = *(short*)srcData;
656-
break;
657-
658-
case EETypeElementType.Int64:
659-
*(long*)data = *(short*)srcData;
660-
break;
661-
662-
case EETypeElementType.Single:
663-
*(float*)data = *(short*)srcData;
664-
break;
665-
666-
case EETypeElementType.Double:
667-
*(double*)data = *(short*)srcData;
668-
break;
669-
670-
default:
671-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
672-
}
673-
break;
674-
675-
case EETypeElementType.Int32:
676-
switch (destElementType)
677-
{
678-
case EETypeElementType.Int64:
679-
*(long*)data = *(int*)srcData;
680-
break;
681-
682-
case EETypeElementType.Single:
683-
*(float*)data = (float)*(int*)srcData;
684-
break;
685-
686-
case EETypeElementType.Double:
687-
*(double*)data = *(int*)srcData;
688-
break;
689-
690-
default:
691-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
692-
}
693-
break;
694-
695-
case EETypeElementType.UInt32:
696-
switch (destElementType)
697-
{
698-
case EETypeElementType.Int64:
699-
case EETypeElementType.UInt64:
700-
*(long*)data = *(uint*)srcData;
701-
break;
702-
703-
case EETypeElementType.Single:
704-
*(float*)data = (float)*(uint*)srcData;
705-
break;
706-
707-
case EETypeElementType.Double:
708-
*(double*)data = *(uint*)srcData;
709-
break;
710-
711-
default:
712-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
713-
}
714-
break;
715-
716-
717-
case EETypeElementType.Int64:
718-
switch (destElementType)
719-
{
720-
case EETypeElementType.Single:
721-
*(float*)data = (float)*(long*)srcData;
722-
break;
723-
724-
case EETypeElementType.Double:
725-
*(double*)data = (double)*(long*)srcData;
726-
break;
727-
728-
default:
729-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
730-
}
731-
break;
732-
733-
case EETypeElementType.UInt64:
734-
switch (destElementType)
735-
{
736-
case EETypeElementType.Single:
737-
738-
//*(float*) data = (float) *(Ulong*)srcData;
739-
long srcValToFloat = *(long*)srcData;
740-
float f = (float)srcValToFloat;
741-
if (srcValToFloat < 0)
742-
f += 4294967296.0f * 4294967296.0f; // This is 2^64
743-
744-
*(float*)data = f;
745-
break;
746-
747-
case EETypeElementType.Double:
748-
//*(double*) data = (double) *(Ulong*)srcData;
749-
long srcValToDouble = *(long*)srcData;
750-
double d = (double)srcValToDouble;
751-
if (srcValToDouble < 0)
752-
d += 4294967296.0 * 4294967296.0; // This is 2^64
753-
754-
*(double*)data = d;
755-
break;
756-
757-
default:
758-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
759-
}
760-
break;
761-
762-
case EETypeElementType.Single:
763-
switch (destElementType)
764-
{
765-
case EETypeElementType.Double:
766-
*(double*)data = *(float*)srcData;
767-
break;
768-
769-
default:
770-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
771-
}
772-
break;
773-
774-
default:
775-
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
776-
}
777-
}
544+
for (int i = 0; i < length; i++)
545+
{
546+
InvokeUtils.PrimitiveWiden(destElementType, sourceElementType, ref dstData, ref srcData);
547+
srcData = ref Unsafe.AddByteOffset(ref srcData, srcElementSize);
548+
dstData = ref Unsafe.AddByteOffset(ref dstData, destElementSize);
778549
}
779550
}
780551

0 commit comments

Comments
 (0)