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); }
public override void EmitStoreNativeToManaged(MarshalCodeContext context) { EmitConvertNativeToManaged(context); if (context.ManagedEmitters.Count == 0) context.ManagedEmitters.Peek().Emit(context.ILProcessor); }
public override void EmitStoreManagedToNative(MarshalCodeContext context) { EmitConvertManagedToNative(context); if (context.NativeEmitters.Count == 0) context.NativeEmitters.Peek().Emit(context.ILProcessor); }
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)); }
public override void EmitStoreNativeToManaged(MarshalCodeContext context) { EmitConvertNativeToManaged(context); if (context.ManagedEmitters.Count == 0) { context.ManagedEmitters.Peek().Emit(context.ILProcessor); } }
public override void EmitStoreManagedToNative(MarshalCodeContext context) { EmitConvertManagedToNative(context); if (context.NativeEmitters.Count == 0) { context.NativeEmitters.Peek().Emit(context.ILProcessor); } }
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); }
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); }
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); }
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); }
/// <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); } }
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); } }
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); }
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 TypeReference GetNativeType(MarshalCodeContext context) { return new PointerType(context.Assembly.MainModule.Import(typeof(char))); }
public override TypeReference GetNativeType(MarshalCodeContext context) { // TODO: Push native emitter? return new PointerType(elementMarshaller.GetNativeType(context)); }
/// <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); }
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(); }
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(); } }
/// <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); }
/// <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);
public override void EmitConvertManagedToNative(MarshalCodeContext context) { // Check if item is equal to 0 context.ManagedEmitters.Peek().Emit(context.ILProcessor); }
public override TypeReference GetNativeType(MarshalCodeContext context) { EnsureGenerateNativeType(context); return(nativeType); }
public override void EmitConvertNativeToManaged(MarshalCodeContext context) { // TODO: Implement! context.ILProcessor.Emit(OpCodes.Ldnull); }
/// <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);
public override TypeReference GetNativeType(MarshalCodeContext context) { return context.Assembly.MainModule.Import(typeof(IntPtr)); }
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); }
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); }
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); } }
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(); } }
/// <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; }
public override TypeReference GetNativeType(MarshalCodeContext context) { var elementType = ((ArrayType)context.ManagedEmitters.Peek().Type).ElementType; return(new PointerType(elementType)); }
public override void EmitConvertNativeToManaged(MarshalCodeContext context) { throw new NotImplementedException(); }
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)); }
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(); }
public override TypeReference GetNativeType(MarshalCodeContext context) { return(context.Assembly.MainModule.Import(typeof(IntPtr))); }
public override TypeReference GetNativeType(MarshalCodeContext context) { // TODO: Push native emitter? return(new PointerType(elementMarshaller.GetNativeType(context))); }