Skip to content

Commit

Permalink
Delete most of InteropExtensions (dotnet#97685)
Browse files Browse the repository at this point in the history
These existed due to some 5+ year old layering issue.

I left `IsBlittable`. Pretty much every single use of this is a bug (dotnet#75666).
  • Loading branch information
MichalStrehovsky authored Jan 30, 2024
1 parent 3a71efa commit 7c95e52
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,26 @@ public static uint GetStructFieldOffset(RuntimeTypeHandle structureTypeHandle, s
throw new NotSupportedException(SR.Format(SR.StructMarshalling_MissingInteropData, structureType));
}

public static int GetStructUnsafeStructSize(RuntimeTypeHandle structureTypeHandle)
public static unsafe int GetStructUnsafeStructSize(RuntimeTypeHandle structureTypeHandle)
{
if (TryGetStructUnsafeStructSize(structureTypeHandle, out int size))
{
return size;
}

MethodTable* structureMT = structureTypeHandle.ToMethodTable();

// IsBlittable() checks whether the type contains GC references. It is approximate check with false positives.
// This fallback path will return incorrect answer for types that do not contain GC references, but that are
// not actually blittable; e.g. for types with bool fields.
if (structureTypeHandle.IsBlittable() && structureTypeHandle.IsValueType())
if (structureTypeHandle.IsBlittable() && structureMT->IsValueType)
{
return structureTypeHandle.GetValueTypeSize();
return (int)structureMT->ValueTypeSize;
}

// If the type is an interface or a generic type, the reason is likely that.
Type structureType = Type.GetTypeFromHandle(structureTypeHandle)!;
if (structureTypeHandle.IsInterface() || structureTypeHandle.IsGenericType())
if (structureMT->IsInterface || structureMT->IsGeneric)
{
throw new ArgumentException(SR.Format(SR.Arg_CannotMarshal, structureType));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,89 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;

using Internal.Runtime.Augments;
using Internal.Runtime.CompilerServices;

namespace System.Runtime.InteropServices
{
/// <summary>
/// Hooks for interop code to access internal functionality in System.Private.CoreLib.dll.
/// </summary>
internal static unsafe class InteropExtensions
{
internal static bool MightBeBlittable(this RuntimeTypeHandle handle)
public static bool IsBlittable(this RuntimeTypeHandle handle)
{
//
// This is used as the approximate implementation of MethodTable::IsBlittable(). It will err in the direction of declaring
// things blittable since it is used for argument validation only.
//
return !handle.ToMethodTable()->ContainsGCPointers;
}

public static bool IsBlittable(this RuntimeTypeHandle handle)
{
return handle.MightBeBlittable();
}

public static bool IsGenericType(this RuntimeTypeHandle handle)
{
return handle.ToMethodTable()->IsGeneric;
}

public static bool IsGenericTypeDefinition(this RuntimeTypeHandle handle)
{
return handle.ToMethodTable()->IsGenericTypeDefinition;
}

//
// Returns the raw function pointer for a open static delegate - if the function has a jump stub
// it returns the jump target. Therefore the function pointer returned
// by two delegates may NOT be unique
//
public static IntPtr GetRawFunctionPointerForOpenStaticDelegate(this Delegate del)
{
//If it is not open static then return IntPtr.Zero
if (!del.IsOpenStatic)
return IntPtr.Zero;

IntPtr funcPtr = del.GetFunctionPointer(out RuntimeTypeHandle _, out bool _, out bool _);
return funcPtr;
}

public static int GetValueTypeSize(this RuntimeTypeHandle handle)
{
return (int)handle.ToMethodTable()->ValueTypeSize;
}

public static bool IsValueType(this RuntimeTypeHandle handle)
{
return handle.ToMethodTable()->IsValueType;
}

public static bool IsEnum(this RuntimeTypeHandle handle)
{
return handle.ToMethodTable()->IsEnum;
}

public static bool IsInterface(this RuntimeTypeHandle handle)
{
return handle.ToMethodTable()->IsInterface;
}

public static bool AreTypesAssignable(RuntimeTypeHandle sourceType, RuntimeTypeHandle targetType)
{
return RuntimeImports.AreTypesAssignable(sourceType.ToMethodTable(), targetType.ToMethodTable());
}

public static RuntimeTypeHandle GetTypeHandle(this object target)
{
return new RuntimeTypeHandle(target.GetMethodTable());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Runtime.CompilerServices;
using System.Text;

using Internal.Runtime;
using Internal.Runtime.Augments;
using Internal.Runtime.CompilerHelpers;

Expand All @@ -29,7 +30,7 @@ internal static int SizeOfHelper(RuntimeType t, bool throwIfNotMarshalable)
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static IntPtr OffsetOf(Type t, string fieldName)
public static unsafe IntPtr OffsetOf(Type t, string fieldName)
{
ArgumentNullException.ThrowIfNull(t);

Expand All @@ -43,7 +44,7 @@ public static IntPtr OffsetOf(Type t, string fieldName)
throw new ArgumentException(SR.Argument_MustBeRuntimeFieldInfo, nameof(fieldName));
}

if (t.TypeHandle.IsGenericTypeDefinition())
if (t.TypeHandle.ToMethodTable()->IsGenericTypeDefinition)
throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));

return new IntPtr(RuntimeInteropData.GetStructFieldOffset(t.TypeHandle, fieldName));
Expand All @@ -61,7 +62,8 @@ private static unsafe void PtrToStructureHelper(IntPtr ptr, object structure, bo

internal static unsafe void PtrToStructureImpl(IntPtr ptr, object structure)
{
RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;
MethodTable* structureMT = structure.GetMethodTable();
RuntimeTypeHandle structureTypeHandle = new RuntimeTypeHandle(structureMT);

IntPtr unmarshalStub;
if (structureTypeHandle.IsBlittable())
Expand All @@ -78,7 +80,7 @@ internal static unsafe void PtrToStructureImpl(IntPtr ptr, object structure)

if (unmarshalStub != IntPtr.Zero)
{
if (structureTypeHandle.IsValueType())
if (structureMT->IsValueType)
{
((delegate*<ref byte, ref byte, void>)unmarshalStub)(ref *(byte*)ptr, ref structure.GetRawData());
}
Expand All @@ -104,12 +106,12 @@ public static unsafe void DestroyStructure(IntPtr ptr, Type structuretype)

RuntimeTypeHandle structureTypeHandle = structuretype.TypeHandle;

if (structureTypeHandle.IsGenericType())
if (structureTypeHandle.ToMethodTable()->IsGeneric)
throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(structuretype));

if (structureTypeHandle.IsEnum() ||
structureTypeHandle.IsInterface() ||
InteropExtensions.AreTypesAssignable(typeof(Delegate).TypeHandle, structureTypeHandle))
if (structureTypeHandle.ToMethodTable()->IsEnum ||
structureTypeHandle.ToMethodTable()->IsInterface ||
RuntimeImports.AreTypesAssignable(MethodTable.Of<Delegate>(), structureTypeHandle.ToMethodTable()))
{
throw new ArgumentException(SR.Format(SR.Argument_MustHaveLayoutOrBeBlittable, structuretype));
}
Expand Down Expand Up @@ -137,9 +139,10 @@ public static unsafe void StructureToPtr(object structure, IntPtr ptr, bool fDel
ArgumentNullException.ThrowIfNull(structure);
ArgumentNullException.ThrowIfNull(ptr);

RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;
MethodTable* structureMT = structure.GetMethodTable();
RuntimeTypeHandle structureTypeHandle = new RuntimeTypeHandle(structureMT);

if (structureTypeHandle.IsGenericType())
if (structureMT->IsGeneric)
{
throw new ArgumentException(SR.Argument_NeedNonGenericObject, nameof(structure));
}
Expand All @@ -164,7 +167,7 @@ public static unsafe void StructureToPtr(object structure, IntPtr ptr, bool fDel

if (marshalStub != IntPtr.Zero)
{
if (structureTypeHandle.IsValueType())
if (structureMT->IsValueType)
{
((delegate*<ref byte, ref byte, void>)marshalStub)(ref structure.GetRawData(), ref *(byte*)ptr);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ public PInvokeDelegateThunk(Delegate del)
thunkData->Handle = GCHandle.Alloc(del, GCHandleType.Weak);

// if it is an open static delegate get the function pointer
thunkData->FunctionPtr = del.GetRawFunctionPointerForOpenStaticDelegate();
if (del.IsOpenStatic)
thunkData->FunctionPtr = del.GetFunctionPointer(out RuntimeTypeHandle _, out bool _, out bool _);
else
thunkData->FunctionPtr = default;
}
}
}
Expand All @@ -163,7 +166,7 @@ public PInvokeDelegateThunk(Delegate del)
}
}

private static PInvokeDelegateThunk AllocateThunk(Delegate del)
private static unsafe PInvokeDelegateThunk AllocateThunk(Delegate del)
{
if (s_thunkPoolHeap == null)
{
Expand All @@ -181,9 +184,9 @@ private static PInvokeDelegateThunk AllocateThunk(Delegate del)
//
// For open static delegates set target to ReverseOpenStaticDelegateStub which calls the static function pointer directly
//
bool openStaticDelegate = del.GetRawFunctionPointerForOpenStaticDelegate() != IntPtr.Zero;
bool openStaticDelegate = del.IsOpenStatic;

IntPtr pTarget = RuntimeInteropData.GetDelegateMarshallingStub(del.GetTypeHandle(), openStaticDelegate);
IntPtr pTarget = RuntimeInteropData.GetDelegateMarshallingStub(new RuntimeTypeHandle(del.GetMethodTable()), openStaticDelegate);
Debug.Assert(pTarget != IntPtr.Zero);

RuntimeAugments.SetThunkData(s_thunkPoolHeap, delegateThunk.Thunk, delegateThunk.ContextData, pTarget);
Expand Down

0 comments on commit 7c95e52

Please sign in to comment.