Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Prev Previous commit
Next Next commit
PR feedback
  • Loading branch information
jkoritzinsky committed Apr 3, 2024
commit b285704f83cd852ca9b7df1a42a9c79042c35745
Original file line number Diff line number Diff line change
Expand Up @@ -422,18 +422,19 @@ private static unsafe void DispatchTailCalls(
if (type.IsNullHandle())
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.type);

RuntimeType rtType = (RuntimeType)Type.GetTypeFromHandle(type)!;
TypeHandle handle = type.GetNativeTypeHandle();

if (rtType.IsByRefLike)
throw new NotSupportedException(SR.NotSupported_ByRefLike);
if (handle.IsTypeDesc)
throw new ArgumentException(SR.Arg_TypeNotSupported);

if (rtType.IsPointer || rtType.IsFunctionPointer)
throw new NotSupportedException(SR.NotSupported_BoxedPointer);
MethodTable* pMT = handle.AsMethodTable();

if (rtType.IsActualValueType)
if (pMT->IsValueType)
{
object? result = Box(rtType.GetNativeTypeHandle().AsMethodTable(), ref target);
GC.KeepAlive(rtType);
if (pMT->IsByRefLike)
throw new NotSupportedException(SR.NotSupported_ByRefLike);
object? result = Box(pMT, ref target);
GC.KeepAlive(type);
return result;
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ internal bool IsNullHandle()
return m_type == null;
}

internal TypeHandle GetNativeTypeHandle()
{
return m_type.GetNativeTypeHandle();
}

internal static bool IsTypeDefinition(RuntimeType type)
{
CorElementType corElemType = GetCorElementType(type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ public static unsafe object RhNewArray(MethodTable* pEEType, int length)
[RuntimeExport("RhBox")]
public static unsafe object RhBox(MethodTable* pEEType, ref byte data)
{
// Compatibility with CoreCLR, throw on a null reference to the unboxed data.
if (Unsafe.IsNullRef(ref target))
throw new NullReferenceException();

ref byte dataAdjustedForNullable = ref data;

// Can box non-ByRefLike value types only (which also implies no finalizers).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,24 +362,25 @@ public static unsafe object GetUninitializedObject(
return RuntimeImports.RhNewObject(mt);
}

public static unsafe object Box(ref byte target, RuntimeTypeHandle type)
public static unsafe object? Box(ref byte target, RuntimeTypeHandle type)
{
if (type.IsNull)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.type);

// Compatibility with CoreCLR, throw on a null reference to the unboxed data.
if (Unsafe.IsNullRef(ref target))
throw new NullReferenceException();

MethodTable* eeType = type.ToMethodTable();

if (eeType->IsByRef || eeType->IsPointer || eeType->IsFunctionPointer)
throw new ArgumentException(SR.Arg_TypeNotSupported);

if (!eeType->IsValueType)
{
return Unsafe.As<byte, object>>(ref target);
}

if (eeType->IsByRefLike)
throw new NotSupportedException(SR.NotSupported_ByRefLike);

if (eeType->IsPointer || eeType->IsFunctionPointer)
throw new NotSupportedException(SR.NotSupported_BoxedPointer);

return RuntimeImports.RhBoxAny(ref target, eeType);
return RuntimeImports.RhBox(ref target, eeType);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ public static unsafe object ToObject(TypedReference value)
{
RuntimeTypeHandle handle = RawTargetTypeToken(value);

if (handle.IsNull)
ThrowHelper.ThrowArgumentException_ArgumentNull_TypedRefType();

MethodTable* mt = handle.ToMethodTable();
if (mt->IsPointer || mt->IsFunctionPointer)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2954,9 +2954,6 @@
<data name="NotSupported_AssemblyLoadFromHash" xml:space="preserve">
<value>Assembly.LoadFrom with hashValue is not supported.</value>
</data>
<data name="NotSupported_BoxedPointer" xml:space="preserve">
<value>Cannot create boxed pointer values.</value>
</data>
<data name="NotSupported_ByRefLike" xml:space="preserve">
<value>Cannot create boxed ByRef-like values.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ public static void BoxPrimitive()
[Fact]
public static void BoxPointer()
{
Assert.Throws<NotSupportedException>(() =>
Assert.Throws<ArgumentException>(() =>
{
nint value = 3;
object result = RuntimeHelpers.Box(ref Unsafe.As<nint, byte>(ref value), typeof(void*).TypeHandle);
Expand Down Expand Up @@ -519,14 +519,22 @@ public static void BoxNullable()
Assert.Equal(value, Assert.IsType<float>(result));
}

[Fact]
public static void BoxNullNullable()
{
float? value = null;
object? result = RuntimeHelpers.Box(ref Unsafe.As<float?, byte>(ref value), typeof(float?).TypeHandle);
Assert.Null(result);
}

[Fact]
public static void NullBox()
{
Assert.Throws<NullReferenceException>(() => RuntimeHelpers.Box(ref Unsafe.NullRef<byte>(), typeof(byte).TypeHandle));
}

[Fact]
public static void BoxInvalidType()
public static void BoxNullTypeHandle()
{
Assert.Throws<ArgumentNullException>(() =>
{
Expand All @@ -541,6 +549,24 @@ public static void BoxReferenceType()
string str = "ABC";
Assert.Same(str, RuntimeHelpers.Box(ref Unsafe.As<string, byte>(ref str), typeof(string).TypeHandle));
}

[Fact]
public static void BoxArrayType()
{
string[] arr = ["a", "b", "c"];
Assert.Same(arr, RuntimeHelpers.Box(ref Unsafe.As<string[], byte>(ref arr), typeof(string[]).TypeHandle));
}

[Fact]
public static void BoxGenericParameterType()
{
Type t = typeof(List<>).GetGenericArguments()[0];
Assert.Throws<ArgumentException>(() =>
{
byte value = 3;
RuntimeHelpers.Box(ref value, t.TypeHandle);
});
}
}

public struct Age
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,23 +226,20 @@ private static extern unsafe IntPtr GetSpanDataFrom(

RuntimeType rtType = (RuntimeType)Type.GetTypeFromHandle(type)!;

if (rtType.IsByRefLike)
throw new NotSupportedException(SR.NotSupported_ByRefLike);

if (rtType.IsPointer || rtType.IsFunctionPointer)
throw new NotSupportedException(SR.NotSupported_BoxedPointer);
if (rtType.IsPointer || rtType.IsFunctionPointer || rtType.IsByRef || rtType.IsGenericParameter)
throw new ArgumentException(SR.Arg_TypeNotSupported);


if (rtType.IsValueType)
{
object? result = null;
InternalBox(new QCallTypeHandle(ref rtType), ref target, ObjectHandleOnStack.Create(ref result));
return result;
}
else
if (!rtType.IsValueType)
{
return Unsafe.As<byte, object?>(ref target);
}

if (rtType.IsByRefLike)
throw new NotSupportedException(SR.NotSupported_ByRefLike);

object? result = null;
InternalBox(new QCallTypeHandle(ref rtType), ref target, ObjectHandleOnStack.Create(ref result));
return result;
}
}
}