/// <inheritdoc/>
        public override FlowGraph Apply(FlowGraph graph)
        {
            var builder = graph.ToBuilder();

            foreach (var insn in builder.NamedInstructions)
            {
                ValueTag           array;
                ClrFieldDefinition pseudoField;
                if (IsArrayInit(insn, out array, out pseudoField))
                {
                    array = ElideReinterpretCasts(array, builder.ToImmutable());
                    var   arrayType = TypeHelpers.UnboxIfPossible(graph.GetValueType(array));
                    IType elementType;
                    IReadOnlyList <Constant> data;
                    int rank;
                    if (ClrArrayType.TryGetArrayElementType(arrayType, out elementType) &&
                        ClrArrayType.TryGetArrayRank(arrayType, out rank) &&
                        rank == 1 &&
                        TryDecodePseudoFieldData(pseudoField, elementType, out data))
                    {
                        // Generate instructions to fill the array.
                        FillWith(array, data, elementType, insn);
                        // Neuter the old array init function.
                        insn.Instruction = Instruction.CreateConstant(DefaultConstant.Instance, insn.ResultType);
                    }
                }
            }
            return(builder.ToImmutable());
        }
Beispiel #2
0
        /// <summary>
        /// Takes a Flame type and converts it to a Cecil type reference.
        /// For this to work, <paramref name="type"/> cannot reference
        /// non-Cecil types.
        /// </summary>
        /// <param name="type">
        /// The type to convert to a type reference.
        /// </param>
        /// <returns>
        /// A type reference.
        /// </returns>
        public static Mono.Cecil.TypeReference ImportReference(
            this Mono.Cecil.ModuleDefinition module,
            IType type)
        {
            if (type is ClrTypeDefinition)
            {
                var typeRef = ((ClrTypeDefinition)type).Definition;
                // The module can be null for testing purposes.
                return(module == null ? typeRef : module.ImportReference(typeRef));
            }
            else if (type is ClrGenericParameter)
            {
                // There's no need to "import" generic parameters: they can only be
                // used in the same place where they are defined.
                return(((ClrGenericParameter)type).Definition);
            }
            else if (type is PointerType)
            {
                var pointerType = (PointerType)type;
                var elemType    = pointerType.ElementType;
                var elemTypeRef = module.ImportReference(elemType);
                if (pointerType.Kind == PointerKind.Reference)
                {
                    return(new Mono.Cecil.ByReferenceType(elemTypeRef));
                }
                else if (pointerType.Kind == PointerKind.Box)
                {
                    if (elemType.IsReferenceType())
                    {
                        var def = module.ImportReference(elemTypeRef);
                        return(module == null ? def : module.ImportReference(def));
                    }
                    else
                    {
                        return(module.ImportReference(module.TypeSystem.Object));
                    }
                }
                else
                {
                    return(new Mono.Cecil.PointerType(elemTypeRef));
                }
            }

            IType elementType;

            if (ClrArrayType.TryGetArrayElementType(type, out elementType))
            {
                // Handle arrays.
                int rank;
                ClrArrayType.TryGetArrayRank(type, out rank);
                return(new Mono.Cecil.ArrayType(module.ImportReference(elementType), rank));
            }
            else if (type is TypeSpecialization)
            {
                // Handle generics.
                var instance = new Mono.Cecil.GenericInstanceType(
                    module.ImportReference(
                        type.GetRecursiveGenericDeclaration()));

                foreach (var item in type.GetRecursiveGenericArguments())
                {
                    instance.GenericArguments.Add(module.ImportReference(item));
                }

                return(instance);
            }
            else
            {
                throw new NotSupportedException($"Cannot import ill-understood type '{type.FullName}'.");
            }
        }