diff options
Diffstat (limited to 'src/Common/src/TypeSystem/Interop/IL/Marshaller.cs')
-rw-r--r-- | src/Common/src/TypeSystem/Interop/IL/Marshaller.cs | 159 |
1 files changed, 89 insertions, 70 deletions
diff --git a/src/Common/src/TypeSystem/Interop/IL/Marshaller.cs b/src/Common/src/TypeSystem/Interop/IL/Marshaller.cs index ef75539f1..d7e88915d 100644 --- a/src/Common/src/TypeSystem/Interop/IL/Marshaller.cs +++ b/src/Common/src/TypeSystem/Interop/IL/Marshaller.cs @@ -718,6 +718,9 @@ namespace Internal.TypeSystem.Interop PropagateToByRefArg(_ilCodeStreams.UnmarshallingCodestream, _managedHome); } } + + // TODO This should be in finally block + // https://github.com/dotnet/corert/issues/6075 EmitCleanupManaged(_ilCodeStreams.UnmarshallingCodestream); } @@ -1634,9 +1637,9 @@ namespace Internal.TypeSystem.Interop } - class SafeHandleMarshaller : ReferenceMarshaller + class SafeHandleMarshaller : Marshaller { - protected override void AllocNativeToManaged(ILCodeStream codeStream) + private void AllocSafeHandle(ILCodeStream codeStream) { var ctor = ManagedType.GetParameterlessConstructor(); if (ctor == null) @@ -1651,11 +1654,29 @@ namespace Internal.TypeSystem.Interop codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(String.Format("'{0}' does not have a default constructor. Subclasses of SafeHandle must have a default constructor to support marshaling a Windows HANDLE into managed code.", name))); codeStream.Emit(ILOpcode.newobj, emitter.NewToken(exceptionCtor)); codeStream.Emit(ILOpcode.throw_); + return; } - else - { - base.AllocNativeToManaged(codeStream); - } + + codeStream.Emit(ILOpcode.newobj, _ilCodeStreams.Emitter.NewToken(ctor)); + } + + protected override void EmitMarshalReturnValueManagedToNative() + { + ILEmitter emitter = _ilCodeStreams.Emitter; + ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; + ILCodeStream returnValueMarshallingCodeStream = _ilCodeStreams.ReturnValueMarshallingCodeStream; + + SetupArgumentsForReturnValueMarshalling(); + + AllocSafeHandle(marshallingCodeStream); + StoreManagedValue(marshallingCodeStream); + + StoreNativeValue(returnValueMarshallingCodeStream); + + LoadManagedValue(returnValueMarshallingCodeStream); + LoadNativeValue(returnValueMarshallingCodeStream); + returnValueMarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( + InteropTypes.GetSafeHandle(Context).GetKnownMethod("SetHandle", null))); } protected override void EmitMarshalArgumentManagedToNative() @@ -1672,42 +1693,13 @@ namespace Internal.TypeSystem.Interop PropagateFromByRefArg(marshallingCodeStream, _managedHome); } - // TODO: https://github.com/dotnet/corert/issues/3291 - // We don't support [IN,OUT] together yet, either IN or OUT. - if (Out && In) - { - throw new NotSupportedException("Marshalling an argument as both in and out not yet implemented"); - } - var safeHandleType = InteropTypes.GetSafeHandle(Context); - if (Out && IsManagedByRef) + if (In) { - // 1) If this is an output parameter we need to preallocate a SafeHandle to wrap the new native handle value. We - // must allocate this before the native call to avoid a failure point when we already have a native resource - // allocated. We must allocate a new SafeHandle even if we have one on input since both input and output native - // handles need to be tracked and released by a SafeHandle. - // 2) Initialize a local IntPtr that will be passed to the native call. - // 3) After the native call, the new handle value is written into the output SafeHandle and that SafeHandle - // is propagated back to the caller. - var vOutValue = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); - var vSafeHandle = emitter.NewLocal(ManagedType); - marshallingCodeStream.Emit(ILOpcode.newobj, emitter.NewToken(ManagedType.GetParameterlessConstructor())); - marshallingCodeStream.EmitStLoc(vSafeHandle); - _ilCodeStreams.CallsiteSetupCodeStream.EmitLdLoca(vOutValue); - - unmarshallingCodeStream.EmitLdLoc(vSafeHandle); - unmarshallingCodeStream.EmitLdLoc(vOutValue); - unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( - safeHandleType.GetKnownMethod("SetHandle", null))); - - unmarshallingCodeStream.EmitLdLoc(vSafeHandle); - StoreManagedValue(unmarshallingCodeStream); + if (IsManagedByRef) + PropagateFromByRefArg(marshallingCodeStream, _managedHome); - PropagateToByRefArg(unmarshallingCodeStream, _managedHome); - } - else - { var vAddRefed = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Boolean)); LoadManagedValue(marshallingCodeStream); marshallingCodeStream.EmitLdLoca(vAddRefed); @@ -1719,44 +1711,56 @@ namespace Internal.TypeSystem.Interop safeHandleType.GetKnownMethod("DangerousGetHandle", null))); StoreNativeValue(marshallingCodeStream); - // TODO: This should be inside finally block and only executed it the handle was addrefed + // TODO: This should be inside finally block and only executed if the handle was addrefed + // https://github.com/dotnet/corert/issues/6075 LoadManagedValue(unmarshallingCodeStream); unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( safeHandleType.GetKnownMethod("DangerousRelease", null))); - - LoadNativeArg(_ilCodeStreams.CallsiteSetupCodeStream); } - } + if (Out && IsManagedByRef) + { + // 1) If this is an output parameter we need to preallocate a SafeHandle to wrap the new native handle value. We + // must allocate this before the native call to avoid a failure point when we already have a native resource + // allocated. We must allocate a new SafeHandle even if we have one on input since both input and output native + // handles need to be tracked and released by a SafeHandle. + // 2) Initialize a local IntPtr that will be passed to the native call. + // 3) After the native call, the new handle value is written into the output SafeHandle and that SafeHandle + // is propagated back to the caller. + var vSafeHandle = emitter.NewLocal(ManagedType); + AllocSafeHandle(marshallingCodeStream); + marshallingCodeStream.EmitStLoc(vSafeHandle); - protected override void TransformNativeToManaged(ILCodeStream codeStream) - { - LoadManagedValue(codeStream); - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken( - InteropTypes.GetSafeHandle(Context).GetKnownMethod("SetHandle", null))); - } - } + var lSkipPropagation = emitter.NewCodeLabel(); + if (In) + { + // Propagate the value only if it has changed + ILLocalVariable vOriginalValue = emitter.NewLocal(NativeType); + LoadNativeValue(marshallingCodeStream); + marshallingCodeStream.EmitStLoc(vOriginalValue); + + unmarshallingCodeStream.EmitLdLoc(vOriginalValue); + LoadNativeValue(unmarshallingCodeStream); + unmarshallingCodeStream.Emit(ILOpcode.beq, lSkipPropagation); + } - class ReferenceMarshaller : Marshaller - { - protected override void AllocNativeToManaged(ILCodeStream codeStream) - { - var emitter = _ilCodeStreams.Emitter; - var lNull = emitter.NewCodeLabel(); + unmarshallingCodeStream.EmitLdLoc(vSafeHandle); + LoadNativeValue(unmarshallingCodeStream); + unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( + safeHandleType.GetKnownMethod("SetHandle", null))); - // Check for null - LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.brfalse, lNull); + unmarshallingCodeStream.EmitLdArg(Index - 1); + unmarshallingCodeStream.EmitLdLoc(vSafeHandle); + unmarshallingCodeStream.EmitStInd(ManagedType); - codeStream.Emit(ILOpcode.newobj, emitter.NewToken( - ManagedType.GetParameterlessConstructor())); - StoreManagedValue(codeStream); - codeStream.EmitLabel(lNull); + unmarshallingCodeStream.EmitLabel(lSkipPropagation); + } + + LoadNativeArg(callsiteCodeStream); } } - class StringBuilderMarshaller : ReferenceMarshaller + class StringBuilderMarshaller : Marshaller { private bool _isAnsi; public StringBuilderMarshaller(bool isAnsi) @@ -1778,6 +1782,21 @@ namespace Internal.TypeSystem.Interop Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemFree"))); } + protected override void AllocNativeToManaged(ILCodeStream codeStream) + { + var emitter = _ilCodeStreams.Emitter; + var lNull = emitter.NewCodeLabel(); + + // Check for null + LoadNativeValue(codeStream); + codeStream.Emit(ILOpcode.brfalse, lNull); + + codeStream.Emit(ILOpcode.newobj, emitter.NewToken( + ManagedType.GetParameterlessConstructor())); + StoreManagedValue(codeStream); + codeStream.EmitLabel(lNull); + } + protected override void AllocManagedToNative(ILCodeStream codeStream) { ILEmitter emitter = _ilCodeStreams.Emitter; @@ -1877,8 +1896,8 @@ namespace Internal.TypeSystem.Interop protected override void TransformNativeToManaged(ILCodeStream codeStream) { - LoadManagedAddr(codeStream); LoadNativeAddr(codeStream); + LoadManagedAddr(codeStream); codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken( InteropStateManager.GetStructMarshallingNativeToManagedThunk(ManagedType))); } @@ -2072,7 +2091,7 @@ namespace Internal.TypeSystem.Interop var managedElementType = ((ArrayType)ManagedType).ElementType; ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); - codeStream.EmitLdArg(0); + codeStream.EmitLdArg(1); // load the length EmitElementCount(codeStream, MarshalDirection.Reverse); codeStream.EmitStLoc(vLength); @@ -2092,13 +2111,13 @@ namespace Internal.TypeSystem.Interop codeStream.EmitLabel(lLoopHeader); // load managed type - codeStream.EmitLdArg(0); + codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); codeStream.EmitLdLoc(vIndex); // load native type - codeStream.EmitLdArg(1); + codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(_nativeField)); codeStream.EmitLdLoc(vIndex); @@ -2172,9 +2191,9 @@ namespace Internal.TypeSystem.Interop ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream codeStream = _ilCodeStreams.UnmarshallingCodestream; - codeStream.EmitLdArg(0); - codeStream.EmitLdArg(1); + + codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(_nativeField)); codeStream.Emit(ILOpcode.conv_u); |