Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

switch to using CSTRMarshaller instead of AnsiBSTR #55032

Merged
merged 9 commits into from
Jul 13, 2021
91 changes: 87 additions & 4 deletions src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,10 @@ protected override void EmitCleanupManaged(ILCodeStream codeStream)

class AnsiStringMarshaller : Marshaller
{
const int MAX_LOCAL_BUFFER_LENGTH = 256; // TODO: Is this accurate on all platforms?
mangod9 marked this conversation as resolved.
Show resolved Hide resolved

private ILLocalVariable m_localBuffer = default;
mangod9 marked this conversation as resolved.
Show resolved Hide resolved

internal override bool CleanupRequired
mangod9 marked this conversation as resolved.
Show resolved Hide resolved
{
get
Expand All @@ -1605,20 +1609,82 @@ protected override void TransformManagedToNative(ILCodeStream codeStream)

#if READYTORUN
mangod9 marked this conversation as resolved.
Show resolved Hide resolved
var stringToAnsi =
Context.SystemModule.GetKnownType("System.StubHelpers", "AnsiBSTRMarshaler")
Context.SystemModule.GetKnownType("System.StubHelpers", "CSTRMarshaler")
.GetKnownMethod("ConvertToNative", null);

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

if (bPassByValueInOnly)
Copy link
Member Author

Choose a reason for hiding this comment

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

is there a reason why this logic cant move to System.StubHelpers.CSTRMarshaler ?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, it would be nice to have majority of the logic in C#, and minimize amount of the hand-emitted IL.

{
var bufSize = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32));
m_localBuffer = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr));

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

var noOptimize = emitter.NewCodeLabel();

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

// String.Length + 2
LoadManagedValue(codeStream);
var stringLen =
Context.SystemModule.GetKnownType("System", "String")
mangod9 marked this conversation as resolved.
Show resolved Hide resolved
.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(m_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 (m_localBuffer != default)
{
codeStream.EmitLdLoc(m_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

Expand All @@ -1631,7 +1697,7 @@ protected override void TransformNativeToManaged(ILCodeStream codeStream)

#if READYTORUN
var ansiToString =
Context.SystemModule.GetKnownType("System.StubHelpers", "AnsiBSTRMarshaler")
Context.SystemModule.GetKnownType("System.StubHelpers", "CSTRMarshaler")
.GetKnownMethod("ConvertToManaged", null);
#else
var ansiToString = Context.GetHelperEntryPoint("InteropHelpers", "AnsiStringToString");
Expand All @@ -1645,11 +1711,28 @@ protected override void EmitCleanupManaged(ILCodeStream codeStream)
{
var emitter = _ilCodeStreams.Emitter;
#if READYTORUN
var optimize = emitter.NewCodeLabel();

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

if (m_localBuffer != default)
{
// if (m_dwLocalBuffer) goto Optimize
codeStream.EmitLdLoc(m_localBuffer);
codeStream.Emit(ILOpcode.brtrue, optimize);
}

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

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

Expand Down