Пример #1
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));
        }
Пример #2
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();
            }
        }
Пример #3
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);
        }
Пример #4
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();
        }
Пример #5
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);
            }
        }
Пример #6
0
        protected override void TransformManagedToNative(ILCodeStream codeStream)
        {
            var lMarshaller = InitializeMarshallerVariable();

            var       customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler");
            ILEmitter emitter = _ilCodeStreams.Emitter;
            var       manageToNativeMethod = customMarshallerType.GetKnownMethod(
                "MarshalManagedToNative",
                new MethodSignature(MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.IntPtr), new[] { Context.GetWellKnownType(WellKnownType.Object) }));

            codeStream.EmitLdLoc(lMarshaller);
            LoadManagedValue(codeStream);
            codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(manageToNativeMethod));
            StoreNativeValue(codeStream);
            if (MarshalDirection == MarshalDirection.Forward)
            {
                if (In && Out)
                {
                    EmitCleanUpManagedData(codeStream);
                }

                EmitCleanUpNativeData(_ilCodeStreams.CleanupCodeStream);
            }
            else
            {
                EmitCleanUpManagedData(codeStream);
            }
        }
Пример #7
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);
        }
Пример #8
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));
        }
Пример #9
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);
        }
Пример #10
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);
        }
Пример #11
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);
        }
Пример #12
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));
            }
        }
Пример #13
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);
     }
 }
Пример #14
0
        protected override void TransformNativeToManaged(ILCodeStream codeStream)
        {
            var lMarshaller = InitializeMarshallerVariable();

            var       customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler");
            ILEmitter emitter = _ilCodeStreams.Emitter;
            var       marshalNativeToManagedMethod = customMarshallerType.GetKnownMethod(
                "MarshalNativeToManaged",
                new MethodSignature(MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.Object), new[] { Context.GetWellKnownType(WellKnownType.IntPtr) }));

            codeStream.EmitLdLoc(lMarshaller);
            LoadNativeValue(codeStream);
            codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(marshalNativeToManagedMethod));
            StoreManagedValue(codeStream);
        }
Пример #15
0
        protected void EmitCleanUpNativeData(ILCodeStream codeStream)
        {
            var lMarshaller = InitializeMarshallerVariable();

            var       customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler");
            ILEmitter emitter = _ilCodeStreams.Emitter;

            // Call CleanUpNativeData on cleanup code stream.
            var cleanupNativeDataMethod = customMarshallerType.GetKnownMethod(
                "CleanUpNativeData",
                new MethodSignature(MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.Void), new[] { Context.GetWellKnownType(WellKnownType.IntPtr) }));

            codeStream.EmitLdLoc(lMarshaller);
            LoadNativeValue(codeStream);
            codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(cleanupNativeDataMethod));
        }
Пример #16
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());
        }
Пример #17
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);
        }
Пример #18
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);
            }
        }
Пример #19
0
        /// <summary>
        /// Provides method bodies for intrinsics recognized by the compiler that
        /// are specialized per instantiation. It can return null if the intrinsic
        /// is not recognized.
        /// </summary>
        private MethodIL TryGetPerInstantiationIntrinsicMethodIL(MethodDesc method)
        {
            Debug.Assert(method.IsIntrinsic);

            MetadataType owningType = method.OwningType.GetTypeDefinition() as MetadataType;

            if (owningType == null)
            {
                return(null);
            }

            string methodName = method.Name;

            switch (owningType.Name)
            {
            case "Activator":
            {
                TypeSystemContext context = owningType.Context;
                if (methodName == "CreateInstance" && method.Signature.Length == 0 && method.HasInstantiation &&
                    method.Instantiation[0] is TypeDesc activatedType &&
                    activatedType != context.UniversalCanonType &&
                    activatedType.IsValueType &&
                    activatedType.GetParameterlessConstructor() == null)
                {
                    ILEmitter    emit       = new ILEmitter();
                    ILCodeStream codeStream = emit.NewCodeStream();

                    var t = emit.NewLocal(context.GetSignatureVariable(0, method: true));
                    codeStream.EmitLdLoca(t);
                    codeStream.Emit(ILOpcode.initobj, emit.NewToken(context.GetSignatureVariable(0, method: true)));
                    codeStream.EmitLdLoc(t);
                    codeStream.Emit(ILOpcode.ret);

                    return(new InstantiatedMethodIL(method, emit.Link(method.GetMethodDefinition())));
                }
            }
            break;

            case "RuntimeHelpers":
            {
                if (owningType.Namespace == "System.Runtime.CompilerServices")
                {
                    return(RuntimeHelpersIntrinsics.EmitIL(method));
                }
            }
            break;

            case "Comparer`1":
            {
                if (methodName == "Create" && owningType.Namespace == "System.Collections.Generic")
                {
                    return(ComparerIntrinsics.EmitComparerCreate(method));
                }
            }
            break;

            case "EqualityComparer`1":
            {
                if (methodName == "Create" && owningType.Namespace == "System.Collections.Generic")
                {
                    return(ComparerIntrinsics.EmitEqualityComparerCreate(method));
                }
            }
            break;

            case "ComparerHelpers":
            {
                if (owningType.Namespace != "Internal.IntrinsicSupport")
                {
                    return(null);
                }

                if (methodName == "EnumOnlyCompare")
                {
                    //calls CompareTo for underlyingType to avoid boxing

                    TypeDesc elementType = method.Instantiation[0];
                    if (!elementType.IsEnum)
                    {
                        return(null);
                    }

                    TypeDesc   underlyingType            = elementType.UnderlyingType;
                    TypeDesc   returnType                = method.Context.GetWellKnownType(WellKnownType.Int32);
                    MethodDesc underlyingCompareToMethod = underlyingType.GetKnownMethod("CompareTo",
                                                                                         new MethodSignature(
                                                                                             MethodSignatureFlags.None,
                                                                                             genericParameterCount: 0,
                                                                                             returnType: returnType,
                                                                                             parameters: new TypeDesc[] { underlyingType }));

                    ILEmitter emitter    = new ILEmitter();
                    var       codeStream = emitter.NewCodeStream();

                    codeStream.EmitLdArga(0);
                    codeStream.EmitLdArg(1);
                    codeStream.Emit(ILOpcode.call, emitter.NewToken(underlyingCompareToMethod));
                    codeStream.Emit(ILOpcode.ret);

                    return(emitter.Link(method));
                }
            }
            break;

            case "EqualityComparerHelpers":
            {
                if (owningType.Namespace != "Internal.IntrinsicSupport")
                {
                    return(null);
                }

                if (methodName == "EnumOnlyEquals")
                {
                    // EnumOnlyEquals would basically like to do this:
                    // static bool EnumOnlyEquals<T>(T x, T y) where T: struct => x == y;
                    // This is not legal though.
                    // We don't want to do this:
                    // static bool EnumOnlyEquals<T>(T x, T y) where T: struct => x.Equals(y);
                    // Because it would box y.
                    // So we resort to some per-instantiation magic.

                    TypeDesc elementType = method.Instantiation[0];
                    if (!elementType.IsEnum)
                    {
                        return(null);
                    }

                    ILOpcode convInstruction;
                    if (((DefType)elementType).InstanceFieldSize.AsInt <= 4)
                    {
                        convInstruction = ILOpcode.conv_i4;
                    }
                    else
                    {
                        Debug.Assert(((DefType)elementType).InstanceFieldSize.AsInt == 8);
                        convInstruction = ILOpcode.conv_i8;
                    }

                    return(new ILStubMethodIL(method, new byte[] {
                            (byte)ILOpcode.ldarg_0,
                            (byte)convInstruction,
                            (byte)ILOpcode.ldarg_1,
                            (byte)convInstruction,
                            (byte)ILOpcode.prefix1, unchecked ((byte)ILOpcode.ceq),
                            (byte)ILOpcode.ret,
                        },
                                              Array.Empty <LocalVariableDefinition>(), null));
                }
                else if (methodName == "GetComparerForReferenceTypesOnly")
                {
                    TypeDesc elementType = method.Instantiation[0];
                    if (!elementType.IsRuntimeDeterminedSubtype &&
                        !elementType.IsCanonicalSubtype(CanonicalFormKind.Any) &&
                        !elementType.IsGCPointer)
                    {
                        return(new ILStubMethodIL(method, new byte[] {
                                (byte)ILOpcode.ldnull,
                                (byte)ILOpcode.ret
                            },
                                                  Array.Empty <LocalVariableDefinition>(), null));
                    }
                }
                else if (methodName == "StructOnlyEquals")
                {
                    TypeDesc elementType = method.Instantiation[0];
                    if (!elementType.IsRuntimeDeterminedSubtype &&
                        !elementType.IsCanonicalSubtype(CanonicalFormKind.Any) &&
                        !elementType.IsGCPointer)
                    {
                        Debug.Assert(elementType.IsValueType);

                        TypeSystemContext context    = elementType.Context;
                        MetadataType      helperType = context.SystemModule.GetKnownType("Internal.IntrinsicSupport", "EqualityComparerHelpers");

                        MethodDesc methodToCall;
                        if (elementType.IsEnum)
                        {
                            methodToCall = helperType.GetKnownMethod("EnumOnlyEquals", null).MakeInstantiatedMethod(elementType);
                        }
                        else if (elementType.IsNullable && ComparerIntrinsics.ImplementsIEquatable(elementType.Instantiation[0]))
                        {
                            methodToCall = helperType.GetKnownMethod("StructOnlyEqualsNullable", null).MakeInstantiatedMethod(elementType.Instantiation[0]);
                        }
                        else if (ComparerIntrinsics.ImplementsIEquatable(elementType))
                        {
                            methodToCall = helperType.GetKnownMethod("StructOnlyEqualsIEquatable", null).MakeInstantiatedMethod(elementType);
                        }
                        else
                        {
                            methodToCall = helperType.GetKnownMethod("StructOnlyNormalEquals", null).MakeInstantiatedMethod(elementType);
                        }

                        return(new ILStubMethodIL(method, new byte[]
                            {
                                (byte)ILOpcode.ldarg_0,
                                (byte)ILOpcode.ldarg_1,
                                (byte)ILOpcode.call, 1, 0, 0, 0,
                                (byte)ILOpcode.ret
                            },
                                                  Array.Empty <LocalVariableDefinition>(), new object[] { methodToCall }));
                    }
                }
            }
            break;
            }

            return(null);
        }
Пример #20
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);
        }
Пример #21
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);
        }