Skip to content

Commit

Permalink
Remove complex marshalling support from crossgen2 (#70183)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkoritzinsky authored Jun 7, 2022
1 parent c27d571 commit 9f654ce
Show file tree
Hide file tree
Showing 6 changed files with 5 additions and 196 deletions.
134 changes: 0 additions & 134 deletions src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1544,16 +1544,12 @@ protected override void TransformManagedToNative(ILCodeStream codeStream)
}
else
{
#if READYTORUN
throw new NotSupportedException();
#else
var helper = Context.GetHelperEntryPoint("InteropHelpers", "StringToUnicodeBuffer");
LoadManagedValue(codeStream);

codeStream.Emit(ILOpcode.call, emitter.NewToken(helper));

StoreNativeValue(codeStream);
#endif
}
}

Expand Down Expand Up @@ -1593,11 +1589,6 @@ protected override void EmitCleanupManaged(ILCodeStream codeStream)

class AnsiStringMarshaller : Marshaller
{
#if READYTORUN
const int MAX_LOCAL_BUFFER_LENGTH = 260 + 1; // MAX_PATH + 1

private ILLocalVariable? _localBuffer = null;
#endif

internal override bool CleanupRequired
{
Expand All @@ -1620,103 +1611,21 @@ protected override void TransformManagedToNative(ILCodeStream codeStream)
//
// ANSI marshalling. Allocate a byte array, copy characters
//

#if READYTORUN
var stringToAnsi =
Context.SystemModule.GetKnownType("System.StubHelpers", "CSTRMarshaler")
.GetKnownMethod("ConvertToNative", null);

bool bPassByValueInOnly = In && !Out && !IsManagedByRef;

if (bPassByValueInOnly)
{
var bufSize = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32));
_localBuffer = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr));

// LocalBuffer = 0
codeStream.Emit(ILOpcode.ldnull);
codeStream.EmitStLoc((ILLocalVariable)_localBuffer);

var noOptimize = emitter.NewCodeLabel();

// if == NULL, goto NoOptimize
LoadManagedValue(codeStream);
codeStream.Emit(ILOpcode.brfalse, noOptimize);

// String.Length + 2
LoadManagedValue(codeStream);
var stringLen =
Context.GetWellKnownType(WellKnownType.String)
.GetKnownMethod("get_Length", null);
codeStream.Emit(ILOpcode.call, emitter.NewToken(stringLen));
codeStream.EmitLdc(2);
codeStream.Emit(ILOpcode.add);

// (String.Length + 2) * GetMaxDBCSCharByteSize()
codeStream.Emit(ILOpcode.ldsfld, emitter.NewToken(Context.SystemModule.GetKnownType(
"System.Runtime.InteropServices","Marshal")
.GetKnownField("SystemMaxDBCSCharSize")));
codeStream.Emit(ILOpcode.mul_ovf);

// BufSize = (String.Length + 2) * GetMaxDBCSCharByteSize()
codeStream.EmitStLoc(bufSize);

// if (MAX_LOCAL_BUFFER_LENGTH < BufSize ) goto NoOptimize
codeStream.EmitLdc(MAX_LOCAL_BUFFER_LENGTH + 1);
codeStream.EmitLdLoc(bufSize);
codeStream.Emit(ILOpcode.clt);
codeStream.Emit(ILOpcode.brtrue, noOptimize);

// LocalBuffer = localloc(BufSize);
codeStream.EmitLdLoc(bufSize);
codeStream.Emit(ILOpcode.localloc);
codeStream.EmitStLoc((ILLocalVariable)_localBuffer);

// NoOptimize:
codeStream.EmitLabel(noOptimize);
}

int flags = (PInvokeFlags.BestFitMapping ? 0x1 : 0)
| (PInvokeFlags.ThrowOnUnmappableChar ? 0x100 : 0);

// CSTRMarshaler.ConvertToNative pManaged, dwAnsiMarshalFlags, pLocalBuffer
codeStream.EmitLdc(flags);
LoadManagedValue(codeStream);

if (_localBuffer.HasValue)
{
codeStream.EmitLdLoc((ILLocalVariable)_localBuffer);
}
else
{
codeStream.Emit(ILOpcode.ldnull);
}

codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi));
#else
LoadManagedValue(codeStream);
var stringToAnsi = Context.GetHelperEntryPoint("InteropHelpers", "StringToAnsiString");

codeStream.Emit(PInvokeFlags.BestFitMapping ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0);
codeStream.Emit(PInvokeFlags.ThrowOnUnmappableChar ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0);

codeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi));
#endif

StoreNativeValue(codeStream);
}

protected override void TransformNativeToManaged(ILCodeStream codeStream)
{
ILEmitter emitter = _ilCodeStreams.Emitter;

#if READYTORUN
var ansiToString =
Context.SystemModule.GetKnownType("System.StubHelpers", "CSTRMarshaler")
.GetKnownMethod("ConvertToManaged", null);
#else
var ansiToString = Context.GetHelperEntryPoint("InteropHelpers", "AnsiStringToString");
#endif
LoadNativeValue(codeStream);
codeStream.Emit(ILOpcode.call, emitter.NewToken(ansiToString));
StoreManagedValue(codeStream);
Expand All @@ -1725,30 +1634,6 @@ protected override void TransformNativeToManaged(ILCodeStream codeStream)
protected override void EmitCleanupManaged(ILCodeStream codeStream)
{
var emitter = _ilCodeStreams.Emitter;
#if READYTORUN
var optimize = emitter.NewCodeLabel();

MethodDesc clearNative =
Context.SystemModule.GetKnownType("System.StubHelpers", "CSTRMarshaler")
.GetKnownMethod("ClearNative", null);

if (_localBuffer.HasValue)
{
// if (m_dwLocalBuffer) goto Optimize
codeStream.EmitLdLoc((ILLocalVariable)_localBuffer);
codeStream.Emit(ILOpcode.brtrue, optimize);
}

LoadNativeValue(codeStream);
// static void m_idClearNative(IntPtr ptr)
codeStream.Emit(ILOpcode.call, emitter.NewToken(clearNative));

// Optimize:
if (_localBuffer != default)
{
codeStream.EmitLabel(optimize);
}
#else
var lNullCheck = emitter.NewCodeLabel();

// Check for null array
Expand All @@ -1760,7 +1645,6 @@ protected override void EmitCleanupManaged(ILCodeStream codeStream)
InteropTypes.GetMarshal(Context).GetKnownMethod("FreeCoTaskMem", null)));

codeStream.EmitLabel(lNullCheck);
#endif
}
}

Expand Down Expand Up @@ -2042,11 +1926,7 @@ protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream
codeStream.Emit(ILOpcode.brfalse, lNullPointer);

codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
#if READYTORUN
InteropTypes.GetMarshal(Context).GetKnownMethod("GetFunctionPointerForDelegate",
#else
InteropTypes.GetPInvokeMarshal(Context).GetKnownMethod("GetFunctionPointerForDelegate",
#endif
new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.IntPtr),
new TypeDesc[] { Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType }
))));
Expand All @@ -2070,27 +1950,13 @@ protected override void TransformNativeToManaged(ILCodeStream codeStream)
LoadNativeValue(codeStream);
codeStream.Emit(ILOpcode.dup);
codeStream.Emit(ILOpcode.brfalse, lNullPointer);

#if READYTORUN
TypeDesc systemType = Context.SystemModule.GetKnownType("System", "Type");

codeStream.Emit(ILOpcode.ldtoken, _ilCodeStreams.Emitter.NewToken(ManagedType));
codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(systemType.GetKnownMethod("GetTypeFromHandle", null)));

codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
InteropTypes.GetMarshal(Context).GetKnownMethod("GetDelegateForFunctionPointer",
new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType,
new TypeDesc[] { Context.GetWellKnownType(WellKnownType.IntPtr), systemType }
))));
#else
codeStream.Emit(ILOpcode.ldtoken, _ilCodeStreams.Emitter.NewToken(ManagedType));

codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
InteropTypes.GetPInvokeMarshal(Context).GetKnownMethod("GetDelegateForFunctionPointer",
new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType,
new TypeDesc[] { Context.GetWellKnownType(WellKnownType.IntPtr), Context.GetWellKnownType(WellKnownType.RuntimeTypeHandle) }
))));
#endif

codeStream.Emit(ILOpcode.br, lDone);

Expand Down
5 changes: 0 additions & 5 deletions src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ public static MetadataType GetMemoryMarshal(TypeSystemContext context)
return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "MemoryMarshal");
}

public static MetadataType GetStubHelpers(TypeSystemContext context)
{
return context.SystemModule.GetKnownType("System.StubHelpers", "StubHelpers");
}

public static MetadataType GetNativeFunctionPointerWrapper(TypeSystemContext context)
{
return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "NativeFunctionPointerWrapper");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,23 +349,6 @@ public sealed override bool CanInline(MethodDesc callerMethod, MethodDesc callee

public sealed override bool GeneratesPInvoke(MethodDesc method)
{
// PInvokes depend on details of the core library, so for now only compile them if:
// 1) We're compiling the core library module, or
// 2) We're compiling any module, and no marshalling is needed
//
// TODO Future: consider compiling PInvokes with complex marshalling in version bubble
// mode when the core library is included in the bubble.

Debug.Assert(method is EcmaMethod);

// If the PInvoke is declared on an external module, we can only compile it if
// that module is part of the version bubble.
if (!_versionBubbleModuleSet.Contains(((EcmaMethod)method).Module))
return false;

if (((EcmaMethod)method).Module.Equals(method.Context.SystemModule))
return true;

return !Marshaller.IsMarshallingRequired(method);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,6 @@ private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams)
TypeDesc nativeReturnType = _marshallers[0].NativeParameterType;
TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1];

MetadataType stubHelpersType = InteropTypes.GetStubHelpers(context);

// if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
if (_importMetadata.Flags.SetLastError)
{
if (!MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)_targetMethod.OwningType).Module))
{
// When runtime marshalling is disabled, we don't support generating the stub IL
// in Ready-to-Run so we can correctly throw an exception at runtime when the user tries to
// use SetLastError=true when marshalling is disabled.
throw new NotSupportedException();
}
callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
stubHelpersType.GetKnownMethod("ClearLastError", null)));
}

for (int i = 1; i < _marshallers.Length; i++)
{
nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType;
Expand All @@ -69,14 +53,6 @@ private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams)
var rawTargetMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig);

callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(rawTargetMethod));

// if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastError
// so that last error can be used later by calling Marshal.GetLastPInvokeError
if (_importMetadata.Flags.SetLastError)
{
callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
stubHelpersType.GetKnownMethod("SetLastError", null)));
}
}

private MethodIL EmitIL()
Expand All @@ -93,6 +69,9 @@ private MethodIL EmitIL()
if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute"))
throw new NotSupportedException();

if (_importMetadata.Flags.SetLastError)
throw new NotSupportedException();

PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams();
ILEmitter emitter = pInvokeILCodeStreams.Emitter;
ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,16 @@ partial class Marshaller
{
protected static Marshaller CreateMarshaller(MarshallerKind kind)
{
// ReadyToRun only supports emitting IL for blittable types
switch (kind)
{
case MarshallerKind.Enum:
case MarshallerKind.BlittableValue:
case MarshallerKind.BlittableStruct:
case MarshallerKind.UnicodeChar:
return new BlittableValueMarshaller();
case MarshallerKind.BlittableStructPtr:
return new BlittableStructPtrMarshaller();
case MarshallerKind.BlittableArray:
return new BlittableArrayMarshaller();
case MarshallerKind.Bool:
case MarshallerKind.CBool:
return new BooleanMarshaller();
case MarshallerKind.AnsiString:
return new AnsiStringMarshaller();
case MarshallerKind.SafeHandle:
return new SafeHandleMarshaller();
case MarshallerKind.UnicodeString:
return new UnicodeStringMarshaller();
case MarshallerKind.VoidReturn:
return new VoidReturnMarshaller();
case MarshallerKind.FunctionPointer:
return new DelegateMarshaller();
default:
// ensures we don't throw during create marshaller. We will throw NSE
// during EmitIL which will be handled.
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/dllimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3366,7 +3366,7 @@ BOOL NDirect::MarshalingRequired(

default:
{
if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_FNPTR)
if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_PTR || type == ELEMENT_TYPE_FNPTR)
{

if (i > 0)
Expand Down

0 comments on commit 9f654ce

Please sign in to comment.