Skip to content

Commit

Permalink
[mono] Convert Array icalls to use ObjectHandleOnStack. (#77343)
Browse files Browse the repository at this point in the history
  • Loading branch information
vargaz authored Dec 7, 2022
1 parent 3c57211 commit a94fa06
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 117 deletions.
87 changes: 62 additions & 25 deletions src/mono/System.Private.CoreLib/src/System/Array.Mono.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ private static void Copy(Array sourceArray, int sourceIndex, Array destinationAr
if (destinationIndex < 0)
throw new ArgumentOutOfRangeException(nameof(destinationIndex), "Value has to be >= 0.");

if (FastCopy(sourceArray, sourceIndex, destinationArray, destinationIndex, length))
var src = sourceArray;
var dst = destinationArray;
if (FastCopy(ObjectHandleOnStack.Create(ref src), sourceIndex, ObjectHandleOnStack.Create(ref dst), destinationIndex, length))
return;

CopySlow(sourceArray, sourceIndex, destinationArray, destinationIndex, length, reliable);
Expand Down Expand Up @@ -168,7 +170,8 @@ private static void CopySlow(Array sourceArray, int sourceIndex, Array destinati
if (reliable)
{
if (!dst_type.Equals(src_type) &&
!(dst_type.IsPrimitive && src_type.IsPrimitive && CanChangePrimitive(ref dst_type, ref src_type, true)))
!(dst_type.IsPrimitive && src_type.IsPrimitive &&
CanChangePrimitive(ObjectHandleOnStack.Create(ref dst_type), ObjectHandleOnStack.Create(ref src_type), true)))
{
throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType);
}
Expand All @@ -181,18 +184,25 @@ private static void CopySlow(Array sourceArray, int sourceIndex, Array destinati
}
}

Array src = sourceArray;
ObjectHandleOnStack src_handle = ObjectHandleOnStack.Create(ref src);
Array dst = destinationArray;
ObjectHandleOnStack dst_handle = ObjectHandleOnStack.Create(ref dst);
object? srcval = null;
ObjectHandleOnStack val_handle = ObjectHandleOnStack.Create(ref srcval);

if (!ReferenceEquals(sourceArray, destinationArray) || source_pos > dest_pos)
{
for (int i = 0; i < length; i++)
{
object srcval = sourceArray.GetValueImpl(source_pos + i);
GetValueImpl(src_handle, val_handle, source_pos + i);

if (dst_type_vt && (srcval == null || (src_type == typeof(object) && !dst_elem_type.IsAssignableFrom (srcval.GetType()))))
throw new InvalidCastException(SR.InvalidCast_DownCastArrayElement);

try
{
destinationArray.SetValueRelaxedImpl(srcval, dest_pos + i);
SetValueRelaxedImpl(dst_handle, val_handle, dest_pos + i);
}
catch (ArgumentException)
{
Expand All @@ -204,11 +214,11 @@ private static void CopySlow(Array sourceArray, int sourceIndex, Array destinati
{
for (int i = length - 1; i >= 0; i--)
{
object srcval = sourceArray.GetValueImpl(source_pos + i);
GetValueImpl(src_handle, val_handle, source_pos + i);

try
{
destinationArray.SetValueRelaxedImpl(srcval, dest_pos + i);
SetValueRelaxedImpl(dst_handle, val_handle, dest_pos + i);
}
catch (ArgumentException)
{
Expand Down Expand Up @@ -254,9 +264,8 @@ private static bool CanAssignArrayElement(Type source, Type target)
}
else if (source.IsPrimitive && target.IsPrimitive)
{

// Allow primitive type widening
return CanChangePrimitive(ref source, ref target, false);
return CanChangePrimitive(ObjectHandleOnStack.Create(ref source), ObjectHandleOnStack.Create(ref target), false);
}
else if (!source.IsValueType && !source.IsPointer)
{
Expand Down Expand Up @@ -319,15 +328,19 @@ private unsafe nint GetFlattenedIndex(ReadOnlySpan<int> indices)
if (GetType().GetElementType()!.IsPointer)
throw new NotSupportedException(SR.NotSupported_Type);

return GetValueImpl((int)index);
Array self = this;
object? res = null;
GetValueImpl(ObjectHandleOnStack.Create(ref self), ObjectHandleOnStack.Create(ref res), (int)index);
return res;
}

internal void InternalSetValue(object? value, nint index)
{
if (GetType().GetElementType()!.IsPointer)
throw new NotSupportedException(SR.NotSupported_Type);

SetValueImpl(value, (int)index);
Array self = this;
SetValueImpl(ObjectHandleOnStack.Create(ref self), ObjectHandleOnStack.Create(ref value), (int)index);
}

public void Initialize()
Expand All @@ -351,68 +364,92 @@ public int GetUpperBound(int dimension)
return GetLowerBound(dimension) + GetLength(dimension) - 1;
}

internal CorElementType GetCorElementTypeOfElementType()
{
object arr = this;
return GetCorElementTypeOfElementTypeInternal(ObjectHandleOnStack.Create(ref arr));
}

private bool IsValueOfElementType(object value)
{
object arr = this;
return IsValueOfElementTypeInternal(ObjectHandleOnStack.Create(ref arr), ObjectHandleOnStack.Create(ref value));
}

[Intrinsic] // when dimension is `0` constant
public int GetLength(int dimension)
{
object arr = this;
return GetLengthInternal(ObjectHandleOnStack.Create(ref arr), dimension);
}

[Intrinsic] // when dimension is `0` constant
public int GetLowerBound(int dimension)
{
object arr = this;
return GetLowerBoundInternal(ObjectHandleOnStack.Create(ref arr), dimension);
}

[Intrinsic]
internal int GetElementSize() => GetElementSize();

[Intrinsic]
internal bool IsPrimitive() => IsPrimitive();

[MethodImpl(MethodImplOptions.InternalCall)]
internal extern CorElementType GetCorElementTypeOfElementType();
private static extern CorElementType GetCorElementTypeOfElementTypeInternal(ObjectHandleOnStack arr);

[MethodImpl(MethodImplOptions.InternalCall)]
private extern bool IsValueOfElementType(object value);
private static extern bool IsValueOfElementTypeInternal(ObjectHandleOnStack arr, ObjectHandleOnStack obj);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern bool CanChangePrimitive(ref Type srcType, ref Type dstType, bool reliable);
private static extern bool CanChangePrimitive(ObjectHandleOnStack srcType, ObjectHandleOnStack dstType, bool reliable);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool FastCopy(Array source, int source_idx, Array dest, int dest_idx, int length);
internal static extern bool FastCopy(ObjectHandleOnStack source, int source_idx, ObjectHandleOnStack dest, int dest_idx, int length);

[Intrinsic] // when dimension is `0` constant
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern int GetLength(int dimension);
private static extern int GetLengthInternal(ObjectHandleOnStack arr, int dimension);

[Intrinsic] // when dimension is `0` constant
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern int GetLowerBound(int dimension);
private static extern int GetLowerBoundInternal(ObjectHandleOnStack arr, int dimension);

// CAUTION! No bounds checking!
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern void GetGenericValue_icall<T>(ref Array self, int pos, out T value);
private static extern void GetGenericValue_icall<T>(ObjectHandleOnStack self, int pos, out T value);

// CAUTION! No bounds checking!
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern object GetValueImpl(int pos);
private static extern void GetValueImpl(ObjectHandleOnStack arr, ObjectHandleOnStack res, int pos);

// CAUTION! No bounds checking!
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern void SetGenericValue_icall<T>(ref Array self, int pos, ref T value);
private static extern void SetGenericValue_icall<T>(ObjectHandleOnStack arr, int pos, ref T value);

[Intrinsic]
private void GetGenericValueImpl<T>(int pos, out T value)
{
Array self = this;
GetGenericValue_icall(ref self, pos, out value);
GetGenericValue_icall(ObjectHandleOnStack.Create(ref self), pos, out value);
}

[Intrinsic]
private void SetGenericValueImpl<T>(int pos, ref T value)
{
Array self = this;
SetGenericValue_icall(ref self, pos, ref value);
SetGenericValue_icall(ObjectHandleOnStack.Create(ref self), pos, ref value);
}

// CAUTION! No bounds checking!
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void SetValueImpl(object? value, int pos);
private static extern void SetValueImpl(ObjectHandleOnStack arr, ObjectHandleOnStack value, int pos);

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void InitializeInternal(ObjectHandleOnStack arr);

// CAUTION! No bounds checking!
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void SetValueRelaxedImpl(object? value, int pos);
private static extern void SetValueRelaxedImpl(ObjectHandleOnStack arr, ObjectHandleOnStack value, int pos);

#pragma warning disable CA1822
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public override ParameterInfo[] GetParameters()

// Have to clone because GetParametersInfo icall returns cached value
var dest = new ParameterInfo[src.Length];
Array.FastCopy(src, 0, dest, 0, src.Length);
Array.FastCopy(ObjectHandleOnStack.Create (ref src), 0, ObjectHandleOnStack.Create (ref dest), 0, src.Length);
return dest;
}

Expand Down
13 changes: 10 additions & 3 deletions src/mono/mono/metadata/icall-decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@ ICALL_EXPORT int ves_icall_System_GC_GetCollectionCount (int);
ICALL_EXPORT int ves_icall_System_GC_GetMaxGeneration (void);
ICALL_EXPORT gint64 ves_icall_System_GC_GetAllocatedBytesForCurrentThread (void);
ICALL_EXPORT int ves_icall_get_method_attributes (MonoMethod* method);
ICALL_EXPORT void ves_icall_System_Array_GetGenericValue_icall (MonoArray**, guint32, gpointer);
ICALL_EXPORT void ves_icall_System_Array_SetGenericValue_icall (MonoArray**, guint32, gpointer);
ICALL_EXPORT void ves_icall_System_Array_GetGenericValue_icall (MonoObjectHandleOnStack arr_handle, guint32 pos, gpointer value);
ICALL_EXPORT void ves_icall_System_Array_SetGenericValue_icall (MonoObjectHandleOnStack *arr_handle, guint32 pos, gpointer value);

ICALL_EXPORT void ves_icall_System_Environment_Exit (int);
ICALL_EXPORT void ves_icall_System_GC_InternalCollect (int generation);
ICALL_EXPORT void ves_icall_System_GC_RecordPressure (gint64);
Expand All @@ -139,7 +140,7 @@ ICALL_EXPORT void ves_icall_System_Buffer_BulkMoveWithWriteBarrier (guint8 *, gu
ICALL_EXPORT void ves_icall_System_Runtime_RuntimeImports_ZeroMemory (guint8*, size_t);

ICALL_EXPORT void ves_icall_System_Array_InternalCreate (MonoArray *volatile* result, MonoType* type, gint32 rank, gint32* pLengths, gint32* pLowerBounds);
ICALL_EXPORT MonoBoolean ves_icall_System_Array_CanChangePrimitive (MonoReflectionType *volatile* ref_src_type_handle, MonoReflectionType *volatile* ref_dst_type_handle, MonoBoolean reliable);
ICALL_EXPORT MonoBoolean ves_icall_System_Array_CanChangePrimitive (MonoObjectHandleOnStack ref_src_type_handle, MonoObjectHandleOnStack ref_dst_type_handle, MonoBoolean reliable);

ICALL_EXPORT MonoBoolean ves_icall_System_Diagnostics_Debugger_IsAttached_internal (void);
ICALL_EXPORT MonoBoolean ves_icall_System_Diagnostics_Debugger_IsLogging (void);
Expand Down Expand Up @@ -201,4 +202,10 @@ ICALL_EXPORT gint32 ves_icall_RuntimeType_GetGenericParameterPosition (MonoQCall

ICALL_EXPORT int ves_icall_System_Enum_InternalGetCorElementType (MonoQCallTypeHandle type_handle);

ICALL_EXPORT gint32 ves_icall_System_Array_GetCorElementTypeOfElementTypeInternal (MonoObjectHandleOnStack arr_handle);

ICALL_EXPORT MonoBoolean ves_icall_System_Array_IsValueOfElementTypeInternal (MonoObjectHandleOnStack arr_handle, MonoObjectHandleOnStack obj_handle);

ICALL_EXPORT MonoBoolean ves_icall_System_Array_FastCopy (MonoObjectHandleOnStack source_handle, int source_idx, MonoObjectHandleOnStack dest_handle, int dest_idx, int length);

#endif // __MONO_METADATA_ICALL_DECL_H__
16 changes: 8 additions & 8 deletions src/mono/mono/metadata/icall-def.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,18 +128,18 @@ NOHANDLES(ICALL(ARGI_4, "Setup", ves_icall_System_ArgIterator_Se

ICALL_TYPE(ARRAY, "System.Array", ARRAY_0)
NOHANDLES(ICALL(ARRAY_0, "CanChangePrimitive", ves_icall_System_Array_CanChangePrimitive))
HANDLES(ARRAY_4, "FastCopy", ves_icall_System_Array_FastCopy, MonoBoolean, 5, (MonoArray, int, MonoArray, int, int))
HANDLES(ARRAY_4a, "GetCorElementTypeOfElementType", ves_icall_System_Array_GetCorElementTypeOfElementType, gint32, 1, (MonoArray))
NOHANDLES(ICALL(ARRAY_4, "FastCopy", ves_icall_System_Array_FastCopy))
NOHANDLES(ICALL(ARRAY_4a, "GetCorElementTypeOfElementTypeInternal", ves_icall_System_Array_GetCorElementTypeOfElementTypeInternal))
NOHANDLES(ICALL(ARRAY_5, "GetGenericValue_icall", ves_icall_System_Array_GetGenericValue_icall))
HANDLES(ARRAY_6, "GetLength", ves_icall_System_Array_GetLength, gint32, 2, (MonoArray, gint32))
HANDLES(ARRAY_7, "GetLowerBound", ves_icall_System_Array_GetLowerBound, gint32, 2, (MonoArray, gint32))
HANDLES(ARRAY_10, "GetValueImpl", ves_icall_System_Array_GetValueImpl, MonoObject, 2, (MonoArray, guint32))
HANDLES(ARRAY_6, "GetLengthInternal", ves_icall_System_Array_GetLengthInternal, gint32, 2, (MonoObjectHandleOnStack, gint32))
HANDLES(ARRAY_7, "GetLowerBoundInternal", ves_icall_System_Array_GetLowerBoundInternal, gint32, 2, (MonoObjectHandleOnStack, gint32))
HANDLES(ARRAY_10, "GetValueImpl", ves_icall_System_Array_GetValueImpl, void, 3, (MonoObjectHandleOnStack, MonoObjectHandleOnStack, guint32))
HANDLES(ARRAY_10_a, "InitializeInternal", ves_icall_System_Array_InitializeInternal, void, 1, (MonoObjectHandleOnStack))
NOHANDLES(ICALL(ARRAY_10a, "InternalCreate", ves_icall_System_Array_InternalCreate))
HANDLES(ARRAY_10b, "IsValueOfElementType", ves_icall_System_Array_IsValueOfElementType, gint32, 2, (MonoArray, MonoObject))
NOHANDLES(ICALL(ARRAY_10b, "IsValueOfElementTypeInternal", ves_icall_System_Array_IsValueOfElementTypeInternal))
NOHANDLES(ICALL(ARRAY_11, "SetGenericValue_icall", ves_icall_System_Array_SetGenericValue_icall))
HANDLES(ARRAY_13, "SetValueImpl", ves_icall_System_Array_SetValueImpl, void, 3, (MonoArray, MonoObject, guint32))
HANDLES(ARRAY_14, "SetValueRelaxedImpl", ves_icall_System_Array_SetValueRelaxedImpl, void, 3, (MonoArray, MonoObject, guint32))
HANDLES(ARRAY_13, "SetValueImpl", ves_icall_System_Array_SetValueImpl, void, 3, (MonoObjectHandleOnStack, MonoObjectHandleOnStack, guint32))
HANDLES(ARRAY_14, "SetValueRelaxedImpl", ves_icall_System_Array_SetValueRelaxedImpl, void, 3, (MonoObjectHandleOnStack, MonoObjectHandleOnStack, guint32))

ICALL_TYPE(BUFFER, "System.Buffer", BUFFER_0)
NOHANDLES(ICALL(BUFFER_0, "BulkMoveWithWriteBarrier", ves_icall_System_Buffer_BulkMoveWithWriteBarrier))
Expand Down
Loading

0 comments on commit a94fa06

Please sign in to comment.