Пример #1
0
        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();
            }
        }
Пример #2
0
        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);
        }
Пример #3
0
        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();
        }
Пример #4
0
        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);
        }
Пример #5
0
        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));
        }
Пример #6
0
        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);
            }
        }
Пример #7
0
        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));
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }
Пример #10
0
        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));
            }
        }
Пример #11
0
 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);
     }
 }
Пример #12
0
        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());
        }
Пример #13
0
        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);
        }
Пример #14
0
        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);
        }
Пример #15
0
        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);
        }
Пример #16
0
        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);
        }
Пример #17
0
        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);
            }
        }
Пример #18
0
        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);
        }