Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
12c00b0
Implement MakeFunctionPointerSignatureType, MakeModifiedSignatureType…
jgh07 Jan 30, 2026
d100b0f
Override UnderlyingSystemType in SignatureModifiedType
jgh07 Jan 30, 2026
2fb7104
Remove unused using
jgh07 Jan 30, 2026
370bba8
Implement RuntimeType.MakeFunctionPointerType
jgh07 Feb 1, 2026
6334ac3
Clone arrays; Remove unbounded stackalloc
jgh07 Feb 2, 2026
db884d6
Add more checks, defensive clones
jgh07 Feb 2, 2026
646c698
Implement DynamicILGenerator.EmitCalli; Fix issues with MakeFunctionP…
jgh07 Feb 2, 2026
34a4aa8
Clone before null checks
jgh07 Feb 2, 2026
911ab4c
Code style adjustments
jgh07 Feb 2, 2026
6a79794
Add test cases for MakeFunctionPointerType
jgh07 Feb 2, 2026
10480d6
Implement ContainsGenericParameters property
jgh07 Feb 2, 2026
36efdd7
Merge branch 'main' into issue-75348
jkotas Feb 2, 2026
235a1eb
Make return type non-nullable in MakeFunctionPointerSignatureType
jgh07 Feb 3, 2026
3e69ba5
Merge branch 'issue-75348' of https://github.com/jgh07/runtime into i…
jgh07 Feb 3, 2026
992f8ef
Correctly handle modopt-encoded calling conventions on DynamicMethod
jgh07 Feb 3, 2026
5208c79
Encode custom modifiers on return type correctly for DynamicMethod
jgh07 Feb 6, 2026
3cda7fb
Address review comments
jgh07 Feb 6, 2026
ad985be
Throw if calling conventions are supplied for managed function pointers
jgh07 Feb 6, 2026
03a405f
Compute stack change based on unmodified return type
jgh07 Feb 6, 2026
f559fc9
Add more tests, fix some issues
jgh07 Feb 8, 2026
541b4e1
Disable tests for MakeFunctionPointerType on Mono
jgh07 Feb 8, 2026
e1de07c
Disable DynamicMethod EmitCalli tests on Mono
jgh07 Feb 8, 2026
58e0b44
Refer to new issue for Mono implementation; Implement suggestion in M…
jgh07 Feb 8, 2026
9f1e007
Redirect Emit(OpCodes.Calli, Type) to EmitCalli(Type) for function po…
jgh07 Feb 8, 2026
ff157db
Remove redundant clone
jgh07 Feb 8, 2026
ffbc5af
Remove special cases in Emit(OpCode, Type)
jgh07 Feb 9, 2026
9a86dc8
Support ldtoken for function pointer (signature) types in ILGenerator…
jgh07 Feb 9, 2026
af07d0c
Disable failing test on Mono
jgh07 Feb 11, 2026
3ebe1d3
Add explicit parentheses to make precedence clearer
jgh07 Feb 11, 2026
a41d0f0
Implement SignatureModifiedType.ElementType
jgh07 Feb 11, 2026
5bfe315
Override remaining methods on signature types; Documentation improvem…
jgh07 Feb 11, 2026
d57d7c3
Implement MakeFunctionPointerType for NativeAOT
jgh07 Feb 11, 2026
d325940
Remove AddFunctionPointer helper
jgh07 Feb 12, 2026
4afdc6c
More improvements and cleanup
jgh07 Feb 15, 2026
7f28b72
Merge branch 'main' into issue-75348
jgh07 Feb 15, 2026
5f1bbf0
Remove unused parameter
jgh07 Feb 15, 2026
03501f2
Remove items that were accidentally added in merge
jgh07 Feb 15, 2026
d1afecf
Handle non-RuntimeTypes in MakeFunctionPointerType
jgh07 Feb 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,18 @@ public override void EmitCalli(OpCode opcode, CallingConvention unmanagedCallCon
PutInteger4(token);
}

/// <inheritdoc/>
public override void EmitCalli(Type functionPointerType)
{
ArgumentNullException.ThrowIfNull(functionPointerType);

if (!functionPointerType.IsFunctionPointer)
throw new ArgumentException(SR.Argument_MustBeFunctionPointer, nameof(functionPointerType));

SignatureHelper sig = SignatureHelper.GetMethodSigHelper(m_scope, functionPointerType);
Emit(OpCodes.Calli, sig);
}

public override void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[]? optionalParameterTypes)
{
ArgumentNullException.ThrowIfNull(methodInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,51 @@ internal static SignatureHelper GetMethodSigHelper(Module? mod, CallingConventio
return new SignatureHelper(mod, intCall, returnType, null, null);
}

internal static SignatureHelper GetMethodSigHelper(DynamicScope scope, Type functionPointerType)
{
Debug.Assert(functionPointerType.IsFunctionPointer);

Type retType = functionPointerType.GetFunctionPointerReturnType();
Type[] retTypeModReqs = retType.GetRequiredCustomModifiers();
Type[] retTypeModOpts = retType.GetOptionalCustomModifiers();
Type[] paramTypes = functionPointerType.GetFunctionPointerParameterTypes();
Type[][] paramModReqs = new Type[paramTypes.Length][];
Type[][] paramModOpts = new Type[paramTypes.Length][];

retType = retType.UnderlyingSystemType;

for (int i = 0; i < paramTypes.Length; i++)
{
paramModReqs[i] = paramTypes[i].GetRequiredCustomModifiers();
paramModOpts[i] = paramTypes[i].GetOptionalCustomModifiers();
paramTypes[i] = paramTypes[i].UnderlyingSystemType;
}

MdSigCallingConvention callConv = MdSigCallingConvention.Default;

if (functionPointerType.IsUnmanagedFunctionPointer)
{
callConv = MdSigCallingConvention.Unmanaged;

if (functionPointerType.GetFunctionPointerCallingConventions() is { Length: 1 } conventions)
{
callConv = conventions[0].FullName switch
{
"System.Runtime.CompilerServices.CallConvCdecl" => MdSigCallingConvention.C,
"System.Runtime.CompilerServices.CallConvStdcall" => MdSigCallingConvention.StdCall,
"System.Runtime.CompilerServices.CallConvThiscall" => MdSigCallingConvention.ThisCall,
"System.Runtime.CompilerServices.CallConvFastcall" => MdSigCallingConvention.FastCall,
_ => MdSigCallingConvention.Unmanaged
};
}
}

SignatureHelper sig = new(null, callConv);
sig.AddDynamicArgument(scope, retType, retTypeModReqs, retTypeModOpts, false);
sig.AddArguments(scope, paramTypes, paramModReqs, paramModOpts);
return sig;
}

public static SignatureHelper GetLocalVarSigHelper()
{
return GetLocalVarSigHelper(null);
Expand Down Expand Up @@ -320,8 +365,8 @@ private void AddOneArgTypeHelper(Type clsArgument, Type[]? requiredCustomModifie
AddOneArgTypeHelper(clsArgument);
}

private void AddOneArgTypeHelper(Type clsArgument) { AddOneArgTypeHelperWorker(clsArgument, false); }
private void AddOneArgTypeHelperWorker(Type clsArgument, bool lastWasGenericInst)
private void AddOneArgTypeHelper(Type clsArgument, DynamicScope? scope = null) { AddOneArgTypeHelperWorker(clsArgument, false, scope); }
private void AddOneArgTypeHelperWorker(Type clsArgument, bool lastWasGenericInst, DynamicScope? scope)
{
if (clsArgument.IsGenericParameter)
{
Expand All @@ -336,7 +381,7 @@ private void AddOneArgTypeHelperWorker(Type clsArgument, bool lastWasGenericInst
{
AddElementType(CorElementType.ELEMENT_TYPE_GENERICINST);

AddOneArgTypeHelperWorker(clsArgument.GetGenericTypeDefinition(), true);
AddOneArgTypeHelperWorker(clsArgument.GetGenericTypeDefinition(), true, scope);

Type[] args = clsArgument.GetGenericArguments();

Expand Down Expand Up @@ -424,6 +469,25 @@ private void AddOneArgTypeHelperWorker(Type clsArgument, bool lastWasGenericInst
AddData(0);
}
}
else if (clsArgument.IsFunctionPointer)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we throw NotSupportedException for scope == null? It is better to throw than produce bad binary silently.

I assume that it can be hit with (non-persistent) Reflection.Emit. Is that right? We may want to add a test that validates it is throwing (and not crashing or producing bad output).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that it can be hit with (non-persistent) Reflection.Emit. Is that right?

Yes, or by just invoking SignatureHelper manually. I added an exception.

if (scope == null)
throw new NotSupportedException(SR.NotSupported_FunctionPointerSignature);

AddData((int)CorElementType.ELEMENT_TYPE_FNPTR);
SignatureHelper sig = GetMethodSigHelper(scope, clsArgument);
byte[] bytes = sig.GetSignature();

if (m_currSig + bytes.Length > m_signature.Length)
{
m_signature = ExpandArray(m_signature, m_signature.Length + bytes.Length);
}

for (int i = 0; i < bytes.Length; i++)
{
m_signature[m_currSig++] = bytes[i];
}
}
else
{
CorElementType type = CorElementType.ELEMENT_TYPE_MAX;
Expand Down Expand Up @@ -729,9 +793,10 @@ internal byte[] InternalGetSignatureArray()
return temp;
}

internal void AddDynamicArgument(DynamicScope dynamicScope, Type clsArgument, Type[]? requiredCustomModifiers, Type[]? optionalCustomModifiers)
internal void AddDynamicArgument(DynamicScope dynamicScope, Type clsArgument, Type[]? requiredCustomModifiers, Type[]? optionalCustomModifiers, bool incrementArgCount = true)
{
IncrementArgCounts();
if (incrementArgCount)
IncrementArgCounts();

Debug.Assert(clsArgument != null);

Expand All @@ -744,12 +809,6 @@ internal void AddDynamicArgument(DynamicScope dynamicScope, Type clsArgument, Ty
if (t is not RuntimeType rtType)
throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(optionalCustomModifiers));

if (t.HasElementType)
throw new ArgumentException(SR.Argument_ArraysInvalid, nameof(optionalCustomModifiers));

if (t.ContainsGenericParameters)
throw new ArgumentException(SR.Argument_GenericsInvalid, nameof(optionalCustomModifiers));

AddElementType(CorElementType.ELEMENT_TYPE_CMOD_OPT);

int token = dynamicScope.GetTokenFor(rtType.TypeHandle);
Expand All @@ -767,12 +826,6 @@ internal void AddDynamicArgument(DynamicScope dynamicScope, Type clsArgument, Ty
if (t is not RuntimeType rtType)
throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(requiredCustomModifiers));

if (t.HasElementType)
throw new ArgumentException(SR.Argument_ArraysInvalid, nameof(requiredCustomModifiers));

if (t.ContainsGenericParameters)
throw new ArgumentException(SR.Argument_GenericsInvalid, nameof(requiredCustomModifiers));

AddElementType(CorElementType.ELEMENT_TYPE_CMOD_REQD);

int token = dynamicScope.GetTokenFor(rtType.TypeHandle);
Expand All @@ -781,7 +834,18 @@ internal void AddDynamicArgument(DynamicScope dynamicScope, Type clsArgument, Ty
}
}

AddOneArgTypeHelper(clsArgument);
AddOneArgTypeHelper(clsArgument, dynamicScope);
}

internal void AddArguments(DynamicScope dynamicScope, Type[]? arguments, Type[][]? requiredCustomModifiers, Type[][]? optionalCustomModifiers)
{
if (arguments is null)
return;

for (int i = 0; i < arguments.Length; i++)
{
AddDynamicArgument(dynamicScope, arguments[i], requiredCustomModifiers?[i], optionalCustomModifiers?[i]);
}
}

#endregion
Expand Down
23 changes: 23 additions & 0 deletions src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,29 @@ internal RuntimeType MakeByRef()
return type!;
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_MakeFunctionPointer")]
private static partial void MakeFunctionPointer(nint* retAndParamTypes, int numArgs, [MarshalAs(UnmanagedType.Bool)] bool isUnmanaged, ObjectHandleOnStack type);

internal RuntimeType MakeFunctionPointer(Type[] parameterTypes, bool isUnmanaged)
{
int count = 1 + parameterTypes.Length;
nint[] retAndParamTypeHandles = new nint[count];

retAndParamTypeHandles[0] = GetNativeHandle().Value;
for (int i = 0; i < parameterTypes.Length; i++)
retAndParamTypeHandles[i + 1] = parameterTypes[i].TypeHandle.Value;

RuntimeType? type = null;
fixed (nint* pRetAndParamTypeHandles = retAndParamTypeHandles)
{
MakeFunctionPointer(pRetAndParamTypeHandles, parameterTypes.Length, isUnmanaged, ObjectHandleOnStack.Create(ref type));
}

GC.KeepAlive(m_type);
GC.KeepAlive(parameterTypes);
return type!;
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_MakePointer")]
private static partial void MakePointer(QCallTypeHandle handle, ObjectHandleOnStack type);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3729,6 +3729,24 @@ public override Type MakeArrayType(int rank)
return new RuntimeTypeHandle(this).MakeArray(rank);
}

public override Type MakeFunctionPointerType(Type[]? parameterTypes, bool isUnmanaged = false)
{
parameterTypes = (parameterTypes != null) ? (Type[])parameterTypes.Clone() : [];
for (int i = 0; i < parameterTypes.Length; i++)
{
Type paramType = parameterTypes[i];
ArgumentNullException.ThrowIfNull(paramType, nameof(parameterTypes));

if (paramType is not RuntimeType)
return Type.MakeFunctionPointerSignatureType(this, parameterTypes, isUnmanaged);

if (paramType == typeof(void) || paramType.IsGenericTypeDefinition)
throw new ArgumentException(string.Format(SR.FunctionPointer_ParameterInvalid, paramType.ToString()), nameof(parameterTypes));
}

return new RuntimeTypeHandle(this).MakeFunctionPointer(parameterTypes, isUnmanaged);
}

public override StructLayoutAttribute? StructLayoutAttribute => PseudoCustomAttribute.GetStructLayoutCustomAttribute(this);

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public static RuntimeTypeInfo GetPointerType(this RuntimeTypeInfo targetType)
return RuntimePointerTypeInfo.GetPointerTypeInfo(targetType);
}

public static RuntimeTypeInfo GetFunctionPointerType(this RuntimeTypeInfo returnType, RuntimeTypeInfo[] parameterTypes, bool isUnmanaged)
{
return RuntimeFunctionPointerTypeInfo.GetFunctionPointerTypeInfo(returnType, parameterTypes, isUnmanaged);
}

public static RuntimeTypeInfo GetConstructedGenericTypeNoConstraintCheck(this RuntimeTypeInfo genericTypeDefinition, RuntimeTypeInfo[] genericTypeArguments)
{
return RuntimeConstructedGenericTypeInfo.GetRuntimeConstructedGenericTypeInfoNoConstraintCheck(genericTypeDefinition, genericTypeArguments);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,28 @@ public Type MakeArrayType(int rank)
return this.GetMultiDimArrayType(rank).ToType();
}

public Type MakeFunctionPointerType(Type[]? parameterTypes, bool isUnmanaged = false)
{
parameterTypes ??= [];
RuntimeTypeInfo[] runtimeParameterTypes = new RuntimeTypeInfo[parameterTypes.Length];

for (int i = 0; i < parameterTypes.Length; i++)
{
Type paramType = parameterTypes[i];
ArgumentNullException.ThrowIfNull(paramType, nameof(parameterTypes));

if (paramType is not RuntimeType rtType)
return Type.MakeFunctionPointerSignatureType(this.ToType(), parameterTypes, isUnmanaged);

if (rtType == typeof(void) || rtType.IsGenericTypeDefinition)
throw new ArgumentException(string.Format(SR.FunctionPointer_ParameterInvalid, rtType.ToString()), nameof(parameterTypes));

runtimeParameterTypes[i] = rtType.GetRuntimeTypeInfo();
}

return this.GetFunctionPointerType(runtimeParameterTypes, isUnmanaged).ToType();
}

public Type MakePointerType()
{
return this.GetPointerType().ToType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,9 @@ public override Type MakeArrayType()
public override Type MakeArrayType(int rank)
=> GetRuntimeTypeInfo().MakeArrayType(rank);

public override Type MakeFunctionPointerType(Type[]? parameterTypes, bool isUnmanaged = false)
=> GetRuntimeTypeInfo().MakeFunctionPointerType(parameterTypes, isUnmanaged);

[RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public override Type MakeGenericType(params Type[] instantiation)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/qcallentrypoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ static const Entry s_QCall[] =
DllImportEntry(RuntimeTypeHandle_MakeByRef)
DllImportEntry(RuntimeTypeHandle_MakeSZArray)
DllImportEntry(RuntimeTypeHandle_MakeArray)
DllImportEntry(RuntimeTypeHandle_MakeFunctionPointer)
DllImportEntry(RuntimeTypeHandle_GetConstraints)
DllImportEntry(RuntimeTypeHandle_GetArgumentTypesFromFunctionPointer)
DllImportEntry(RuntimeTypeHandle_GetAssemblySlow)
Expand Down
16 changes: 16 additions & 0 deletions src/coreclr/vm/runtimehandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,22 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_MakeByRef(QCall::TypeHandle pTypeHan
return;
}

extern "C" void QCALLTYPE RuntimeTypeHandle_MakeFunctionPointer(TypeHandle* pRetAndArgTypes, INT32 numArgs, BOOL isUnmanaged, QCall::ObjectHandleOnStack retType)
{
QCALL_CONTRACT;

TypeHandle fnPtrHandle;

BEGIN_QCALL;
BYTE callConv = (BYTE)(isUnmanaged ? IMAGE_CEE_CS_CALLCONV_UNMANAGED : IMAGE_CEE_CS_CALLCONV_DEFAULT);
fnPtrHandle = ClassLoader::LoadFnptrTypeThrowing(callConv, numArgs, pRetAndArgTypes);
GCX_COOP();
retType.Set(fnPtrHandle.GetManagedClassObject());
END_QCALL;

return;
}

extern "C" void QCALLTYPE RuntimeTypeHandle_Instantiate(QCall::TypeHandle pTypeHandle, TypeHandle * pInstArray, INT32 cInstArray, QCall::ObjectHandleOnStack retType)
{
QCALL_CONTRACT;
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 @@ -160,6 +160,7 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_MakeByRef(QCall::TypeHandle pTypeHan
extern "C" void QCALLTYPE RuntimeTypeHandle_MakePointer(QCall::TypeHandle pTypeHandle, QCall::ObjectHandleOnStack retType);
extern "C" void QCALLTYPE RuntimeTypeHandle_MakeSZArray(QCall::TypeHandle pTypeHandle, QCall::ObjectHandleOnStack retType);
extern "C" void QCALLTYPE RuntimeTypeHandle_MakeArray(QCall::TypeHandle pTypeHandle, INT32 rank, QCall::ObjectHandleOnStack retType);
extern "C" void QCALLTYPE RuntimeTypeHandle_MakeFunctionPointer(TypeHandle* pRetAndArgTypes, INT32 numArgs, BOOL isUnmanaged, QCall::ObjectHandleOnStack retType);
extern "C" void QCALLTYPE RuntimeTypeHandle_PrepareMemberInfoCache(QCall::TypeHandle pMemberInfoCache);
extern "C" void QCALLTYPE RuntimeTypeHandle_ConstructName(QCall::TypeHandle pTypeHandle, DWORD format, QCall::StringHandleOnStack retString);
extern "C" void QCALLTYPE RuntimeTypeHandle_GetInterfaces(MethodTable* pMT, QCall::ObjectHandleOnStack result);
Expand Down
12 changes: 12 additions & 0 deletions src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4441,4 +4441,16 @@
<data name="IO_SharedMemory_DirectoryOwnerPermissionsIncorrect" xml:space="preserve">
<value>The directory '{0}' does not have the expected owner permissions: {1}.</value>
</data>
<data name="Argument_MustBeFunctionPointer" xml:space="preserve">
<value>Argument must represent a function pointer type.</value>
</data>
<data name="ManagedFunctionPointer_CallingConventionsNotAllowed">
<value>Unmanaged calling conventions cannot be specified for managed function pointers.</value>
</data>
<data name="FunctionPointer_ParameterInvalid">
<value>'{0}' cannot be used as a parameter type for a function pointer.</value>
</data>
<data name="NotSupported_FunctionPointerSignature">
<value>Function pointer signature can only be encoded by dynamic ILGenerator.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -778,9 +778,11 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureByRefType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureCallingConvention.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureConstructedGenericType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureFunctionPointerType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureGenericMethodParameterType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureGenericParameterType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureHasElementType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureModifiedType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignaturePointerType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\SignatureTypeExtensions.cs" />
Expand Down Expand Up @@ -2938,4 +2940,4 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Wasi\WasiPollWorld.wit.imports.wasi.io.v0_2_0.IPoll.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Wasi\WasiPollWorld.wit.imports.wasi.io.v0_2_0.PollInterop.cs" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ public abstract void EmitCalli(OpCode opcode, CallingConventions callingConventi

public abstract void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type? returnType, Type[]? parameterTypes);

/// <summary>
/// Puts a <see cref="OpCodes.Calli"/> instruction onto the Microsoft intermediate language (MSIL) stream,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept this description largely the same as the existing overloads. I think it might make more sense to update it though, since as far as I'm concerned the term MSIL was dropped in favor of CIL.

/// specifying the type of the function pointer to indirectly call.
/// </summary>
/// <param name="functionPointerType">
/// The type of the function pointer to indirectly call.
/// The specified type must represent a function pointer type.
/// </param>
public virtual void EmitCalli(Type functionPointerType) => throw new NotSupportedException(SR.NotSupported_SubclassOverride);

public abstract void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[]? optionalParameterTypes);

public abstract void Emit(OpCode opcode, SignatureHelper signature);
Expand Down
Loading
Loading