protected override TypeDesc MarshalArgument(TypeDesc managedType, ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream unmarshallingCodeStream) { TypeSystemContext context = PInvokeMethodData.Context; if (PInvokeMethodData.GetCharSet() == PInvokeAttributes.CharSetUnicode) { // TODO: Handles [out] marshalling only for now var stringBuilderType = context.SystemModule.GetKnownType("System.Text", "StringBuilder"); var charArrayType = context.GetWellKnownType(WellKnownType.Char).MakeArrayType(); IL.Stubs.ILLocalVariable vStringBuilder = emitter.NewLocal(stringBuilderType); IL.Stubs.ILLocalVariable vBuffer = emitter.NewLocal(charArrayType); marshallingCodeStream.EmitStLoc(vStringBuilder); marshallingCodeStream.EmitLdLoc(vStringBuilder); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.GetHelperEntryPoint("InteropHelpers", "GetEmptyStringBuilderBuffer"))); marshallingCodeStream.EmitStLoc(vBuffer); unmarshallingCodeStream.EmitLdLoc(vStringBuilder); unmarshallingCodeStream.EmitLdLoc(vBuffer); unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.GetHelperEntryPoint("InteropHelpers", "ReplaceStringBuilderBuffer"))); marshallingCodeStream.EmitLdLoc(vBuffer); return(base.MarshalArgument(charArrayType, emitter, marshallingCodeStream, unmarshallingCodeStream)); } else { throw new NotSupportedException(); } }
protected override void EmitMarshalArgumentManagedToNative() { ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; ILEmitter emitter = _ilCodeStreams.Emitter; var arrayType = (ArrayType)ManagedParameterType; Debug.Assert(arrayType.IsSzArray); IL.Stubs.ILLocalVariable vPinnedFirstElement = emitter.NewLocal(arrayType.ParameterType.MakeByRefType(), true); IL.Stubs.ILLocalVariable vArray = emitter.NewLocal(arrayType); ILCodeLabel lNullArray = emitter.NewCodeLabel(); // Check for null array, or 0 element array. marshallingCodeStream.Emit(ILOpcode.dup); marshallingCodeStream.EmitStLoc(vArray); marshallingCodeStream.Emit(ILOpcode.brfalse, lNullArray); marshallingCodeStream.EmitLdLoc(vArray); marshallingCodeStream.Emit(ILOpcode.ldlen); marshallingCodeStream.Emit(ILOpcode.conv_i4); marshallingCodeStream.Emit(ILOpcode.brfalse, lNullArray); // Array has elements. marshallingCodeStream.EmitLdLoc(vArray); marshallingCodeStream.EmitLdc(0); marshallingCodeStream.Emit(ILOpcode.ldelema, emitter.NewToken(arrayType.ElementType)); marshallingCodeStream.EmitStLoc(vPinnedFirstElement); // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit. marshallingCodeStream.EmitLabel(lNullArray); marshallingCodeStream.EmitLdLoc(vPinnedFirstElement); marshallingCodeStream.Emit(ILOpcode.conv_i); NativeParameterType = PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr); }
protected override void EmitMarshalArgumentManagedToNative() { ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; ILCodeStream unmarshallingCodeStream = _ilCodeStreams.UnmarshallingCodestream; TypeSystemContext context = PInvokeMethodData.Context; // TODO: Handles [out] marshalling only for now var stringBuilderType = context.SystemModule.GetKnownType("System.Text", "StringBuilder"); var charArrayType = context.GetWellKnownType(WellKnownType.Char).MakeArrayType(); IL.Stubs.ILLocalVariable vStringBuilder = emitter.NewLocal(stringBuilderType); IL.Stubs.ILLocalVariable vBuffer = emitter.NewLocal(charArrayType); marshallingCodeStream.EmitStLoc(vStringBuilder); marshallingCodeStream.EmitLdLoc(vStringBuilder); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.GetHelperEntryPoint("InteropHelpers", "GetEmptyStringBuilderBuffer"))); marshallingCodeStream.EmitStLoc(vBuffer); unmarshallingCodeStream.EmitLdLoc(vStringBuilder); unmarshallingCodeStream.EmitLdLoc(vBuffer); unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.GetHelperEntryPoint("InteropHelpers", "ReplaceStringBuilderBuffer"))); marshallingCodeStream.EmitLdLoc(vBuffer); ManagedParameterType = charArrayType; base.EmitMarshalArgumentManagedToNative(); }
protected override void EmitMarshalArgumentManagedToNative() { ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; TypeSystemContext context = PInvokeMethodData.Context; // // Unicode marshalling. Pin the string and push a pointer to the first character on the stack. // TypeDesc stringType = context.GetWellKnownType(WellKnownType.String); IL.Stubs.ILLocalVariable vPinnedString = emitter.NewLocal(stringType, true); ILCodeLabel lNullString = emitter.NewCodeLabel(); marshallingCodeStream.EmitStLoc(vPinnedString); marshallingCodeStream.EmitLdLoc(vPinnedString); marshallingCodeStream.Emit(ILOpcode.conv_i); marshallingCodeStream.Emit(ILOpcode.dup); // Marshalling a null string? marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.SystemModule. GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers"). GetKnownMethod("get_OffsetToStringData", null))); marshallingCodeStream.Emit(ILOpcode.add); marshallingCodeStream.EmitLabel(lNullString); NativeParameterType = context.GetWellKnownType(WellKnownType.IntPtr); }
protected override TypeDesc MarshalArgument(TypeDesc managedType, ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream unmarshallingCodeStream) { var safeHandleType = PInvokeMethodData.SafeHandleType; var vAddRefed = emitter.NewLocal(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.Boolean)); var vSafeHandle = emitter.NewLocal(managedType); marshallingCodeStream.EmitStLoc(vSafeHandle); marshallingCodeStream.EmitLdLoc(vSafeHandle); marshallingCodeStream.EmitLdLoca(vAddRefed); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( safeHandleType.GetKnownMethod("DangerousAddRef", null))); marshallingCodeStream.EmitLdLoc(vSafeHandle); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( safeHandleType.GetKnownMethod("DangerousGetHandle", null))); // TODO: This should be inside finally block and only executed it the handle was addrefed unmarshallingCodeStream.EmitLdLoc(vSafeHandle); unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( safeHandleType.GetKnownMethod("DangerousRelease", null))); return(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr)); }
protected override void EmitElementCount(ILCodeStream codeStream, MarshalDirection direction) { ILEmitter emitter = _ilCodeStreams.Emitter; if (MarshalAsDescriptor == null || !MarshalAsDescriptor.SizeConst.HasValue) { throw new InvalidProgramException("SizeConst is required for ByValArray."); } if (direction == MarshalDirection.Forward) { // In forward direction ElementCount = Min(managed.length, SizeConst); var vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); var lSmaller = emitter.NewCodeLabel(); var lDone = emitter.NewCodeLabel(); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); var lNullCheck = emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.brfalse, lNullCheck); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); codeStream.Emit(ILOpcode.ldlen); codeStream.Emit(ILOpcode.conv_i4); codeStream.EmitStLoc(vLength); codeStream.EmitLabel(lNullCheck); Debug.Assert(MarshalAsDescriptor.SizeConst.HasValue); int sizeConst = (int)MarshalAsDescriptor.SizeConst.Value; codeStream.EmitLdc(sizeConst); codeStream.EmitLdLoc(vLength); codeStream.Emit(ILOpcode.blt, lSmaller); codeStream.EmitLdLoc(vLength); codeStream.Emit(ILOpcode.br, lDone); codeStream.EmitLabel(lSmaller); codeStream.EmitLdc(sizeConst); codeStream.EmitLabel(lDone); } else { // In reverse direction ElementCount = SizeConst; Debug.Assert(MarshalAsDescriptor.SizeConst.HasValue); int sizeConst = (int)MarshalAsDescriptor.SizeConst.Value; codeStream.EmitLdc(sizeConst); } }
protected override TypeDesc MarshalArgument(TypeDesc managedType, ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream unmarshallingCodeStream) { var byRefType = (ByRefType)managedType; IL.Stubs.ILLocalVariable vPinnedByRef = emitter.NewLocal(byRefType, true); marshallingCodeStream.EmitStLoc(vPinnedByRef); marshallingCodeStream.EmitLdLoc(vPinnedByRef); marshallingCodeStream.Emit(ILOpcode.conv_i); return(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr)); }
protected virtual void EmitByRefManagedToNative() { ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; ILEmitter emitter = _ilCodeStreams.Emitter; var byRefType = (ByRefType)ManagedParameterType; IL.Stubs.ILLocalVariable vPinnedByRef = emitter.NewLocal(byRefType, true); marshallingCodeStream.EmitStLoc(vPinnedByRef); marshallingCodeStream.EmitLdLoc(vPinnedByRef); marshallingCodeStream.Emit(ILOpcode.conv_i); NativeParameterType = PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr); }
private ILLocalVariable InitializeMarshallerVariable() { if (MarshallerLocalVariable != (ILLocalVariable)(-1)) { return(MarshallerLocalVariable); } var marshallerType = MarshalAsDescriptor.MarshallerType; if (marshallerType.IsGenericDefinition) { ThrowHelper.ThrowTypeLoadException(marshallerType); } var customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler"); var getInstanceMethod = marshallerType.GetMethod( "GetInstance", new MethodSignature(MethodSignatureFlags.Static, 0, customMarshallerType, new[] { Context.GetWellKnownType(WellKnownType.String) })); if (ManagedType.IsValueType || ManagedType.IsPointer || ManagedType.IsFunctionPointer) { ThrowHelper.ThrowMarshalDirectiveException(); } var initializeCustomMarshallerMethod = Context.GetHelperEntryPoint("InteropHelpers", "InitializeCustomMarshaller"); ILEmitter emitter = _ilCodeStreams.Emitter; MarshallerLocalVariable = emitter.NewLocal(customMarshallerType); var cookie = MarshalAsDescriptor.Cookie; // Custom marshaller initialization should not be catched, so initialize early ILCodeStream fnptrLoadStream = _ilCodeStreams.FunctionPointerLoadStream; fnptrLoadStream.Emit(ILOpcode.ldtoken, emitter.NewToken(ManagedType)); fnptrLoadStream.Emit(ILOpcode.ldtoken, emitter.NewToken(marshallerType)); fnptrLoadStream.Emit(ILOpcode.ldstr, emitter.NewToken(cookie)); if (getInstanceMethod != null) { fnptrLoadStream.Emit(ILOpcode.ldftn, emitter.NewToken(getInstanceMethod)); } else { fnptrLoadStream.EmitLdc(0); fnptrLoadStream.Emit(ILOpcode.conv_i); } fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(initializeCustomMarshallerMethod)); fnptrLoadStream.EmitStLoc(MarshallerLocalVariable); return(MarshallerLocalVariable); }
protected override TypeDesc MarshalArgument(TypeDesc managedType, ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream unmarshallingCodeStream) { TypeSystemContext context = PInvokeMethodData.Context; if (PInvokeMethodData.GetCharSet() == PInvokeAttributes.CharSetUnicode) { // // Unicode marshalling. Pin the string and push a pointer to the first character on the stack. // TypeDesc stringType = context.GetWellKnownType(WellKnownType.String); IL.Stubs.ILLocalVariable vPinnedString = emitter.NewLocal(stringType, true); ILCodeLabel lNullString = emitter.NewCodeLabel(); marshallingCodeStream.EmitStLoc(vPinnedString); marshallingCodeStream.EmitLdLoc(vPinnedString); marshallingCodeStream.Emit(ILOpcode.conv_i); marshallingCodeStream.Emit(ILOpcode.dup); // Marshalling a null string? marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.SystemModule. GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers"). GetKnownMethod("get_OffsetToStringData", null))); marshallingCodeStream.Emit(ILOpcode.add); marshallingCodeStream.EmitLabel(lNullString); return(context.GetWellKnownType(WellKnownType.IntPtr)); } else { // // ANSI marshalling. Allocate a byte array, copy characters, pin first element. // var stringToAnsi = context.GetHelperEntryPoint("InteropHelpers", "StringToAnsi"); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi)); // Call the Array marshaller MarshalArgument return(base.MarshalArgument(context.GetWellKnownType(WellKnownType.Byte).MakeArrayType(), emitter, marshallingCodeStream, unmarshallingCodeStream)); } }
public void EmitMarshallingIL(ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream callsiteSetupCodeStream, ILCodeStream unmarshallingCodeStream, ILCodeStream returnValueCodeStream) { if (!PInvokeParameterMetadata.Return) { marshallingCodeStream.EmitLdArg(PInvokeParameterMetadata.Index - 1); NativeType = MarshalArgument(ManagedType, emitter, marshallingCodeStream, unmarshallingCodeStream); IL.Stubs.ILLocalVariable vMarshalledTypeTemp = emitter.NewLocal(NativeType); marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } else { NativeType = MarshalReturn(ManagedType, emitter, marshallingCodeStream, returnValueCodeStream); } }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); ILLocalVariable returnValue = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); MetadataType startup = Context.GetHelperType("StartupCodeHelpers"); codeStream.Emit(ILOpcode.call, emitter.NewToken(startup.GetKnownMethod("Initialize", null))); // Initialize command line args // TODO: For Windows change to "InitializeCommandLineArgsW" with wmain wchar_t change. string initArgsName = (Context.Target.OperatingSystem == TargetOS.Windows) ? "InitializeCommandLineArgs" : "InitializeCommandLineArgs"; MethodDesc initArgs = startup.GetKnownMethod(initArgsName, null); codeStream.Emit(ILOpcode.ldarg_0); // argc codeStream.Emit(ILOpcode.ldarg_1); // argv codeStream.Emit(ILOpcode.call, emitter.NewToken(initArgs)); // Call program Main if (_mainMethod.Signature.Length > 0) { TypeDesc environ = Context.SystemModule.GetKnownType("System", "Environment"); codeStream.Emit(ILOpcode.call, emitter.NewToken(environ.GetKnownMethod("GetCommandLineArgs", null))); } codeStream.Emit(ILOpcode.call, emitter.NewToken(_mainMethod)); if (_mainMethod.Signature.ReturnType.IsVoid) { codeStream.EmitLdc(0); } codeStream.EmitStLoc(returnValue); codeStream.Emit(ILOpcode.call, emitter.NewToken(startup.GetKnownMethod("Shutdown", null))); codeStream.EmitLdLoc(returnValue); codeStream.Emit(ILOpcode.ret); return(emitter.Link()); }
protected override TypeDesc MarshalReturn(TypeDesc managedType, ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream returnValueMarshallingCodeStream) { var nativeType = PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr); var vSafeHandle = emitter.NewLocal(managedType); var vReturnValue = emitter.NewLocal(nativeType); marshallingCodeStream.Emit(ILOpcode.newobj, emitter.NewToken(managedType.GetDefaultConstructor())); marshallingCodeStream.EmitStLoc(vSafeHandle); returnValueMarshallingCodeStream.EmitStLoc(vReturnValue); returnValueMarshallingCodeStream.EmitLdLoc(vSafeHandle); returnValueMarshallingCodeStream.EmitLdLoc(vReturnValue); returnValueMarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( PInvokeMethodData.SafeHandleType.GetKnownMethod("SetHandle", null))); returnValueMarshallingCodeStream.EmitLdLoc(vSafeHandle); return(nativeType); }
protected override void EmitMarshalReturnValueManagedToNative() { ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream returnValueMarshallingCodeStream = _ilCodeStreams.ReturnValueMarshallingCodeStream; ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; NativeParameterType = PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr); var vSafeHandle = emitter.NewLocal(ManagedParameterType); var vReturnValue = emitter.NewLocal(NativeParameterType); marshallingCodeStream.Emit(ILOpcode.newobj, emitter.NewToken(ManagedParameterType.GetDefaultConstructor())); marshallingCodeStream.EmitStLoc(vSafeHandle); returnValueMarshallingCodeStream.EmitStLoc(vReturnValue); returnValueMarshallingCodeStream.EmitLdLoc(vSafeHandle); returnValueMarshallingCodeStream.EmitLdLoc(vReturnValue); returnValueMarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( PInvokeMethodData.SafeHandleType.GetKnownMethod("SetHandle", null))); returnValueMarshallingCodeStream.EmitLdLoc(vSafeHandle); }
protected override void AllocManagedToNative(ILCodeStream codeStream) { ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeLabel lNull = emitter.NewCodeLabel(); ILLocalVariable lSize = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); LoadManagedValue(codeStream); codeStream.Emit(ILOpcode.brfalse, lNull); MethodDesc getNativeSizeHelper = Context.GetHelperEntryPoint("InteropHelpers", "AsAnyGetNativeSize"); LoadManagedValue(codeStream); codeStream.Emit(ILOpcode.call, emitter.NewToken(getNativeSizeHelper)); codeStream.Emit(ILOpcode.dup); codeStream.EmitStLoc(lSize); codeStream.Emit(ILOpcode.localloc); codeStream.Emit(ILOpcode.dup); StoreNativeValue(codeStream); codeStream.EmitLdc(0); codeStream.EmitLdLoc(lSize); codeStream.Emit(ILOpcode.initblk); codeStream.EmitLabel(lNull); }
protected override void EmitMarshalFieldManagedToNative() { // It generates the following code //if (ManagedArg.Field != null) //{ // // fixed (InlineArray* pUnsafe = &NativeArg.Field) // { // uint index = 0u; // while ((ulong)index < (ulong)((long)ManagedArg.Field.Length)) // { // NativeArg.s[index] = ManagedArg.Field[(int)index]; // index += 1u; // } // } //} ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream codeStream = _ilCodeStreams.MarshallingCodeStream; var nativeArrayType = NativeType as InlineArrayType; Debug.Assert(nativeArrayType != null); Debug.Assert(ManagedType is ArrayType); var managedElementType = ((ArrayType)ManagedType).ElementType; ILCodeLabel lDone = emitter.NewCodeLabel(); ILCodeLabel lRangeCheck = emitter.NewCodeLabel(); ILCodeLabel lLoopHeader = emitter.NewCodeLabel(); ILLocalVariable vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable vNative = emitter.NewLocal(NativeType.MakeByRefType(), isPinned: true); // check if ManagedType == null, then return codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); codeStream.Emit(ILOpcode.brfalse, lDone); codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(_nativeField)); codeStream.EmitStLoc(vNative); EmitElementCount(codeStream, MarshalDirection.Forward); codeStream.EmitStLoc(vLength); codeStream.EmitLdc(0); codeStream.EmitStLoc(vIndex); codeStream.Emit(ILOpcode.br, lRangeCheck); codeStream.EmitLabel(lLoopHeader); codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(_nativeField)); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdElem(managedElementType); // generate marshalling IL for the element GetElementMarshaller(MarshalDirection.Forward) .EmitMarshallingIL(new PInvokeILCodeStreams(_ilCodeStreams.Emitter, codeStream)); codeStream.Emit(ILOpcode.call, emitter.NewToken( nativeArrayType.GetInlineArrayMethod(InlineArrayMethodKind.Setter))); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdc(1); codeStream.Emit(ILOpcode.add); codeStream.EmitStLoc(vIndex); codeStream.EmitLabel(lRangeCheck); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); codeStream.Emit(ILOpcode.blt, lLoopHeader); codeStream.EmitLabel(lDone); }
protected override void EmitMarshalArgumentManagedToNative() { ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; ILCodeStream unmarshallingCodeStream = _ilCodeStreams.UnmarshallingCodestream; // we don't support [IN,OUT] together yet, either IN or OUT Debug.Assert(!(PInvokeParameterMetadata.Out && PInvokeParameterMetadata.In)); var safeHandleType = PInvokeMethodData.SafeHandleType; if (Out) { // 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. Debug.Assert(ManagedParameterType is ByRefType); var vOutArg = emitter.NewLocal(ManagedParameterType); marshallingCodeStream.EmitStLoc(vOutArg); TypeDesc resolvedType = ((ByRefType)ManagedParameterType).ParameterType; var nativeType = PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr).MakeByRefType(); var vOutValue = emitter.NewLocal(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr)); var vSafeHandle = emitter.NewLocal(resolvedType); marshallingCodeStream.Emit(ILOpcode.newobj, emitter.NewToken(resolvedType.GetDefaultConstructor())); marshallingCodeStream.EmitStLoc(vSafeHandle); marshallingCodeStream.EmitLdLoca(vOutValue); unmarshallingCodeStream.EmitLdLoc(vSafeHandle); unmarshallingCodeStream.EmitLdLoc(vOutValue); unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( PInvokeMethodData.SafeHandleType.GetKnownMethod("SetHandle", null))); unmarshallingCodeStream.EmitLdLoc(vOutArg); unmarshallingCodeStream.EmitLdLoc(vSafeHandle); unmarshallingCodeStream.Emit(ILOpcode.stind_i); NativeParameterType = nativeType; } else { var vAddRefed = emitter.NewLocal(PInvokeMethodData.Context.GetWellKnownType(WellKnownType.Boolean)); var vSafeHandle = emitter.NewLocal(ManagedParameterType); marshallingCodeStream.EmitStLoc(vSafeHandle); marshallingCodeStream.EmitLdLoc(vSafeHandle); marshallingCodeStream.EmitLdLoca(vAddRefed); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( safeHandleType.GetKnownMethod("DangerousAddRef", null))); marshallingCodeStream.EmitLdLoc(vSafeHandle); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( safeHandleType.GetKnownMethod("DangerousGetHandle", null))); // TODO: This should be inside finally block and only executed it the handle was addrefed unmarshallingCodeStream.EmitLdLoc(vSafeHandle); unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( safeHandleType.GetKnownMethod("DangerousRelease", null))); NativeParameterType = PInvokeMethodData.Context.GetWellKnownType(WellKnownType.IntPtr); } }
protected override void EmitMarshalFieldNativeToManaged() { ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream codeStream = _ilCodeStreams.UnmarshallingCodestream; // It generates the following IL: // ManagedArg.s = new ElementType[Length]; // // for (uint index = 0u; index < Length; index += 1u) // { // ManagedArg.s[index] = NativeArg.s[index]; // } // ILCodeLabel lRangeCheck = emitter.NewCodeLabel(); ILCodeLabel lLoopHeader = emitter.NewCodeLabel(); Debug.Assert(ManagedType is ArrayType); var nativeArrayType = NativeType as InlineArrayType; Debug.Assert(nativeArrayType != null); var managedElementType = ((ArrayType)ManagedType).ElementType; ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); codeStream.EmitLdArg(1); // load the length EmitElementCount(codeStream, MarshalDirection.Reverse); codeStream.EmitStLoc(vLength); codeStream.EmitLdLoc(vLength); codeStream.Emit(ILOpcode.newarr, emitter.NewToken(managedElementType)); codeStream.Emit(ILOpcode.stfld, emitter.NewToken(_managedField)); var vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); // index = 0 codeStream.EmitLdc(0); codeStream.EmitStLoc(vIndex); codeStream.Emit(ILOpcode.br, lRangeCheck); codeStream.EmitLabel(lLoopHeader); // load managed type codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); codeStream.EmitLdLoc(vIndex); // load native type codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(_nativeField)); codeStream.EmitLdLoc(vIndex); codeStream.Emit(ILOpcode.call, emitter.NewToken( nativeArrayType.GetInlineArrayMethod(InlineArrayMethodKind.Getter))); // generate marshalling IL for the element GetElementMarshaller(MarshalDirection.Reverse) .EmitMarshallingIL(new PInvokeILCodeStreams(_ilCodeStreams.Emitter, codeStream)); codeStream.EmitStElem(managedElementType); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdc(1); codeStream.Emit(ILOpcode.add); codeStream.EmitStLoc(vIndex); codeStream.EmitLabel(lRangeCheck); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); codeStream.Emit(ILOpcode.blt, lLoopHeader); }