Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

PInvoke calli #5960

Merged
merged 3 commits into from
Jul 2, 2018
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
2 changes: 1 addition & 1 deletion src/Common/src/TypeSystem/IL/ILProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ private MethodIL CreateMethodIL(MethodDesc method)
if (((MetadataType)method.OwningType).HasCustomAttribute("System.Runtime.InteropServices", "McgIntrinsicsAttribute"))
{
var name = method.Name;
if (name == "Call")
if (name == "Call" || name == "StdCall")
{
return CalliIntrinsic.EmitIL(method);
}
Expand Down
8 changes: 6 additions & 2 deletions src/Common/src/TypeSystem/IL/Stubs/CalliIntrinsic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static class CalliIntrinsic
{
public static MethodIL EmitIL(MethodDesc target)
{
Debug.Assert(target.Name == "Call");
Debug.Assert(target.Name == "Call" || target.Name == "StdCall");
Debug.Assert(target.Signature.Length > 0
&& target.Signature[0] == target.Context.GetWellKnownType(WellKnownType.IntPtr));

Expand All @@ -44,7 +44,11 @@ public static MethodIL EmitIL(MethodDesc target)
parameters[i - 1] = template[i];
}

var signature = new MethodSignature(template.Flags, 0, returnType, parameters);
MethodSignatureFlags flags = template.Flags;
if (target.Name == "StdCall")
flags |= MethodSignatureFlags.UnmanagedCallingConventionStdCall;

var signature = new MethodSignature(flags, 0, returnType, parameters);
codeStream.Emit(ILOpcode.calli, emitter.NewToken(signature));
codeStream.Emit(ILOpcode.ret);

Expand Down
15 changes: 11 additions & 4 deletions src/Common/src/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ public override MethodSignature Signature
// Prepend fnptr argument to the signature
TypeDesc[] parameterTypes = new TypeDesc[_targetSignature.Length + 1];

parameterTypes[0] = Context.GetWellKnownType(WellKnownType.IntPtr);
for (int i = 0; i < _targetSignature.Length; i++)
parameterTypes[i + 1] = _targetSignature[i];
parameterTypes[i] = _targetSignature[i];
parameterTypes[parameterTypes.Length - 1] = Context.GetWellKnownType(WellKnownType.IntPtr);

_signature = new MethodSignature(MethodSignatureFlags.Static, 0, _targetSignature.ReturnType, parameterTypes);
}
Expand All @@ -80,10 +80,17 @@ public override string Name
}
}

public override bool IsPInvoke
{
get
{
return true;
}
}

public override MethodIL EmitIL()
{
// TODO
throw null;
return PInvokeILEmitter.EmitIL(this, default(PInvokeILEmitterConfiguration), _interopStateManager);
}
}
}
75 changes: 56 additions & 19 deletions src/Common/src/TypeSystem/IL/Stubs/PInvokeILEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@ private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration
// targetMethod could be either a PInvoke or a DelegateMarshallingMethodThunk
// ForwardNativeFunctionWrapper method thunks are marked as PInvokes, so it is
// important to check them first here so that we get the right flags.
//
DelegateMarshallingMethodThunk delegateThunk = _targetMethod as DelegateMarshallingMethodThunk;

if (delegateThunk != null)
//
if (_targetMethod is DelegateMarshallingMethodThunk delegateMethod)
{
_flags = ((EcmaType)delegateThunk.DelegateType).GetDelegatePInvokeFlags();
_flags = ((EcmaType)delegateMethod.DelegateType).GetDelegatePInvokeFlags();
}
else
{
Expand All @@ -57,9 +55,21 @@ private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration

private static Marshaller[] InitializeMarshallers(MethodDesc targetMethod, InteropStateManager interopStateManager, PInvokeFlags flags)
{
bool isDelegate = targetMethod is DelegateMarshallingMethodThunk;
MethodSignature methodSig = isDelegate ? ((DelegateMarshallingMethodThunk)targetMethod).DelegateSignature : targetMethod.Signature;
MarshalDirection direction = isDelegate ? ((DelegateMarshallingMethodThunk)targetMethod).Direction: MarshalDirection.Forward;
MarshalDirection direction = MarshalDirection.Forward;
MethodSignature methodSig;
switch (targetMethod)
{
case DelegateMarshallingMethodThunk delegateMethod:
methodSig = delegateMethod.DelegateSignature;
direction = delegateMethod.Direction;
break;
case CalliMarshallingMethodThunk calliMethod:
methodSig = calliMethod.TargetSignature;
break;
default:
methodSig = targetMethod.Signature;
break;
}
int indexOffset = 0;
if (!methodSig.IsStatic && direction == MarshalDirection.Forward)
{
Expand Down Expand Up @@ -282,6 +292,27 @@ private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams)
}
}

private void EmitCalli(PInvokeILCodeStreams ilCodeStreams, CalliMarshallingMethodThunk calliThunk)
{
ILEmitter emitter = ilCodeStreams.Emitter;
ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream;

TypeDesc nativeReturnType = _marshallers[0].NativeParameterType;
TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1];

for (int i = 1; i < _marshallers.Length; i++)
{
nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType;
}

MethodSignature nativeSig = new MethodSignature(
calliThunk.TargetSignature.Flags, 0, nativeReturnType,
nativeParameterTypes);

callsiteSetupCodeStream.EmitLdArg(calliThunk.TargetSignature.Length);
callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig));
}

private MethodIL EmitIL()
{
PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams();
Expand All @@ -295,20 +326,23 @@ private MethodIL EmitIL()
}

// make the call
DelegateMarshallingMethodThunk delegateMethod = _targetMethod as DelegateMarshallingMethodThunk;
if (delegateMethod != null)
{
EmitDelegateCall(delegateMethod, pInvokeILCodeStreams);
}
else
switch (_targetMethod)
{
EmitPInvokeCall(pInvokeILCodeStreams);
case DelegateMarshallingMethodThunk delegateMethod:
EmitDelegateCall(delegateMethod, pInvokeILCodeStreams);
break;
case CalliMarshallingMethodThunk calliMethod:
EmitCalli(pInvokeILCodeStreams, calliMethod);
break;
default:
EmitPInvokeCall(pInvokeILCodeStreams);
break;
}

_marshallers[0].LoadReturnValue(unmarshallingCodestream);
unmarshallingCodestream.Emit(ILOpcode.ret);

return new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired());
return new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired());
}

public static MethodIL EmitIL(MethodDesc method,
Expand Down Expand Up @@ -342,11 +376,14 @@ private bool IsStubRequired()
return true;
}

if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module,
_pInvokeILEmitterConfiguration))
if (_pInvokeILEmitterConfiguration != null)
{
return true;
if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration))
{
return true;
}
}

if (_flags.SetLastError)
{
return true;
Expand Down
56 changes: 42 additions & 14 deletions src/JitInterface/src/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -760,13 +760,8 @@ private uint getMethodAttribsInternal(MethodDesc method)
result |= CorInfoFlag.CORINFO_FLG_SHAREDINST;

if (method.IsPInvoke)
{
result |= CorInfoFlag.CORINFO_FLG_PINVOKE;

// See comment in pInvokeMarshalingRequired
result |= CorInfoFlag.CORINFO_FLG_DONT_INLINE;
}

// TODO: Cache inlining hits
// Check for an inlining directive.

Expand Down Expand Up @@ -1037,23 +1032,34 @@ private CorInfoUnmanagedCallConv getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* me
return (CorInfoUnmanagedCallConv)unmanagedCallConv;
}

private bool IsPInvokeStubRequired(MethodDesc method)
{
return ((Internal.IL.Stubs.PInvokeILStubMethodIL)_compilation.GetMethodIL(method)).IsStubRequired;
}

private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* handle, CORINFO_SIG_INFO* callSiteSig)
{
// TODO: Support for PInvoke calli with marshalling. For now, assume there is no marshalling required.
// calli is covered by convertPInvokeCalliToCall
if (handle == null)
{
#if DEBUG
MethodSignature methodSignature = (MethodSignature)HandleToObject((IntPtr)callSiteSig->pSig);

MethodDesc stub = _compilation.PInvokeILProvider.GetCalliStub(methodSignature);
Debug.Assert(!IsPInvokeStubRequired(stub));
#endif

return false;
}

MethodDesc method = HandleToObject(handle);

if (method.IsRawPInvoke())
return false;

// TODO: Ideally, we would just give back the PInvoke stub IL to the JIT and let it inline it, without
// checking whether it is required upfront. Unfortunatelly, RyuJIT is not able to generate PInvoke
// transitions in inlined methods today (impCheckForPInvokeCall is not called for inlinees and number of other places
// depend on it). To get a decent code with this limitation, we mirror CoreCLR behavior: Check
// whether PInvoke stub is required here, and disable inlining of PInvoke methods in getMethodAttribsInternal.
return ((Internal.IL.Stubs.PInvokeILStubMethodIL)_compilation.GetMethodIL(method)).IsStubRequired;
// We could have given back the PInvoke stub IL to the JIT and let it inline it, without
// checking whether there is any stub required. Save the JIT from doing the inlining by checking upfront.
return IsPInvokeStubRequired(method);
}

private bool satisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method)
Expand Down Expand Up @@ -3450,8 +3456,30 @@ private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd)

private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool mustConvert)
{
Debug.Assert(!mustConvert);
return false;
var methodIL = (MethodIL)HandleToObject((IntPtr)pResolvedToken.tokenScope);
if (methodIL.OwningMethod.IsPInvoke)
{
return false;
}

MethodSignature signature = (MethodSignature)methodIL.GetObject((int)pResolvedToken.token);

CorInfoCallConv callConv = (CorInfoCallConv)(signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask);
if (callConv != CorInfoCallConv.CORINFO_CALLCONV_C &&
callConv != CorInfoCallConv.CORINFO_CALLCONV_STDCALL &&
callConv != CorInfoCallConv.CORINFO_CALLCONV_THISCALL &&
callConv != CorInfoCallConv.CORINFO_CALLCONV_FASTCALL)
{
return false;
}

MethodDesc stub = _compilation.PInvokeILProvider.GetCalliStub(signature);
if (!mustConvert && !IsPInvokeStubRequired(stub))
return false;

pResolvedToken.hMethod = ObjectToHandle(stub);
pResolvedToken.hClass = ObjectToHandle(stub.OwningType);
return true;
}

private void* getMemoryManager()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace System.Threading
public partial class EventWaitHandle : WaitHandle
{
public EventWaitHandle(bool initialState, EventResetMode mode) :
this(initialState, mode, null, out _)
{
}
this(initialState, mode, null, out _)
{
}

public EventWaitHandle(bool initialState, EventResetMode mode, string name) :
this(initialState, mode, name, out _)
Expand Down
8 changes: 0 additions & 8 deletions tests/CoreCLR.issues.targets
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
<ItemGroup Condition="'$(XunitTestBinBase)' != ''">

<!-- Pinvoke calli -->
<!-- https://github.com/dotnet/corert/issues/5587 -->
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\Invoke\SEH\_il_dbgcatchfinally_ind\_il_dbgcatchfinally_ind.*" />
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\Invoke\SEH\_il_relcatchfinally_ind\_il_relcatchfinally_ind.*" />
<ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\CLR-x86-JIT\V2.0-RTM\b487364\b487364\b487364.*" />

<!-- Infinite generic expansion -->
<!-- https://github.com/dotnet/corert/issues/363 -->
<ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\inlining\bug505642\test\test.*" />
Expand Down Expand Up @@ -266,8 +260,6 @@
<ExcludeList Include="$(XunitTestBinBase)\Interop\RefCharArray\RefCharArrayTest\RefCharArrayTest.*" />
<ExcludeList Include="$(XunitTestBinBase)\Interop\RefInt\RefIntTest\RefIntTest.*" />
<ExcludeList Include="$(XunitTestBinBase)\Interop\StringMarshalling\LPTSTR\LPTSTRTest\LPTSTRTest.*" />
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\coverage\oldtests\Desktop\callipinvoke_il_d\callipinvoke_il_d.*" />
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\coverage\oldtests\Desktop\callipinvoke_il_r\callipinvoke_il_r.*" />
<ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\IL\PInvokeTail\TailWinApi\TailWinApi.*" />
<ExcludeList Include="$(XunitTestBinBase)\Interop\ICastable\Castable\Castable.*" />
<ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\pinvoke\instance01\instance01.*" />
Expand Down