Пример #1
0
        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);
        }
Пример #2
0
        /// <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;
        }
Пример #3
0
        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;
        }
Пример #4
0
        /// <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;
        }
Пример #5
0
        // 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;
        }