Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -170,6 +170,7 @@
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\SignatureHelper.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\SymbolMethod.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\FieldInfo.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\InstanceCalliHelper.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\LoaderAllocator.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\MdConstant.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\MdFieldInfo.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

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

namespace System.Reflection
{
/// <summary>
/// Provides a set of helper methods for calling instance methods using calli.
/// This is necessary since C# function pointers currently do not support instance methods.
/// </summary>
internal static unsafe class InstanceCalliHelper
{
// Zero parameter methods such as property getters:

[Intrinsic]
internal static bool Call(delegate*<object, bool> fn, object o) => fn(o);

[Intrinsic]
internal static byte Call(delegate*<object, byte> fn, object o) => fn(o);

[Intrinsic]
internal static char Call(delegate*<object, char> fn, object o) => fn(o);

[Intrinsic]
internal static DateTime Call(delegate*<object, DateTime> fn, object o) => fn(o);

[Intrinsic]
internal static DateTimeOffset Call(delegate*<object, DateTimeOffset> fn, object o) => fn(o);

[Intrinsic]
internal static decimal Call(delegate*<object, decimal> fn, object o) => fn(o);

[Intrinsic]
internal static double Call(delegate*<object, double> fn, object o) => fn(o);

[Intrinsic]
internal static float Call(delegate*<object, float> fn, object o) => fn(o);

[Intrinsic]
internal static Guid Call(delegate*<object, Guid> fn, object o) => fn(o);

[Intrinsic]
internal static short Call(delegate*<object, short> fn, object o) => fn(o);

[Intrinsic]
internal static int Call(delegate*<object, int> fn, object o) => fn(o);

[Intrinsic]
internal static long Call(delegate*<object, long> fn, object o) => fn(o);

[Intrinsic]
internal static nint Call(delegate*<object, nint> fn, object o) => fn(o);

[Intrinsic]
internal static nuint Call(delegate*<object, nuint> fn, object o) => fn(o);

[Intrinsic]
internal static object? Call(delegate*<object, object?> fn, object o) => fn(o);

[Intrinsic]
internal static sbyte Call(delegate*<object, sbyte> fn, object o) => fn(o);

[Intrinsic]
internal static ushort Call(delegate*<object, ushort> fn, object o) => fn(o);

[Intrinsic]
internal static uint Call(delegate*<object, uint> fn, object o) => fn(o);

[Intrinsic]
internal static ulong Call(delegate*<object, ulong> fn, object o) => fn(o);

[Intrinsic]
internal static void Call(delegate*<object, void> fn, object o) => fn(o);

// One parameter methods with no return such as property setters:

[Intrinsic]
internal static void Call(delegate*<object, bool, void> fn, object o, bool arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, byte, void> fn, object o, byte arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, char, void> fn, object o, char arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, DateTime, void> fn, object o, DateTime arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, DateTimeOffset, void> fn, object o, DateTimeOffset arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, decimal, void> fn, object o, decimal arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, double, void> fn, object o, double arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, float, void> fn, object o, float arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, Guid, void> fn, object o, Guid arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, short, void> fn, object o, short arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, int, void> fn, object o, int arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, long, void> fn, object o, long arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, nint, void> fn, object o, nint arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, nuint, void> fn, object o, nuint arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, object?, void> fn, object o, object? arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, sbyte, void> fn, object o, sbyte arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, ushort, void> fn, object o, ushort arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, uint, void> fn, object o, uint arg1) => fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, ulong, void> fn, object o, ulong arg1) => fn(o, arg1);

// Other methods:

[Intrinsic]
internal static void Call(delegate*<object, object?, object?, void> fn, object o, object? arg1, object? arg2)
=> fn(o, arg1, arg2);

[Intrinsic]
internal static void Call(delegate*<object, object?, object?, object?, void> fn, object o, object? arg1, object? arg2, object? arg3)
=> fn(o, arg1, arg2, arg3);

[Intrinsic]
internal static void Call(delegate*<object, object?, object?, object?, object?, void> fn, object o, object? arg1, object? arg2, object? arg3, object? arg4)
=> fn(o, arg1, arg2, arg3, arg4);

[Intrinsic]
internal static void Call(delegate*<object, object?, object?, object?, object?, object?, void> fn, object o, object? arg1, object? arg2, object? arg3, object? arg4, object? arg5)
=> fn(o, arg1, arg2, arg3, arg4, arg5);

[Intrinsic]
internal static void Call(delegate*<object, object?, object?, object?, object?, object?, object?, void> fn, object o, object? arg1, object? arg2, object? arg3, object? arg4, object? arg5, object? arg6)
=> fn(o, arg1, arg2, arg3, arg4, arg5, arg6);

[Intrinsic]
internal static void Call(delegate*<object, IEnumerable<object>?, void> fn, object o, IEnumerable<object>? arg1)
=> fn(o, arg1);

[Intrinsic]
internal static void Call(delegate*<object, IEnumerable<object>?, IEnumerable<object>?, void> fn, object o, IEnumerable<object>? arg1, IEnumerable<object>? arg2)
=> fn(o, arg1, arg2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ private MethodIL TryGetIntrinsicMethodIL(MethodDesc method)
return UnsafeIntrinsics.EmitIL(method);
}

if (mdType.Name == "InstanceCalliHelper" && mdType.Namespace == "System.Reflection")
{
return InstanceCalliHelperIntrinsics.EmitIL(method);
}

return null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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.Reflection.Metadata.Ecma335;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

namespace Internal.IL
{
public class InstanceCalliHelperIntrinsics
{
public static MethodIL EmitIL(MethodDesc method)
{
MethodIL methodIL = EcmaMethodIL.Create((EcmaMethod)method);

if (method.Name.StartsWith("Invoke", StringComparison.Ordinal))
{
methodIL = new ExplicitThisCall(methodIL);
}

return methodIL;
}

private class ExplicitThisCall : MethodIL
{
private readonly MethodIL _wrappedMethodIL;

public ExplicitThisCall(MethodIL wrapped)
{
_wrappedMethodIL = wrapped;
}

// MethodIL overrides:
public override int MaxStack => _wrappedMethodIL.MaxStack;
public override bool IsInitLocals => _wrappedMethodIL.IsInitLocals;
public override byte[] GetILBytes() => _wrappedMethodIL.GetILBytes();
public override LocalVariableDefinition[] GetLocals() => _wrappedMethodIL.GetLocals();
public override ILExceptionRegion[] GetExceptionRegions() => _wrappedMethodIL.GetExceptionRegions();
public override MethodDebugInformation GetDebugInfo() => _wrappedMethodIL.GetDebugInfo();

// MethodILScope overrides:
public override MethodIL GetMethodILDefinition() => _wrappedMethodIL.GetMethodILDefinition();
public override MethodDesc OwningMethod => _wrappedMethodIL.OwningMethod;
public override string ToString() => _wrappedMethodIL.ToString();
public override object GetObject(int token, NotFoundBehavior notFoundBehavior)
{
object item = _wrappedMethodIL.GetObject(token, notFoundBehavior);
if (item is MethodSignature sig)
{
var builder = new MethodSignatureBuilder(sig);
builder.Flags = (sig.Flags | MethodSignatureFlags.ExplicitThis) & ~MethodSignatureFlags.Static;
item = builder.ToSignature();
}

return item;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@
<Compile Include="Compiler\ReadyToRunXmlRootProvider.cs" />
<Compile Include="IBC\IBCProfileData.cs" />
<Compile Include="IBC\IBCProfileParser.cs" />
<Compile Include="IL\Stubs\InstanceCalliHelperIntrinsics.cs" />
<Compile Include="IL\Stubs\PInvokeILEmitter.cs" />
<Compile Include="Interop\IL\Marshaller.ReadyToRun.cs" />
<Compile Include="Compiler\PerfEventSource.cs" />
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ set(VM_SOURCES_WKS
hosting.cpp
hostinformation.cpp
ilmarshalers.cpp
instancecalli.cpp
interopconverter.cpp
interoputil.cpp
interpexec.cpp
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,10 @@ DEFINE_CLASS(MEMBER, Reflection, MemberInfo)

DEFINE_CLASS(METHODBASEINVOKER, Reflection, MethodBaseInvoker)

DEFINE_CLASS_U(Reflection, RuntimeMethodInfo, NoClass)
DEFINE_FIELD_U(m_handle, ReflectMethodObject, m_pMD)
DEFINE_CLASS(INSTANCE_CALLI_HELPER, Reflection, InstanceCalliHelper)

DEFINE_CLASS_U(Reflection, RuntimeMethodInfo, NoClass)
DEFINE_FIELD_U(m_handle, ReflectMethodObject, m_pMD)
DEFINE_CLASS(METHOD, Reflection, RuntimeMethodInfo)
DEFINE_METHOD(METHOD, INVOKE, Invoke, IM_Obj_BindingFlags_Binder_ArrObj_CultureInfo_RetObj)
DEFINE_METHOD(METHOD, GET_PARAMETERS, GetParameters, IM_RetArrParameterInfo)
Expand Down
86 changes: 86 additions & 0 deletions src/coreclr/vm/instancecalli.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "common.h"

void MethodDesc::GenerateFunctionPointerCall(DynamicResolver** resolver, COR_ILMETHOD_DECODER** methodILDecoder)
{
STANDARD_VM_CONTRACT;
_ASSERTE(resolver != NULL);
_ASSERTE(methodILDecoder != NULL);
_ASSERTE(*resolver == NULL && *methodILDecoder == NULL);
_ASSERTE(IsIL());
_ASSERTE(GetRVA() != 0);

// Intrinsic must be a static method.
_ASSERTE(IsStatic());

MetaSig declarationSig(this);
UINT argCount = declarationSig.NumFixedArgs();

// Intrinsic must have at least the function pointer and the "this" argument.
_ASSERTE(argCount >= 2);

SigTypeContext genericContext;
ILStubLinker sl(
this->GetModule(),
GetSignature(),
&genericContext,
this,
(ILStubLinkerFlags)ILSTUB_LINKER_FLAG_NONE);

ILCodeStream* pCode = sl.NewCodeStream(ILStubLinker::kDispatch);

// Copy the first arg which has the function pointer signature into a SigBuilder to add HASTHIS and EXPLICITTHIS
// and to get a token for the new signature.
// The signature follows details defined in ECMA-335 - II.23.2.1
declarationSig.SkipArg();
SigPointer sp = declarationSig.GetArgProps();

CorElementType eType;
sp.GetElemType(&eType); // Skip past the element type to get at the signature.
_ASSERTE(eType == ELEMENT_TYPE_FNPTR);

SigBuilder sigBuilder;
sp.CopySignature(GetModule(), &sigBuilder, IMAGE_CEE_CS_CALLCONV_HASTHIS | IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS);

// Create a token for the new signature.
DWORD sigLen;
PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature((DWORD*)&sigLen);
mdToken fcnPtrToken = pCode->GetSigToken(pSig, sigLen);

// Load "this" and each argument to the function pointer.
for (UINT i = 1; i < argCount; ++i)
pCode->EmitLDARG(i);

// Load the function pointer and call it.
pCode->EmitLDARG(0);
pCode->EmitCALLI(fcnPtrToken, argCount - 1, declarationSig.IsReturnTypeVoid() ? 0 : 1);
pCode->EmitRET();

// Generate all IL associated data for JIT.
NewHolder<ILStubResolver> ilResolver = new ILStubResolver();
ilResolver->SetStubMethodDesc(this);

{
UINT maxStack;
size_t cbCode = sl.Link(&maxStack);
DWORD cbSig = sl.GetLocalSigSize();

COR_ILMETHOD_DECODER* pILHeader = ilResolver->AllocGeneratedIL(cbCode, cbSig, maxStack);
BYTE* pbBuffer = (BYTE*)pILHeader->Code;
BYTE* pbLocalSig = (BYTE*)pILHeader->LocalVarSig;
_ASSERTE(cbSig == pILHeader->cbLocalVarSig);
sl.GenerateCode(pbBuffer, cbCode);
sl.GetLocalSig(pbLocalSig, cbSig);

// Store the token lookup map.
ilResolver->SetTokenLookupMap(sl.GetTokenLookupMap());
ilResolver->SetJitFlags(CORJIT_FLAGS(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB));

*resolver = (DynamicResolver*)ilResolver;
*methodILDecoder = pILHeader;
}

ilResolver.SuppressRelease();
}
7 changes: 7 additions & 0 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7555,6 +7555,13 @@ static void getMethodInfoHelper(
{
fILIntrinsic = getILIntrinsicImplementationForActivator(ftn, methInfo, &localSig);
}
else if (CoreLibBinder::IsClass(pMT, CLASS__INSTANCE_CALLI_HELPER))
{
// We can ignore the existing header, since we are going to generate a new one.
cxt.Header = NULL;

ftn->GenerateFunctionPointerCall(&cxt.TransientResolver, &cxt.Header);
}
}

scopeHnd = cxt.HasTransientMethodDetails()
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1886,6 +1886,7 @@ class MethodDesc
PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pilHeader, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode);

public:
void GenerateFunctionPointerCall(DynamicResolver** resolver, COR_ILMETHOD_DECODER** methodILDecoder);
bool TryGenerateUnsafeAccessor(DynamicResolver** resolver, COR_ILMETHOD_DECODER** methodILDecoder);
#endif // DACCESS_COMPILE

Expand Down
Loading
Loading