예제 #1
0
 public override void EmitConvertManagedToNative(MarshalCodeContext context)
 {
     // TODO: Currently unsupported
     // For now, output (void*)null
     context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
     context.ILProcessor.Emit(OpCodes.Conv_I);
 }
예제 #2
0
        public override void EmitStoreNativeToManaged(MarshalCodeContext context)
        {
            EmitConvertNativeToManaged(context);

            if (context.ManagedEmitters.Count == 0)
                context.ManagedEmitters.Peek().Emit(context.ILProcessor);
        }
예제 #3
0
        public override void EmitStoreManagedToNative(MarshalCodeContext context)
        {
            EmitConvertManagedToNative(context);

            if (context.NativeEmitters.Count == 0)
                context.NativeEmitters.Peek().Emit(context.ILProcessor);
        }
 public override void EmitConvertManagedToNative(MarshalCodeContext context)
 {
     // TODO: Currently unsupported
     // For now, output (void*)null
     context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
     context.ILProcessor.Emit(OpCodes.Conv_I);
 }
예제 #5
0
        public override void EmitConvertNativeToManaged(MarshalCodeContext context)
        {
            var corlib     = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;
            var @string    = corlib.MainModule.GetType(typeof(string).FullName);
            var stringCtor = @string.Methods.First(x => x.IsConstructor && x.Parameters.Count == 1 && x.Parameters[0].ParameterType.FullName == typeof(char *).FullName);

            context.NativeEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Newobj, context.Assembly.MainModule.Import(stringCtor));
        }
예제 #6
0
        public override void EmitStoreNativeToManaged(MarshalCodeContext context)
        {
            EmitConvertNativeToManaged(context);

            if (context.ManagedEmitters.Count == 0)
            {
                context.ManagedEmitters.Peek().Emit(context.ILProcessor);
            }
        }
예제 #7
0
        public override void EmitStoreManagedToNative(MarshalCodeContext context)
        {
            EmitConvertManagedToNative(context);

            if (context.NativeEmitters.Count == 0)
            {
                context.NativeEmitters.Peek().Emit(context.ILProcessor);
            }
        }
예제 #8
0
        public override void EmitConvertNativeToManaged(MarshalCodeContext context)
        {
            context.NativeEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
            context.ILProcessor.Emit(OpCodes.Ceq);

            // Compare comparison result with 0 (transform "equal to 0" into "inequal to 0")
            context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
            context.ILProcessor.Emit(OpCodes.Ceq);
        }
예제 #9
0
        public override void EmitConvertNativeToManaged(MarshalCodeContext context)
        {
            context.NativeEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
            context.ILProcessor.Emit(OpCodes.Ceq);

            // Compare comparison result with 0 (transform "equal to 0" into "inequal to 0")
            context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
            context.ILProcessor.Emit(OpCodes.Ceq);
        }
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            var elementType = ((ArrayType)context.ManagedEmitters.Peek().Type).ElementType;

            var pinnedArray = new VariableDefinition(new PinnedType(new ByReferenceType(elementType)));
            context.ILProcessor.Body.Variables.Add(pinnedArray);

            context.ManagedEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
            context.ILProcessor.Emit(OpCodes.Ldelema, elementType);
            context.ILProcessor.Emit(OpCodes.Stloc, pinnedArray);
            context.ILProcessor.Emit(OpCodes.Ldloc, pinnedArray);
        }
예제 #11
0
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            var elementType = ((ArrayType)context.ManagedEmitters.Peek().Type).ElementType;

            var pinnedArray = new VariableDefinition(new PinnedType(new ByReferenceType(elementType)));

            context.ILProcessor.Body.Variables.Add(pinnedArray);

            context.ManagedEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
            context.ILProcessor.Emit(OpCodes.Ldelema, elementType);
            context.ILProcessor.Emit(OpCodes.Stloc, pinnedArray);
            context.ILProcessor.Emit(OpCodes.Ldloc, pinnedArray);
        }
예제 #12
0
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            if (delegateWrapper == null)
                delegateWrapper = GetOrCreateGenerateDelegateWrapper(context.Assembly, context.ManagedEmitters.Peek().Type);

            var corlib = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;
            var marshalHelper = corlib.MainModule.GetType("SharpLang.Marshalling.MarshalHelper");
            var createThunk = context.Assembly.MainModule.Import(marshalHelper.Methods.First(x => x.Name == "CreateThunk"));

            // For now, output (void*)null
            context.ManagedEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Ldftn, delegateWrapper);
            context.ILProcessor.Emit(OpCodes.Call, createThunk);
        }
예제 #13
0
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            // Load argument as is
            context.ManagedEmitters.Peek().EmitAddress(context.ILProcessor);

            var corlib             = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;
            var handleRefClass     = corlib.MainModule.GetType(typeof(HandleRef).FullName);
            var handleRefGetHandle = context.Assembly.MainModule.Import(handleRefClass.Properties.First(x => x.Name == "Handle").GetMethod);

            // Extract its Handle property
            context.ILProcessor.Emit(OpCodes.Call, handleRefGetHandle);

            // TODO: After the call (cleanup), do a GC.KeepAlive(handleRef.Wrapper);
        }
예제 #14
0
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            if (delegateWrapper == null)
            {
                delegateWrapper = GetOrCreateGenerateDelegateWrapper(context.Assembly, context.ManagedEmitters.Peek().Type);
            }

            var corlib        = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;
            var marshalHelper = corlib.MainModule.GetType("SharpLang.Marshalling.MarshalHelper");
            var createThunk   = context.Assembly.MainModule.Import(marshalHelper.Methods.First(x => x.Name == "CreateThunk"));

            // For now, output (void*)null
            context.ManagedEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Ldftn, delegateWrapper);
            context.ILProcessor.Emit(OpCodes.Call, createThunk);
        }
예제 #15
0
        /// <summary>
        /// Converts from native to managed and if managed stack is not empty, stores result.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void EmitStoreNativeToManaged(MarshalCodeContext context)
        {
            bool hasManagedEmitter = (context.ManagedEmitters.Count > 0);

            if (hasManagedEmitter)
            {
                context.ManagedEmitters.Peek().StoreStart(context.ILProcessor);
            }

            EmitConvertNativeToManaged(context);

            if (hasManagedEmitter)
            {
                context.ManagedEmitters.Peek().StoreEnd(context.ILProcessor);
            }
        }
예제 #16
0
        public override void EmitConvertNativeToManaged(MarshalCodeContext context)
        {
            // Create marshalled type
            EnsureGenerateNativeType(context);

            if (true)
            {
                // Defer to method
                context.NativeEmitters.Peek().EmitAddress(context.ILProcessor);
                context.ManagedEmitters.Peek().EmitAddress(context.ILProcessor);
                context.ILProcessor.Emit(OpCodes.Call, nativeToManagedMethod);
            }
            else
            {
                // TODO: If we decide to inline later (could avoid some allocations)
                EmitStructConvertCore(context, false);
            }
        }
예제 #17
0
        public override void EmitConvertNativeToManaged(MarshalCodeContext context)
        {
            // Create marshalled type
            EnsureGenerateNativeType(context);

            if (true)
            {
                // Defer to method
                context.NativeEmitters.Peek().EmitAddress(context.ILProcessor);
                context.ManagedEmitters.Peek().EmitAddress(context.ILProcessor);
                context.ILProcessor.Emit(OpCodes.Call, nativeToManagedMethod);
            }
            else
            {
                // TODO: If we decide to inline later (could avoid some allocations)
                EmitStructConvertCore(context, false);
            }
        }
예제 #18
0
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            // uint loopCounter
            var uint32      = context.Assembly.MainModule.Import(typeof(uint));
            var loopCounter = new VariableDefinition(uint32);

            context.Method.Body.Variables.Add(loopCounter);

            // TODO: Handle null? Allocate array?
            var resultType = GetNativeType(context);

            result = new VariableDefinition(resultType);
            context.Method.Body.Variables.Add(result);

            // Block starts
            var loopCounterComparisonStart = context.ILProcessor.Create(OpCodes.Ldloc, loopCounter);
            var loopBodyStart = context.ILProcessor.Create(OpCodes.Nop);

            // loopCounter = 0;
            context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
            context.ILProcessor.Emit(OpCodes.Stloc, loopCounter);
            context.ILProcessor.Emit(OpCodes.Br, loopCounterComparisonStart);

            // loop body
            context.ILProcessor.Append(loopBodyStart);

            // loopCounter++;
            context.ILProcessor.Emit(OpCodes.Ldloc, loopCounter);
            context.ILProcessor.Emit(OpCodes.Ldc_I4_1);
            context.ILProcessor.Emit(OpCodes.Add);
            context.ILProcessor.Emit(OpCodes.Stloc, loopCounter);

            // loopCounter < array.Length
            context.ILProcessor.Append(loopCounterComparisonStart);
            context.ILProcessor.Emit(OpCodes.Conv_U);
            context.ManagedEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Ldlen);
            context.ILProcessor.Emit(OpCodes.Clt);
            context.ILProcessor.Emit(OpCodes.Brtrue, loopBodyStart);

            // Push result on the stack
            context.ILProcessor.Emit(OpCodes.Ldloc, result);
        }
예제 #19
0
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            // uint loopCounter
            var uint32 = context.Assembly.MainModule.Import(typeof(uint));
            var loopCounter = new VariableDefinition(uint32);
            context.Method.Body.Variables.Add(loopCounter);

            // TODO: Handle null? Allocate array?
            var resultType = GetNativeType(context);
            result = new VariableDefinition(resultType);
            context.Method.Body.Variables.Add(result);

            // Block starts
            var loopCounterComparisonStart = context.ILProcessor.Create(OpCodes.Ldloc, loopCounter);
            var loopBodyStart = context.ILProcessor.Create(OpCodes.Nop);

            // loopCounter = 0;
            context.ILProcessor.Emit(OpCodes.Ldc_I4_0);
            context.ILProcessor.Emit(OpCodes.Stloc, loopCounter);
            context.ILProcessor.Emit(OpCodes.Br, loopCounterComparisonStart);

            // loop body
            context.ILProcessor.Append(loopBodyStart);

            // loopCounter++;
            context.ILProcessor.Emit(OpCodes.Ldloc, loopCounter);
            context.ILProcessor.Emit(OpCodes.Ldc_I4_1);
            context.ILProcessor.Emit(OpCodes.Add);
            context.ILProcessor.Emit(OpCodes.Stloc, loopCounter);

            // loopCounter < array.Length
            context.ILProcessor.Append(loopCounterComparisonStart);
            context.ILProcessor.Emit(OpCodes.Conv_U);
            context.ManagedEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Ldlen);
            context.ILProcessor.Emit(OpCodes.Clt);
            context.ILProcessor.Emit(OpCodes.Brtrue, loopBodyStart);

            // Push result on the stack
            context.ILProcessor.Emit(OpCodes.Ldloc, result);
        }
예제 #20
0
        private void EmitStructConvertCore(MarshalCodeContext context, bool managedToNative)
        {
            foreach (var field in fields)
            {
                context.ManagedEmitters.Push(new FieldMarshalledObjectEmitter(field.Field));
                context.NativeEmitters.Push(new FieldMarshalledObjectEmitter(field.NativeField));

                // Marshall field
                if (managedToNative)
                {
                    field.Marshaller.EmitStoreManagedToNative(context);
                }
                else
                {
                    field.Marshaller.EmitStoreNativeToManaged(context);
                }

                context.NativeEmitters.Pop();
                context.ManagedEmitters.Pop();
            }
        }
예제 #21
0
 public override TypeReference GetNativeType(MarshalCodeContext context)
 {
     return new PointerType(context.Assembly.MainModule.Import(typeof(char)));
 }
예제 #22
0
 public override TypeReference GetNativeType(MarshalCodeContext context)
 {
     // TODO: Push native emitter?
     return new PointerType(elementMarshaller.GetNativeType(context));
 }
예제 #23
0
 /// <summary>
 /// Gets the native type.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <returns></returns>
 public virtual TypeReference GetNativeType(MarshalCodeContext context)
 {
     return(context.ManagedEmitters.Peek().Type);
 }
예제 #24
0
        public void Process(MethodDefinition methodDefinition)
        {
            var parameters = methodDefinition.Parameters.Select(CreateMarshalledParameter).ToArray();

            // If everything ended up being a BlittableMarshaller, that means we don't need to do any Marshalling
            if (parameters.All(x => x.Marshaller is BlittableMarshaller))
                return;

            var pinvokeMethod = new MethodDefinition(methodDefinition.Name, methodDefinition.Attributes, methodDefinition.ReturnType);

            // Move PInvokeInfo to underlying native method
            pinvokeMethod.PInvokeInfo = methodDefinition.PInvokeInfo;
            pinvokeMethod.ImplAttributes = methodDefinition.ImplAttributes;
            methodDefinition.PInvokeInfo = null;
            methodDefinition.IsPInvokeImpl = false;
            methodDefinition.ImplAttributes = MethodImplAttributes.IL;

            var context = new MarshalCodeContext(assemblyDefinition, methodDefinition, true);

            // Build method signature
            foreach (var parameter in parameters)
            {
                // Push context
                context.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(parameter.Parameter));
                if (parameter.IsByReference)
                    context.ManagedEmitters.Push(new ByReferenceMarshalledObjectEmitter());

                // Compute native type
                var nativeType = parameter.Marshaller.GetNativeType(context);
                if (parameter.IsByReference)
                    nativeType = new ByReferenceType(nativeType);

                // Add native parameter to pinvoke method
                parameter.NativeParameter = new ParameterDefinition(parameter.Parameter.Name, parameter.Parameter.Attributes, context.Assembly.MainModule.Import(nativeType));
                pinvokeMethod.Parameters.Add(parameter.NativeParameter);

                // Pop context
                if (parameter.IsByReference)
                    context.ManagedEmitters.Pop();
                context.ManagedEmitters.Pop();
            }

            // First, process marshallers which expect an empty stack (due to loop) and make sure they are stored in a local variable
            foreach (var parameter in parameters.Where(x => x.Marshaller.ContainsLoops || (!(x.Marshaller is BlittableMarshaller) && x.IsByReference)))
            {
                // Store in a local (if we didn't do that, we could end up having loops with things on the stack)
                var variableType = parameter.NativeParameterType;
                parameter.Variable = new VariableDefinition(variableType);
                methodDefinition.Body.Variables.Add(parameter.Variable);

                // Out-only parameter? Nothing to do...
                if (parameter.Parameter.IsOut && !parameter.Parameter.IsIn)
                    continue;

                // Push context
                context.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(parameter.Parameter));
                if (parameter.IsByReference)
                    context.ManagedEmitters.Push(new ByReferenceMarshalledObjectEmitter());
                context.NativeEmitters.Push(new VariableMarshalledObjectEmitter(parameter.Variable));

                // Convert parameter
                parameter.Marshaller.EmitStoreManagedToNative(context);

                // Pop context
                context.NativeEmitters.Pop();
                if (parameter.IsByReference)
                    context.ManagedEmitters.Pop();
                context.ManagedEmitters.Pop();
            }

            // Each marshaller is responsible for pushing one parameter to the stack
            foreach (var parameter in parameters)
            {
                if (parameter.Variable != null)
                {
                    // Already processed before and stored in a variable
                    context.ILProcessor.Emit(parameter.IsByReference ? OpCodes.Ldloca : OpCodes.Ldloc, parameter.Variable);
                }
                else
                {
                    // Just process and keep it on the stack
                    context.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(parameter.Parameter));
                    parameter.Marshaller.EmitStoreManagedToNative(context);
                    context.ManagedEmitters.Pop();
                }
            }

            // Emit call
            context.ILProcessor.Emit(OpCodes.Call, pinvokeMethod);

            VariableDefinition returnValue = null;
            Marshaller returnMarshaller = null;
            if (methodDefinition.ReturnType.MetadataType != MetadataType.Void)
            {
                returnMarshaller = Marshaller.FindMarshallerForType(methodDefinition.ReturnType, null);

                // Find native return type
                context.ManagedEmitters.Push(new FakeMarshalledObjectEmitter(methodDefinition.ReturnType));
                var nativeReturnType = returnMarshaller.GetNativeType(context);
                context.ManagedEmitters.Pop();

                // Change return type to native one
                pinvokeMethod.ReturnType = nativeReturnType;

                // Store return value in local variable
                returnValue = new VariableDefinition("returnValue", nativeReturnType);
                methodDefinition.Body.Variables.Add(returnValue);

                context.ILProcessor.Emit(OpCodes.Stloc, returnValue);
            }

            // Emit setup
            // TODO: Force Out parameter to have local variables? (source)
            foreach (var parameter in parameters)
            {
                if (parameter.Parameter.IsOut && parameter.Variable != null)
                {
                    context.NativeEmitters.Push(new VariableMarshalledObjectEmitter(parameter.Variable));
                    context.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(parameter.Parameter));
                    parameter.Marshaller.EmitStoreNativeToManaged(context);
                    context.ManagedEmitters.Pop();
                    context.NativeEmitters.Pop();
                }
            }

            // TODO: Cleanup

            // Emit return value
            if (returnValue != null)
            {
                // Convert return value to managed type
                context.NativeEmitters.Push(new VariableMarshalledObjectEmitter(returnValue));
                returnMarshaller.EmitStoreNativeToManaged(context);
                context.NativeEmitters.Pop();
            }
            context.ILProcessor.Emit(OpCodes.Ret);

            // Add method to type
            methodDefinition.DeclaringType.Methods.Add(pinvokeMethod);

            methodDefinition.Body.UpdateInstructionOffsets();
        }
예제 #25
0
        private void EnsureGenerateNativeType(MarshalCodeContext context)
        {
            // Already done?
            if (fields != null)
            {
                return;
            }

            var corlib   = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;
            var voidType = context.Assembly.MainModule.Import(typeof(void));

            fields = new List <StructField>();

            var marshalledTypeDefinition = marshalledType.Resolve();

            // Create native type, with same fields (but using native types)
            var typeAttributes = marshalledTypeDefinition.Attributes;

            typeAttributes &= ~TypeAttributes.NestedPublic;
            nativeType      = new TypeDefinition(marshalledType.Namespace, marshalledType.Name + "_Native", typeAttributes, marshalledTypeDefinition.BaseType);
            context.Assembly.MainModule.Types.Add(nativeType);

            // Add non-static fields
            foreach (var fieldDefinition in marshalledTypeDefinition.Fields)
            {
                if (fieldDefinition.IsStatic)
                {
                    continue;
                }

                var field = context.Assembly.MainModule.Import(fieldDefinition);

                var fieldType = ResolveGenericsVisitor.Process(marshalledType, field.FieldType);

                context.ManagedEmitters.Push(new FieldMarshalledObjectEmitter(field));

                var marshaller = FindMarshallerForType(fieldType, fieldDefinition.MarshalInfo);

                var nativeFieldType = context.Assembly.MainModule.Import(marshaller.GetNativeType(context));
                var nativeField     = new FieldDefinition(field.Name, fieldDefinition.Attributes, nativeFieldType);
                nativeType.Fields.Add(nativeField);

                fields.Add(new StructField(field, fieldType, nativeField, nativeFieldType, marshaller));

                context.ManagedEmitters.Pop();
            }

            for (int i = 0; i < 2; ++i)
            {
                // Create Managed to Unmanaged wrapper (and opposite)
                var method = new MethodDefinition(i == 0 ? "MarshalManagedToNative" : "MarshalNativeToManaged", MethodAttributes.Static | MethodAttributes.Public, voidType);

                // Add method to type
                nativeType.Methods.Add(method);
                if (i == 0)
                {
                    managedToNativeMethod = method;
                }
                else
                {
                    nativeToManagedMethod = method;
                }

                var managedParameter = new ParameterDefinition("managedObj", ParameterAttributes.None, context.Assembly.MainModule.Import(new ByReferenceType(marshalledType)));
                var nativeParameter  = new ParameterDefinition("nativeObj", ParameterAttributes.None, context.Assembly.MainModule.Import(new ByReferenceType(nativeType)));
                method.Parameters.Add(i == 0 ? managedParameter : nativeParameter);
                method.Parameters.Add(i == 0 ? nativeParameter : managedParameter);
                method.Parameters[1].Attributes |= ParameterAttributes.Out;

                var alternateContext = new MarshalCodeContext(context.Assembly, method, false);

                alternateContext.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(managedParameter));
                alternateContext.ManagedEmitters.Push(new ByReferenceMarshalledObjectEmitter());
                alternateContext.NativeEmitters.Push(new ParameterMarshalledObjectEmitter(nativeParameter));
                alternateContext.NativeEmitters.Push(new ByReferenceMarshalledObjectEmitter());

                EmitStructConvertCore(alternateContext, i == 0);

                alternateContext.ILProcessor.Emit(OpCodes.Ret);

                method.Body.UpdateInstructionOffsets();
            }
        }
예제 #26
0
        /// <summary>
        /// Converts from native to managed and if managed stack is not empty, stores result.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void EmitStoreNativeToManaged(MarshalCodeContext context)
        {
            bool hasManagedEmitter = (context.ManagedEmitters.Count > 0);
            if (hasManagedEmitter)
                context.ManagedEmitters.Peek().StoreStart(context.ILProcessor);

            EmitConvertNativeToManaged(context);

            if (hasManagedEmitter)
                context.ManagedEmitters.Peek().StoreEnd(context.ILProcessor);
        }
예제 #27
0
 /// <summary>
 /// Converts from managed to native and pushes result on the stack.
 /// </summary>
 /// <param name="context">The context.</param>
 public abstract void EmitConvertManagedToNative(MarshalCodeContext context);
예제 #28
0
 /// <summary>
 /// Converts from managed to native and pushes result on the stack.
 /// </summary>
 /// <param name="context">The context.</param>
 public abstract void EmitConvertManagedToNative(MarshalCodeContext context);
예제 #29
0
 public override void EmitConvertManagedToNative(MarshalCodeContext context)
 {
     // Check if item is equal to 0
     context.ManagedEmitters.Peek().Emit(context.ILProcessor);
 }
예제 #30
0
        public override TypeReference GetNativeType(MarshalCodeContext context)
        {
            EnsureGenerateNativeType(context);

            return(nativeType);
        }
예제 #31
0
 public override void EmitConvertManagedToNative(MarshalCodeContext context)
 {
     // Check if item is equal to 0
     context.ManagedEmitters.Peek().Emit(context.ILProcessor);
 }
예제 #32
0
 public override void EmitConvertNativeToManaged(MarshalCodeContext context)
 {
     // TODO: Implement!
     context.ILProcessor.Emit(OpCodes.Ldnull);
 }
예제 #33
0
 /// <summary>
 /// Converts from native to managed and pushes result on the stack.
 /// </summary>
 /// <param name="context">The context.</param>
 public abstract void EmitConvertNativeToManaged(MarshalCodeContext context);
예제 #34
0
 public override TypeReference GetNativeType(MarshalCodeContext context)
 {
     return context.Assembly.MainModule.Import(typeof(IntPtr));
 }
예제 #35
0
        private void EmitStructConvertCore(MarshalCodeContext context, bool managedToNative)
        {
            foreach (var field in fields)
            {
                context.ManagedEmitters.Push(new FieldMarshalledObjectEmitter(field.Field));
                context.NativeEmitters.Push(new FieldMarshalledObjectEmitter(field.NativeField));

                // Marshall field
                if (managedToNative)
                    field.Marshaller.EmitStoreManagedToNative(context);
                else
                    field.Marshaller.EmitStoreNativeToManaged(context);

                context.NativeEmitters.Pop();
                context.ManagedEmitters.Pop();
            }
        }
 public override void EmitConvertNativeToManaged(MarshalCodeContext context)
 {
     // TODO: Implement this
     context.ILProcessor.Emit(OpCodes.Ldnull);
 }
예제 #37
0
        public override TypeReference GetNativeType(MarshalCodeContext context)
        {
            EnsureGenerateNativeType(context);

            return nativeType;
        }
        public override TypeReference GetNativeType(MarshalCodeContext context)
        {
            var elementType = ((ArrayType)context.ManagedEmitters.Peek().Type).ElementType;

            return new PointerType(elementType);
        }
예제 #39
0
 /// <summary>
 /// Converts from native to managed and pushes result on the stack.
 /// </summary>
 /// <param name="context">The context.</param>
 public abstract void EmitConvertNativeToManaged(MarshalCodeContext context);
예제 #40
0
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            var corlib = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;

            // Note: we consider LPTStr (platform dependent) to be unicode (not valid on Win98/WinME, but well...)
            if (context.IsCleanupInlined && (nativeType == NativeType.LPTStr || nativeType == NativeType.LPWStr))
            {
                // fixed (char* c = str)
                var charPtr = new PointerType(context.Assembly.MainModule.Import(typeof(char)));
                var @string = context.Assembly.MainModule.Import(typeof(string));

                var runtimeHelpers = corlib.MainModule.GetType(typeof(RuntimeHelpers).FullName);

                var pinnedStringVariable = new VariableDefinition(new PinnedType(@string));
                var charPtrVariable      = new VariableDefinition(charPtr);

                context.Method.Body.Variables.Add(charPtrVariable);
                context.Method.Body.Variables.Add(pinnedStringVariable);

                // Pin string
                context.ManagedEmitters.Peek().Emit(context.ILProcessor);
                context.ILProcessor.Emit(OpCodes.Stloc, pinnedStringVariable);
                context.ILProcessor.Emit(OpCodes.Ldloc, pinnedStringVariable);

                // Load character start
                var storeCharPtrInst = Instruction.Create(OpCodes.Stloc, charPtrVariable);
                context.ILProcessor.Emit(OpCodes.Conv_I);
                context.ILProcessor.Emit(OpCodes.Dup);
                context.ILProcessor.Emit(OpCodes.Brfalse, storeCharPtrInst);
                context.ILProcessor.Emit(OpCodes.Call, context.Assembly.MainModule.Import(runtimeHelpers.Methods.First(x => x.Name == "get_OffsetToStringData")));
                context.ILProcessor.Emit(OpCodes.Add);

                // Optional: Store it in a variable (for easier debugging?)
                context.ILProcessor.Append(storeCharPtrInst);
                context.ILProcessor.Emit(OpCodes.Ldloc, charPtrVariable);
            }
            else
            {
                string stringToHGlobalName;
                switch (nativeType)
                {
                case NativeType.LPTStr:     // Let's ignore Win98/WinME
                case NativeType.LPWStr:
                    stringToHGlobalName = "StringToHGlobalUni";
                    break;

                case NativeType.LPStr:
                    stringToHGlobalName = "StringToHGlobalAnsi";
                    break;

                case NativeType.BStr:
                case NativeType.TBStr:
                case NativeType.ANSIBStr:
                    throw new NotImplementedException("BSTR is not supported in String Marshaller");

                default:
                    throw new ArgumentOutOfRangeException("nativeType");
                }

                // Call StringToHGlobalUni(str)
                var marshal         = corlib.MainModule.GetType(typeof(Marshal).FullName);
                var stringToHGlobal = context.Assembly.MainModule.Import(marshal.Methods.First(x => x.Name == stringToHGlobalName));

                context.ManagedEmitters.Peek().Emit(context.ILProcessor);
                context.ILProcessor.Emit(OpCodes.Call, stringToHGlobal);
            }
        }
예제 #41
0
        private void EnsureGenerateNativeType(MarshalCodeContext context)
        {
            // Already done?
            if (fields != null)
                return;

            var corlib = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;
            var voidType = context.Assembly.MainModule.Import(typeof(void));

            fields = new List<StructField>();

            var marshalledTypeDefinition = marshalledType.Resolve();

            // Create native type, with same fields (but using native types)
            var typeAttributes = marshalledTypeDefinition.Attributes;
            typeAttributes &= ~TypeAttributes.NestedPublic;
            nativeType = new TypeDefinition(marshalledType.Namespace, marshalledType.Name + "_Native", typeAttributes, marshalledTypeDefinition.BaseType);
            context.Assembly.MainModule.Types.Add(nativeType);

            // Add non-static fields
            foreach (var fieldDefinition in marshalledTypeDefinition.Fields)
            {
                if (fieldDefinition.IsStatic)
                    continue;

                var field = context.Assembly.MainModule.Import(fieldDefinition);

                var fieldType = ResolveGenericsVisitor.Process(marshalledType, field.FieldType);

                context.ManagedEmitters.Push(new FieldMarshalledObjectEmitter(field));

                var marshaller = FindMarshallerForType(fieldType, fieldDefinition.MarshalInfo);

                var nativeFieldType = context.Assembly.MainModule.Import(marshaller.GetNativeType(context));
                var nativeField = new FieldDefinition(field.Name, fieldDefinition.Attributes, nativeFieldType);
                nativeType.Fields.Add(nativeField);

                fields.Add(new StructField(field, fieldType, nativeField, nativeFieldType, marshaller));

                context.ManagedEmitters.Pop();
            }

            for (int i = 0; i < 2; ++i)
            {
                // Create Managed to Unmanaged wrapper (and opposite)
                var method = new MethodDefinition(i == 0 ? "MarshalManagedToNative" : "MarshalNativeToManaged", MethodAttributes.Static | MethodAttributes.Public, voidType);

                // Add method to type
                nativeType.Methods.Add(method);
                if (i == 0)
                    managedToNativeMethod = method;
                else
                    nativeToManagedMethod = method;

                var managedParameter = new ParameterDefinition("managedObj", ParameterAttributes.None, context.Assembly.MainModule.Import(new ByReferenceType(marshalledType)));
                var nativeParameter = new ParameterDefinition("nativeObj", ParameterAttributes.None, context.Assembly.MainModule.Import(new ByReferenceType(nativeType)));
                method.Parameters.Add(i == 0 ? managedParameter : nativeParameter);
                method.Parameters.Add(i == 0 ? nativeParameter : managedParameter);
                method.Parameters[1].Attributes |= ParameterAttributes.Out;

                var alternateContext = new MarshalCodeContext(context.Assembly, method, false);

                alternateContext.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(managedParameter));
                alternateContext.ManagedEmitters.Push(new ByReferenceMarshalledObjectEmitter());
                alternateContext.NativeEmitters.Push(new ParameterMarshalledObjectEmitter(nativeParameter));
                alternateContext.NativeEmitters.Push(new ByReferenceMarshalledObjectEmitter());

                EmitStructConvertCore(alternateContext, i == 0);

                alternateContext.ILProcessor.Emit(OpCodes.Ret);

                method.Body.UpdateInstructionOffsets();
            }
        }
예제 #42
0
 /// <summary>
 /// Gets the native type.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <returns></returns>
 public virtual TypeReference GetNativeType(MarshalCodeContext context)
 {
     return context.ManagedEmitters.Peek().Type;
 }
예제 #43
0
        public override TypeReference GetNativeType(MarshalCodeContext context)
        {
            var elementType = ((ArrayType)context.ManagedEmitters.Peek().Type).ElementType;

            return(new PointerType(elementType));
        }
예제 #44
0
        public override void EmitConvertManagedToNative(MarshalCodeContext context)
        {
            var corlib = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;

            // Note: we consider LPTStr (platform dependent) to be unicode (not valid on Win98/WinME, but well...)
            if (context.IsCleanupInlined && (nativeType == NativeType.LPTStr || nativeType == NativeType.LPWStr))
            {
                // fixed (char* c = str)
                var charPtr = new PointerType(context.Assembly.MainModule.Import(typeof(char)));
                var @string = context.Assembly.MainModule.Import(typeof(string));

                var runtimeHelpers = corlib.MainModule.GetType(typeof(RuntimeHelpers).FullName);

                var pinnedStringVariable = new VariableDefinition(new PinnedType(@string));
                var charPtrVariable = new VariableDefinition(charPtr);

                context.Method.Body.Variables.Add(charPtrVariable);
                context.Method.Body.Variables.Add(pinnedStringVariable);

                // Pin string
                context.ManagedEmitters.Peek().Emit(context.ILProcessor);
                context.ILProcessor.Emit(OpCodes.Stloc, pinnedStringVariable);
                context.ILProcessor.Emit(OpCodes.Ldloc, pinnedStringVariable);

                // Load character start
                var storeCharPtrInst = Instruction.Create(OpCodes.Stloc, charPtrVariable);
                context.ILProcessor.Emit(OpCodes.Conv_I);
                context.ILProcessor.Emit(OpCodes.Dup);
                context.ILProcessor.Emit(OpCodes.Brfalse, storeCharPtrInst);
                context.ILProcessor.Emit(OpCodes.Call, context.Assembly.MainModule.Import(runtimeHelpers.Methods.First(x => x.Name == "get_OffsetToStringData")));
                context.ILProcessor.Emit(OpCodes.Add);

                // Optional: Store it in a variable (for easier debugging?)
                context.ILProcessor.Append(storeCharPtrInst);
                context.ILProcessor.Emit(OpCodes.Ldloc, charPtrVariable);
            }
            else
            {
                string stringToHGlobalName;
                switch (nativeType)
                {
                    case NativeType.LPTStr: // Let's ignore Win98/WinME
                    case NativeType.LPWStr:
                        stringToHGlobalName = "StringToHGlobalUni";
                        break;
                    case NativeType.LPStr:
                        stringToHGlobalName = "StringToHGlobalAnsi";
                        break;
                    case NativeType.BStr:
                    case NativeType.TBStr:
                    case NativeType.ANSIBStr:
                        throw new NotImplementedException("BSTR is not supported in String Marshaller");
                    default:
                        throw new ArgumentOutOfRangeException("nativeType");
                }

                // Call StringToHGlobalUni(str)
                var marshal = corlib.MainModule.GetType(typeof(Marshal).FullName);
                var stringToHGlobal = context.Assembly.MainModule.Import(marshal.Methods.First(x => x.Name == stringToHGlobalName));

                context.ManagedEmitters.Peek().Emit(context.ILProcessor);
                context.ILProcessor.Emit(OpCodes.Call, stringToHGlobal);
            }
        }
예제 #45
0
 public override void EmitConvertNativeToManaged(MarshalCodeContext context)
 {
     throw new NotImplementedException();
 }
예제 #46
0
        public override void EmitConvertNativeToManaged(MarshalCodeContext context)
        {
            var corlib = context.Assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;
            var @string = corlib.MainModule.GetType(typeof(string).FullName);
            var stringCtor = @string.Methods.First(x => x.IsConstructor && x.Parameters.Count == 1 && x.Parameters[0].ParameterType.FullName == typeof(char*).FullName);

            context.NativeEmitters.Peek().Emit(context.ILProcessor);
            context.ILProcessor.Emit(OpCodes.Newobj, context.Assembly.MainModule.Import(stringCtor));
        }
예제 #47
0
 public override void EmitConvertNativeToManaged(MarshalCodeContext context)
 {
     throw new NotImplementedException();
 }
예제 #48
0
        public void Process(MethodDefinition methodDefinition)
        {
            var parameters = methodDefinition.Parameters.Select(CreateMarshalledParameter).ToArray();

            // If everything ended up being a BlittableMarshaller, that means we don't need to do any Marshalling
            if (parameters.All(x => x.Marshaller is BlittableMarshaller))
            {
                return;
            }

            var pinvokeMethod = new MethodDefinition(methodDefinition.Name, methodDefinition.Attributes, methodDefinition.ReturnType);

            // Move PInvokeInfo to underlying native method
            pinvokeMethod.PInvokeInfo       = methodDefinition.PInvokeInfo;
            pinvokeMethod.ImplAttributes    = methodDefinition.ImplAttributes;
            methodDefinition.PInvokeInfo    = null;
            methodDefinition.IsPInvokeImpl  = false;
            methodDefinition.ImplAttributes = MethodImplAttributes.IL;

            var context = new MarshalCodeContext(assemblyDefinition, methodDefinition, true);

            // Build method signature
            foreach (var parameter in parameters)
            {
                // Push context
                context.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(parameter.Parameter));
                if (parameter.IsByReference)
                {
                    context.ManagedEmitters.Push(new ByReferenceMarshalledObjectEmitter());
                }

                // Compute native type
                var nativeType = parameter.Marshaller.GetNativeType(context);
                if (parameter.IsByReference)
                {
                    nativeType = new ByReferenceType(nativeType);
                }

                // Add native parameter to pinvoke method
                parameter.NativeParameter = new ParameterDefinition(parameter.Parameter.Name, parameter.Parameter.Attributes, context.Assembly.MainModule.Import(nativeType));
                pinvokeMethod.Parameters.Add(parameter.NativeParameter);

                // Pop context
                if (parameter.IsByReference)
                {
                    context.ManagedEmitters.Pop();
                }
                context.ManagedEmitters.Pop();
            }

            // First, process marshallers which expect an empty stack (due to loop) and make sure they are stored in a local variable
            foreach (var parameter in parameters.Where(x => x.Marshaller.ContainsLoops || (!(x.Marshaller is BlittableMarshaller) && x.IsByReference)))
            {
                // Store in a local (if we didn't do that, we could end up having loops with things on the stack)
                var variableType = parameter.NativeParameterType;
                parameter.Variable = new VariableDefinition(variableType);
                methodDefinition.Body.Variables.Add(parameter.Variable);

                // Out-only parameter? Nothing to do...
                if (parameter.Parameter.IsOut && !parameter.Parameter.IsIn)
                {
                    continue;
                }

                // Push context
                context.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(parameter.Parameter));
                if (parameter.IsByReference)
                {
                    context.ManagedEmitters.Push(new ByReferenceMarshalledObjectEmitter());
                }
                context.NativeEmitters.Push(new VariableMarshalledObjectEmitter(parameter.Variable));

                // Convert parameter
                parameter.Marshaller.EmitStoreManagedToNative(context);

                // Pop context
                context.NativeEmitters.Pop();
                if (parameter.IsByReference)
                {
                    context.ManagedEmitters.Pop();
                }
                context.ManagedEmitters.Pop();
            }

            // Each marshaller is responsible for pushing one parameter to the stack
            foreach (var parameter in parameters)
            {
                if (parameter.Variable != null)
                {
                    // Already processed before and stored in a variable
                    context.ILProcessor.Emit(parameter.IsByReference ? OpCodes.Ldloca : OpCodes.Ldloc, parameter.Variable);
                }
                else
                {
                    // Just process and keep it on the stack
                    context.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(parameter.Parameter));
                    parameter.Marshaller.EmitStoreManagedToNative(context);
                    context.ManagedEmitters.Pop();
                }
            }

            // Emit call
            context.ILProcessor.Emit(OpCodes.Call, pinvokeMethod);

            VariableDefinition returnValue      = null;
            Marshaller         returnMarshaller = null;

            if (methodDefinition.ReturnType.MetadataType != MetadataType.Void)
            {
                returnMarshaller = Marshaller.FindMarshallerForType(methodDefinition.ReturnType, null);

                // Find native return type
                context.ManagedEmitters.Push(new FakeMarshalledObjectEmitter(methodDefinition.ReturnType));
                var nativeReturnType = returnMarshaller.GetNativeType(context);
                context.ManagedEmitters.Pop();

                // Change return type to native one
                pinvokeMethod.ReturnType = nativeReturnType;

                // Store return value in local variable
                returnValue = new VariableDefinition("returnValue", nativeReturnType);
                methodDefinition.Body.Variables.Add(returnValue);

                context.ILProcessor.Emit(OpCodes.Stloc, returnValue);
            }

            // Emit setup
            // TODO: Force Out parameter to have local variables? (source)
            foreach (var parameter in parameters)
            {
                if (parameter.Parameter.IsOut && parameter.Variable != null)
                {
                    context.NativeEmitters.Push(new VariableMarshalledObjectEmitter(parameter.Variable));
                    context.ManagedEmitters.Push(new ParameterMarshalledObjectEmitter(parameter.Parameter));
                    parameter.Marshaller.EmitStoreNativeToManaged(context);
                    context.ManagedEmitters.Pop();
                    context.NativeEmitters.Pop();
                }
            }

            // TODO: Cleanup

            // Emit return value
            if (returnValue != null)
            {
                // Convert return value to managed type
                context.NativeEmitters.Push(new VariableMarshalledObjectEmitter(returnValue));
                returnMarshaller.EmitStoreNativeToManaged(context);
                context.NativeEmitters.Pop();
            }
            context.ILProcessor.Emit(OpCodes.Ret);

            // Add method to type
            methodDefinition.DeclaringType.Methods.Add(pinvokeMethod);

            methodDefinition.Body.UpdateInstructionOffsets();
        }
예제 #49
0
 public override TypeReference GetNativeType(MarshalCodeContext context)
 {
     return(context.Assembly.MainModule.Import(typeof(IntPtr)));
 }
예제 #50
0
 public override TypeReference GetNativeType(MarshalCodeContext context)
 {
     // TODO: Push native emitter?
     return(new PointerType(elementMarshaller.GetNativeType(context)));
 }