Skip to content

Commit

Permalink
Add IntPtr conversion APIs for some runtime handles (dotnet#69363)
Browse files Browse the repository at this point in the history
* Add conversion APIs for runtime handles
  • Loading branch information
AaronRobinsonMSFT authored May 16, 2022
1 parent 3dcd52e commit fc0b204
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 4 deletions.
64 changes: 63 additions & 1 deletion src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ internal static Type GetTypeHelper(Type typeStart, Type[]? genericArgs, IntPtr p
return type;
}

/// <summary>
/// Returns a new <see cref="RuntimeTypeHandle"/> object created from a handle to a RuntimeType.
/// </summary>
/// <param name="value">An IntPtr handle to a RuntimeType to create a <see cref="RuntimeTypeHandle"/> object from.</param>
/// <returns>A new <see cref="RuntimeTypeHandle"/> object that corresponds to the value parameter.</returns>
public static RuntimeTypeHandle FromIntPtr(IntPtr value) => new RuntimeTypeHandle(Type.GetTypeFromHandleUnsafe(value));

/// <summary>
/// Returns the internal pointer representation of a <see cref="RuntimeTypeHandle"/> object.
/// </summary>
/// <param name="value">A <see cref="RuntimeTypeHandle"/> object to retrieve an internal pointer representation from.</param>
/// <returns>An <see cref="IntPtr"/> object that represents a <see cref="RuntimeTypeHandle"/> object.</returns>
public static IntPtr ToIntPtr(RuntimeTypeHandle value) => value.Value;

public static bool operator ==(RuntimeTypeHandle left, object? right) => left.Equals(right);

public static bool operator ==(object? left, RuntimeTypeHandle right) => right.Equals(left);
Expand Down Expand Up @@ -864,6 +878,25 @@ public override bool Equals(object? obj)
return handle.Value == Value;
}

/// <summary>
/// Returns a new <see cref="RuntimeMethodHandle"/> object created from a handle to a RuntimeMethodInfo.
/// </summary>
/// <param name="value">An IntPtr handle to a RuntimeMethodInfo to create a <see cref="RuntimeMethodHandle"/> object from.</param>
/// <returns>A new <see cref="RuntimeMethodHandle"/> object that corresponds to the value parameter.</returns>
public static RuntimeMethodHandle FromIntPtr(IntPtr value)
{
var handle = new RuntimeMethodHandleInternal(value);
var methodInfo = new RuntimeMethodInfoStub(handle, RuntimeMethodHandle.GetLoaderAllocator(handle));
return new RuntimeMethodHandle(methodInfo);
}

/// <summary>
/// Returns the internal pointer representation of a <see cref="RuntimeMethodHandle"/> object.
/// </summary>
/// <param name="value">A <see cref="RuntimeMethodHandle"/> object to retrieve an internal pointer representation from.</param>
/// <returns>An <see cref="IntPtr"/> object that represents a <see cref="RuntimeMethodHandle"/> object.</returns>
public static IntPtr ToIntPtr(RuntimeMethodHandle value) => value.Value;

public static bool operator ==(RuntimeMethodHandle left, RuntimeMethodHandle right) => left.Equals(right);

public static bool operator !=(RuntimeMethodHandle left, RuntimeMethodHandle right) => !left.Equals(right);
Expand Down Expand Up @@ -1124,9 +1157,16 @@ RuntimeFieldHandleInternal Value
[StructLayout(LayoutKind.Sequential)]
internal sealed class RuntimeFieldInfoStub : IRuntimeFieldInfo
{
public RuntimeFieldInfoStub(RuntimeFieldHandleInternal fieldHandle, object keepalive)
{
m_keepalive = keepalive;
m_fieldHandle = fieldHandle;
}

private readonly object m_keepalive;

// These unused variables are used to ensure that this class has the same layout as RuntimeFieldInfo
#pragma warning disable 414, 169
private object? m_keepalive;
private object? m_c;
private object? m_d;
private int m_b;
Expand Down Expand Up @@ -1190,6 +1230,25 @@ public bool Equals(RuntimeFieldHandle handle)
return handle.Value == Value;
}

/// <summary>
/// Returns a new <see cref="RuntimeFieldHandle"/> object created from a handle to a RuntimeFieldInfo.
/// </summary>
/// <param name="value">An IntPtr handle to a RuntimeFieldInfo to create a <see cref="RuntimeFieldHandle"/> object from.</param>
/// <returns>A new <see cref="RuntimeFieldHandle"/> object that corresponds to the value parameter.</returns>
public static RuntimeFieldHandle FromIntPtr(IntPtr value)
{
var handle = new RuntimeFieldHandleInternal(value);
var fieldInfo = new RuntimeFieldInfoStub(handle, RuntimeFieldHandle.GetLoaderAllocator(handle));
return new RuntimeFieldHandle(fieldInfo);
}

/// <summary>
/// Returns the internal pointer representation of a <see cref="RuntimeFieldHandle"/> object.
/// </summary>
/// <param name="value">A <see cref="RuntimeFieldHandle"/> object to retrieve an internal pointer representation from.</param>
/// <returns>An <see cref="IntPtr"/> object that represents a <see cref="RuntimeFieldHandle"/> object.</returns>
public static IntPtr ToIntPtr(RuntimeFieldHandle value) => value.Value;

public static bool operator ==(RuntimeFieldHandle left, RuntimeFieldHandle right) => left.Equals(right);

public static bool operator !=(RuntimeFieldHandle left, RuntimeFieldHandle right) => !left.Equals(right);
Expand Down Expand Up @@ -1239,6 +1298,9 @@ internal static RuntimeType GetApproxDeclaringType(IRuntimeFieldInfo field)
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool AcquiresContextFromThis(RuntimeFieldHandleInternal field);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern LoaderAllocator GetLoaderAllocator(RuntimeFieldHandleInternal method);

// ISerializable interface
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ public struct RuntimeFieldHandle : IEquatable<RuntimeFieldHandle>, ISerializable
{
private IntPtr _value;

private RuntimeFieldHandle(IntPtr value)
{
_value = value;
}

public IntPtr Value => _value;

public override bool Equals(object? obj)
Expand Down Expand Up @@ -61,6 +66,10 @@ public override int GetHashCode()
return (hashcode + _rotl(hashcode, 13)) ^ fieldName.GetHashCode();
}

public static RuntimeFieldHandle FromIntPtr(IntPtr value) => new RuntimeFieldHandle(value);

public static IntPtr ToIntPtr(RuntimeFieldHandle value) => value.Value;

public static bool operator ==(RuntimeFieldHandle left, RuntimeFieldHandle right)
{
return left.Equals(right);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ public struct RuntimeMethodHandle : IEquatable<RuntimeMethodHandle>, ISerializab
{
private IntPtr _value;

public unsafe IntPtr Value => _value;
private RuntimeMethodHandle(IntPtr value)
{
_value = value;
}

public IntPtr Value => _value;

public override bool Equals(object? obj)
{
Expand Down Expand Up @@ -92,6 +97,10 @@ public override int GetHashCode()
return hashcode;
}

public static RuntimeMethodHandle FromIntPtr(IntPtr value) => new RuntimeMethodHandle(value);

public static IntPtr ToIntPtr(RuntimeMethodHandle value) => value.Value;

public static bool operator ==(RuntimeMethodHandle left, RuntimeMethodHandle right)
{
return left.Equals(right);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ public unsafe struct RuntimeTypeHandle : IEquatable<RuntimeTypeHandle>, ISeriali
//

internal RuntimeTypeHandle(EETypePtr pEEType)
: this(pEEType.RawValue)
{
_value = pEEType.RawValue;
}

private RuntimeTypeHandle(IntPtr value)
{
_value = value;
}

public override bool Equals(object? obj)
Expand Down Expand Up @@ -60,6 +65,10 @@ public bool Equals(RuntimeTypeHandle handle)
}
}

public static RuntimeTypeHandle FromIntPtr(IntPtr value) => new RuntimeTypeHandle(value);

public static IntPtr ToIntPtr(RuntimeTypeHandle value) => value.Value;

public static bool operator ==(object? left, RuntimeTypeHandle right)
{
if (left is RuntimeTypeHandle)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ FCFuncStart(gCOMFieldHandleNewFuncs)
FCFuncElement("GetToken", RuntimeFieldHandle::GetToken)
FCFuncElement("GetStaticFieldForGenericType", RuntimeFieldHandle::GetStaticFieldForGenericType)
FCFuncElement("AcquiresContextFromThis", RuntimeFieldHandle::AcquiresContextFromThis)
FCFuncElement("GetLoaderAllocator", RuntimeFieldHandle::GetLoaderAllocator)
FCFuncEnd()

FCFuncStart(gCOMModuleFuncs)
Expand Down
25 changes: 24 additions & 1 deletion src/coreclr/vm/runtimehandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ FCIMPL1(AssemblyBaseObject*, RuntimeTypeHandle::GetAssembly, ReflectClassBaseObj
FCIMPLEND


FCIMPL1(FC_BOOL_RET, RuntimeFieldHandle::AcquiresContextFromThis, FieldDesc *pField)
FCIMPL1(FC_BOOL_RET, RuntimeFieldHandle::AcquiresContextFromThis, FieldDesc* pField)
{
CONTRACTL {
FCALL_CHECK;
Expand All @@ -375,6 +375,29 @@ FCIMPL1(FC_BOOL_RET, RuntimeFieldHandle::AcquiresContextFromThis, FieldDesc *pFi
}
FCIMPLEND

FCIMPL1(Object*, RuntimeFieldHandle::GetLoaderAllocator, FieldDesc* pField)
{
CONTRACTL {
FCALL_CHECK;
}
CONTRACTL_END;

OBJECTREF loaderAllocator = NULL;

if (!pField)
FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(loaderAllocator);

LoaderAllocator *pLoaderAllocator = pField->GetApproxEnclosingMethodTable()->GetLoaderAllocator();
loaderAllocator = pLoaderAllocator->GetExposedObject();

HELPER_METHOD_FRAME_END();

return OBJECTREFToObject(loaderAllocator);
}
FCIMPLEND

FCIMPL1(ReflectModuleBaseObject*, RuntimeTypeHandle::GetModule, ReflectClassBaseObject *pTypeUNSAFE) {
CONTRACTL {
FCALL_CHECK;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/runtimehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ class RuntimeFieldHandle {
static FCDECL1(INT32, GetToken, ReflectFieldObject *pFieldUNSAFE);
static FCDECL2(FieldDesc*, GetStaticFieldForGenericType, FieldDesc *pField, ReflectClassBaseObject *pDeclaringType);
static FCDECL1(FC_BOOL_RET, AcquiresContextFromThis, FieldDesc *pField);
static FCDECL1(Object*, GetLoaderAllocator, FieldDesc *pField);
};

class ModuleHandle {
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4087,6 +4087,8 @@ public partial struct RuntimeFieldHandle : System.IEquatable<System.RuntimeField
public bool Equals(System.RuntimeFieldHandle handle) { throw null; }
public override int GetHashCode() { throw null; }
public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public static System.RuntimeFieldHandle FromIntPtr(System.IntPtr value) { throw null; }
public static System.IntPtr ToIntPtr(System.RuntimeFieldHandle value) { throw null; }
public static bool operator ==(System.RuntimeFieldHandle left, System.RuntimeFieldHandle right) { throw null; }
public static bool operator !=(System.RuntimeFieldHandle left, System.RuntimeFieldHandle right) { throw null; }
}
Expand All @@ -4100,6 +4102,8 @@ public partial struct RuntimeMethodHandle : System.IEquatable<System.RuntimeMeth
public System.IntPtr GetFunctionPointer() { throw null; }
public override int GetHashCode() { throw null; }
public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public static System.RuntimeMethodHandle FromIntPtr(System.IntPtr value) { throw null; }
public static System.IntPtr ToIntPtr(System.RuntimeMethodHandle value) { throw null; }
public static bool operator ==(System.RuntimeMethodHandle left, System.RuntimeMethodHandle right) { throw null; }
public static bool operator !=(System.RuntimeMethodHandle left, System.RuntimeMethodHandle right) { throw null; }
}
Expand All @@ -4113,6 +4117,8 @@ public partial struct RuntimeTypeHandle : System.IEquatable<System.RuntimeTypeHa
public override int GetHashCode() { throw null; }
public System.ModuleHandle GetModuleHandle() { throw null; }
public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public static System.RuntimeTypeHandle FromIntPtr(System.IntPtr value) { throw null; }
public static System.IntPtr ToIntPtr(System.RuntimeTypeHandle value) { throw null; }
public static bool operator ==(object? left, System.RuntimeTypeHandle right) { throw null; }
public static bool operator ==(System.RuntimeTypeHandle left, object? right) { throw null; }
public static bool operator !=(object? left, System.RuntimeTypeHandle right) { throw null; }
Expand Down
18 changes: 18 additions & 0 deletions src/libraries/System.Runtime/tests/System/HandleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public static void RuntimeFieldHandleTest()

Assert.False(h == default(RuntimeFieldHandle));
Assert.True(h != default(RuntimeFieldHandle));

IntPtr hPtr = RuntimeFieldHandle.ToIntPtr(h);
RuntimeFieldHandle hNew = RuntimeFieldHandle.FromIntPtr(hPtr);
Assert.True(h.Equals(hNew));
Assert.True(hNew.Equals(h));
}

[Fact]
Expand All @@ -59,6 +64,14 @@ public static void RuntimeMethodHandleTest()

Assert.False(h == default(RuntimeMethodHandle));
Assert.True(h != default(RuntimeMethodHandle));

IntPtr hPtr = RuntimeMethodHandle.ToIntPtr(h);
RuntimeMethodHandle hNew = RuntimeMethodHandle.FromIntPtr(hPtr);
Assert.True(h.Equals(hNew));
Assert.True(hNew.Equals(h));

// Confirm the created handle is valid
Assert.Equal(mi, MethodBase.GetMethodFromHandle(hNew));
}

[Fact]
Expand Down Expand Up @@ -96,6 +109,11 @@ public static void RuntimeTypeHandleTest()
Assert.False(null == h);
Assert.True(h != null);
Assert.True(null != h);

IntPtr hPtr = RuntimeTypeHandle.ToIntPtr(h);
RuntimeTypeHandle hNew = RuntimeTypeHandle.FromIntPtr(hPtr);
Assert.True(h.Equals(hNew));
Assert.True(hNew.Equals(h));
}

private class Base
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public override int GetHashCode()
return value.GetHashCode();
}

public static RuntimeFieldHandle FromIntPtr(IntPtr value) => new RuntimeFieldHandle(value);

public static IntPtr ToIntPtr(RuntimeFieldHandle value) => value.Value;

public static bool operator ==(RuntimeFieldHandle left, RuntimeFieldHandle right)
{
return left.Equals(right);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public override int GetHashCode()
return value.GetHashCode();
}

public static RuntimeMethodHandle FromIntPtr(IntPtr value) => new RuntimeMethodHandle(value);

public static IntPtr ToIntPtr(RuntimeMethodHandle value) => value.Value;

public static bool operator ==(RuntimeMethodHandle left, RuntimeMethodHandle right)
{
return left.Equals(right);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ public override int GetHashCode()
return value.GetHashCode();
}

public static RuntimeTypeHandle FromIntPtr(IntPtr value) => new RuntimeTypeHandle(value);

public static IntPtr ToIntPtr(RuntimeTypeHandle value) => value.Value;

public static bool operator ==(RuntimeTypeHandle left, object right)
{
return (right != null) && (right is RuntimeTypeHandle) && left.Equals((RuntimeTypeHandle)right);
Expand Down

0 comments on commit fc0b204

Please sign in to comment.