private static MethodDefinition GetDelegateWrapper(ModuleDefinition module, TypeReference multicastDelegateType) { // Find DelegateWrappers type in assembly var delegateWrappersType = module.GetType("DelegateWrappers"); if (delegateWrappersType == null) return null; // Find if any method match the requested type var multicastDelegateName = multicastDelegateType.MangledName(); return delegateWrappersType.Methods.FirstOrDefault(x => x.Name == multicastDelegateName); }
/// <summary> /// Internal helper to actually builds the type. /// </summary> /// <param name="typeReference">The type definition.</param> /// <returns></returns> private Type BuildType(TypeReference typeReference) { // Open type? if (typeReference.ContainsGenericParameter) return null; TypeRef valueType = TypeRef.Empty; TypeRef dataType; Type result; StackValueType stackType; var typeDefinition = GetMethodTypeDefinition(typeReference); switch (typeReference.MetadataType) { case MetadataType.Pointer: { var type = GetType(((PointerType)typeReference).ElementType, TypeState.Opaque); // In case we recursively created the type, just returns it if (types.TryGetValue(typeReference, out result)) return result; // Special case: void* if (LLVM.VoidTypeInContext(context) == type.DataTypeLLVM) dataType = intPtrLLVM; else dataType = LLVM.PointerType(type.DataTypeLLVM, 0); valueType = dataType; stackType = StackValueType.NativeInt; break; } case MetadataType.ByReference: { var type = GetType(((ByReferenceType)typeReference).ElementType, TypeState.Opaque); // In case we recursively created the type, just returns it if (types.TryGetValue(typeReference, out result)) return result; dataType = LLVM.PointerType(type.DefaultTypeLLVM, 0); valueType = dataType; stackType = StackValueType.Reference; break; } case MetadataType.RequiredModifier: // TODO: Add support for this feature return GetType(((RequiredModifierType)typeReference).ElementType, TypeState.Opaque); case MetadataType.Pinned: // TODO: Add support for this feature return GetType(((PinnedType)typeReference).ElementType, TypeState.Opaque); case MetadataType.Void: dataType = LLVM.VoidTypeInContext(context); stackType = StackValueType.Unknown; break; case MetadataType.Boolean: dataType = LLVM.Int8TypeInContext(context); stackType = StackValueType.Int32; break; case MetadataType.Single: dataType = LLVM.FloatTypeInContext(context); stackType = StackValueType.Float; break; case MetadataType.Double: dataType = LLVM.DoubleTypeInContext(context); stackType = StackValueType.Float; break; case MetadataType.Char: dataType = CharUsesUTF8 ? LLVM.Int8TypeInContext(context) : LLVM.Int16TypeInContext(context); stackType = StackValueType.Int32; break; case MetadataType.Byte: case MetadataType.SByte: dataType = LLVM.Int8TypeInContext(context); stackType = StackValueType.Int32; break; case MetadataType.Int16: case MetadataType.UInt16: dataType = LLVM.Int16TypeInContext(context); stackType = StackValueType.Int32; break; case MetadataType.Int32: case MetadataType.UInt32: dataType = int32LLVM; stackType = StackValueType.Int32; break; case MetadataType.Int64: case MetadataType.UInt64: dataType = int64LLVM; stackType = StackValueType.Int64; break; case MetadataType.UIntPtr: case MetadataType.IntPtr: dataType = intPtrLLVM; stackType = StackValueType.NativeInt; break; case MetadataType.Array: case MetadataType.String: case MetadataType.TypedByReference: case MetadataType.GenericInstance: case MetadataType.ValueType: case MetadataType.Class: case MetadataType.Object: { // Open type? if (typeDefinition.HasGenericParameters && !(typeReference is GenericInstanceType)) return null; // When resolved, void becomes a real type if (typeReference.FullName == typeof(void).FullName) { goto case MetadataType.Void; } if (typeDefinition.IsValueType && typeDefinition.IsEnum) { // Special case: enum // Uses underlying type var enumUnderlyingType = GetType(typeDefinition.GetEnumUnderlyingType(), TypeState.StackComplete); dataType = enumUnderlyingType.DataTypeLLVM; stackType = enumUnderlyingType.StackType; } else { stackType = typeDefinition.IsValueType ? StackValueType.Value : StackValueType.Object; dataType = GenerateDataType(typeReference); } valueType = dataType; break; } default: throw new NotImplementedException(); } // Create class version (boxed version with VTable) var boxedType = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".class"); if (valueType == TypeRef.Empty) valueType = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".value"); result = new Type(typeReference, typeDefinition, dataType, valueType, boxedType, stackType); types.Add(typeReference, result); // Enqueue class generation, if needed EmitType(result); return result; }
private TypeRef GenerateDataType(TypeReference typeReference) { TypeRef dataType; var typeDefinition = GetMethodTypeDefinition(typeReference); // Struct / Class // Auto layout or Sequential Layout with packing size 0 (auto) will result in normal LLVM struct (optimized for target) // Otherwise (Explicit layout or Sequential layout with custom packing), make a i8 array and access field with GEP in it. if (IsCustomLayout(typeDefinition)) { var classSize = ComputeClassSize(typeDefinition, typeReference); dataType = LLVM.ArrayType(LLVM.Int8TypeInContext(context), (uint)classSize); } else { dataType = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".data"); } return dataType; }
/// <summary> /// Internal helper to actually builds the type. /// </summary> /// <param name="typeReference">The type definition.</param> /// <returns></returns> private Type BuildType(TypeReference typeReference) { if (typeReference.ContainsGenericParameter()) return null; TypeRef dataType; StackValueType stackType; var valueType = TypeRef.Empty; switch (typeReference.MetadataType) { case MetadataType.Pointer: { var type = GetType(((PointerType)typeReference).ElementType); // Special case: void* if (LLVM.VoidTypeInContext(context) == type.DataType) dataType = intPtrType; else dataType = LLVM.PointerType(type.DataType, 0); stackType = StackValueType.NativeInt; break; } case MetadataType.ByReference: { var type = GetType(((ByReferenceType)typeReference).ElementType); dataType = LLVM.PointerType(type.DefaultType, 0); stackType = StackValueType.Reference; break; } case MetadataType.RequiredModifier: // TODO: Add support for this feature return GetType(((RequiredModifierType)typeReference).ElementType); case MetadataType.Void: dataType = LLVM.VoidTypeInContext(context); stackType = StackValueType.Unknown; break; case MetadataType.Boolean: dataType = LLVM.Int8TypeInContext(context); stackType = StackValueType.Int32; break; case MetadataType.Single: dataType = LLVM.FloatTypeInContext(context); stackType = StackValueType.Float; break; case MetadataType.Double: dataType = LLVM.DoubleTypeInContext(context); stackType = StackValueType.Float; break; case MetadataType.Char: dataType = CharUsesUTF8 ? LLVM.Int8TypeInContext(context) : LLVM.Int16TypeInContext(context); stackType = StackValueType.Int32; break; case MetadataType.Byte: case MetadataType.SByte: dataType = LLVM.Int8TypeInContext(context); stackType = StackValueType.Int32; break; case MetadataType.Int16: case MetadataType.UInt16: dataType = LLVM.Int16TypeInContext(context); stackType = StackValueType.Int32; break; case MetadataType.Int32: case MetadataType.UInt32: dataType = int32Type; stackType = StackValueType.Int32; break; case MetadataType.Int64: case MetadataType.UInt64: dataType = int64Type; stackType = StackValueType.Int64; break; case MetadataType.UIntPtr: case MetadataType.IntPtr: dataType = intPtrType; stackType = StackValueType.NativeInt; break; case MetadataType.Array: case MetadataType.String: case MetadataType.TypedByReference: case MetadataType.GenericInstance: case MetadataType.ValueType: case MetadataType.Class: case MetadataType.Object: { // When resolved, void becomes a real type if (typeReference.FullName == typeof(void).FullName) { goto case MetadataType.Void; } var typeDefinition = GetMethodTypeDefinition(typeReference); if (typeDefinition.IsValueType && typeDefinition.IsEnum) { // Special case: enum var enumUnderlyingType = GetType(typeDefinition.GetEnumUnderlyingType()); dataType = enumUnderlyingType.DataType; stackType = enumUnderlyingType.StackType; } else { dataType = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".data"); stackType = typeDefinition.IsValueType ? StackValueType.Value : StackValueType.Object; } valueType = dataType; break; } default: throw new NotImplementedException(); } // Create class version (boxed version with VTable) var boxedType = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".class"); if (valueType == TypeRef.Empty) valueType = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".value"); var result = new Type(typeReference, dataType, valueType, boxedType, stackType); bool isLocal = typeReference.Resolve().Module.Assembly == assembly; // Manually emit Array classes locally (until proper mscorlib + generic instantiation exists). isLocal |= typeReference.MetadataType == MetadataType.Array; if (isLocal) EmitType(result); return result; }
// TODO: This method is quite incomplete. It would be good to synchronize it with MarshalCodeGenerator.Process() (with Native/Managed swapped) public static MethodDefinition GetOrCreateGenerateDelegateWrapper(AssemblyDefinition currentAssembly, TypeReference multicastDelegateType) { var multicastDelegateTypeResolved = multicastDelegateType.Resolve(); // Try to find method in assembly where delegate is defined var delegateWrapper = GetDelegateWrapper(multicastDelegateTypeResolved.Module, multicastDelegateType); if (delegateWrapper != null) return delegateWrapper; // Try to find method in current assembly delegateWrapper = GetDelegateWrapper(currentAssembly.MainModule, multicastDelegateType); if (delegateWrapper != null) return delegateWrapper; // Not found, let's create it in current assembly // First, get or create DelegateWrappers static class var delegateWrappersType = currentAssembly.MainModule.GetType("DelegateWrappers"); if (delegateWrappersType == null) { delegateWrappersType = new TypeDefinition(string.Empty, "DelegateWrappers", TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract); currentAssembly.MainModule.Types.Add(delegateWrappersType); } var invokeMethod = multicastDelegateTypeResolved.Methods.First(x => x.Name == "Invoke"); //var returnMarshaller = FindMarshallerForType(context.SourceEmitters.Peek().Type, field.MarshalInfo); delegateWrapper = new MethodDefinition(multicastDelegateType.MangledName(), MethodAttributes.Static, currentAssembly.MainModule.Import(ResolveGenericsVisitor.Process(multicastDelegateType, invokeMethod.ReturnType))); // Determine calling convention var callingConvention = CallingConvention.Winapi; // Set default // If there is a UnmanagedFunctionPointerAttribute, get its value var unmanagedFunctionPointerAttribute = multicastDelegateTypeResolved.HasCustomAttributes ? multicastDelegateTypeResolved.CustomAttributes.FirstOrDefault(x => x.AttributeType.FullName == typeof(UnmanagedFunctionPointerAttribute).FullName) : null; if (unmanagedFunctionPointerAttribute != null) callingConvention = (CallingConvention)unmanagedFunctionPointerAttribute.ConstructorArguments[0].Value; // On Windows, Winapi (default) means StdCall; TODO: Other platforms if (callingConvention == CallingConvention.Winapi) callingConvention = CallingConvention.StdCall; delegateWrapper.CallingConvention = callingConvention.ToCecil(); foreach (var parameter in invokeMethod.Parameters) { delegateWrapper.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, currentAssembly.MainModule.Import(parameter.ParameterType))); } // Extract delegate from thunk table var corlib = currentAssembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly; var marshalHelper = corlib.MainModule.GetType("SharpLang.Marshalling.MarshalHelper"); var getDelegate = currentAssembly.MainModule.Import(marshalHelper.Methods.First(x => x.Name == "GetDelegate")); // Get delegate var ilProcessor = delegateWrapper.Body.GetILProcessor(); ilProcessor.Emit(OpCodes.Call, getDelegate); // TODO: Convert parameters foreach (var parameter in invokeMethod.Parameters) { ilProcessor.Emit(OpCodes.Ldarg, parameter); } // Delegate.Invoke ilProcessor.Emit(OpCodes.Call, currentAssembly.MainModule.Import(invokeMethod)); ilProcessor.Emit(OpCodes.Ret); delegateWrapper.Body.UpdateInstructionOffsets(); // TODO: Convert out parameters // Add MarshalFunctionAttribute var typeType = currentAssembly.MainModule.Import(typeof(System.Type)); var marshalFunctionAttribute = corlib.MainModule.GetType("SharpLang.Marshalling.MarshalFunctionAttribute"); var marshalFunctionAttributeCtor = currentAssembly.MainModule.Import(marshalFunctionAttribute.Methods.Single(x => x.IsConstructor)); delegateWrapper.CustomAttributes.Add(new CustomAttribute(marshalFunctionAttributeCtor) { ConstructorArguments = { new CustomAttributeArgument(typeType, multicastDelegateType) } }); delegateWrappersType.Methods.Add(delegateWrapper); return delegateWrapper; }