Пример #1
0
        /// <summary>
        /// Create the body of the values() method.
        /// </summary>
        private AstBlock CreateValuesBody(XFieldDefinition enumInfoField, XTypeSystem typeSystem)
        {
            var internalEnumInfoType = Compiler.GetDot42InternalType("EnumInfo");
            var valuesMethod         = new XMethodReference.Simple("Values", true, typeSystem.Object, internalEnumInfoType);

            var ast = AstBlock.CreateOptimizedForTarget(
                new AstExpression(AstNode.NoSource, AstCode.Ret, null,
                                  new AstExpression(AstNode.NoSource, AstCode.SimpleCastclass, new XArrayType(XType),
                                                    new AstExpression(AstNode.NoSource, AstCode.Call, valuesMethod,
                                                                      new AstExpression(AstNode.NoSource, AstCode.Ldsfld, enumInfoField)))));

            return(ast);
        }
Пример #2
0
        /// <summary>
        /// Implement the class now that all classes have been created
        /// </summary>
        protected override void CreateMembers(DexTargetPackage targetPackage)
        {
            base.CreateMembers(targetPackage);

            // Build default ctor
            XTypeSystem typeSystem          = Compiler.Module.TypeSystem;
            XSyntheticMethodDefinition ctor = XSyntheticMethodDefinition.Create(XType, XSyntheticMethodFlags.Constructor, "<init>", null, typeSystem.Void);

            ctor.Body = CreateCtorBody();
            Class.Methods.Add(ctor.GetDexMethod(Class, targetPackage));

            // Build Invoke method.
            XMethodDefinition sourceMethod = XType.Methods.Single(x => x.EqualsName("Invoke"));
            Prototype         prototype    = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, Class, sourceMethod);
            MethodDefinition  method       = new MethodDefinition(Class, sourceMethod.Name, prototype)
            {
                AccessFlags = AccessFlags.Public | AccessFlags.Abstract,
                MapFileId   = Compiler.GetNextMapFileId()
            };

            Class.Methods.Add(method);

            // Find xSource method
            targetPackage.NameConverter.Record(sourceMethod, method);

            // If void() delegate, implement java.lang.Runnable
            if (sourceMethod.ReturnType.IsVoid() && (sourceMethod.Parameters.Count == 0))
            {
                // Implement interface
                Class.Interfaces.Add(FrameworkReferences.Runnable);

                // Build run method
                var run = new MethodDefinition(Class, "run", new Prototype(PrimitiveType.Void))
                {
                    AccessFlags = AccessFlags.Public | AccessFlags.Final
                };
                Class.Methods.Add(run);
                run.Body = new DexLib.Instructions.MethodBody(run, 1)
                {
                    IncomingArguments = 1, OutgoingArguments = 1
                };
                var insList = run.Body.Instructions;
                var rThis   = run.Body.Registers[0];
                insList.Add(new DexLib.Instructions.Instruction(OpCodes.Invoke_virtual, method, rThis));
                insList.Add(new DexLib.Instructions.Instruction(OpCodes.Return_void));
            }
        }
Пример #3
0
        public SimpleControlFlow(DecompilerContext context, AstBlock method)
        {
            this.context    = context;
            this.typeSystem = context.CurrentModule.TypeSystem;

            foreach (AstLabel target in method.GetSelfAndChildrenRecursive <AstExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()))
            {
                labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1;
            }
            foreach (AstBasicBlock bb in method.GetSelfAndChildrenRecursive <AstBasicBlock>())
            {
                foreach (AstLabel label in bb.GetChildren().OfType <AstLabel>())
                {
                    labelToBasicBlock[label] = bb;
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Create the body of the class ctor.
        /// </summary>
        private AstBlock CreateClassCtorBody(bool isWide, XFieldDefinition enumInfoField, XFieldDefinition defaultField, XMethodReference enumInfoCtor, XTypeReference valueType, XTypeSystem typeSystem)
        {
            var internalEnumType     = Compiler.GetDot42InternalType("Enum");
            var internalEnumInfoType = Compiler.GetDot42InternalType("EnumInfo");
            var valueToFieldMap      = new Dictionary <object, XFieldDefinition>();
            var ldc = isWide ? AstCode.Ldc_I8 : AstCode.Ldc_I4;

            var ast = AstBlock.CreateOptimizedForTarget(
                // Instantiate enum info field
                new AstExpression(AstNode.NoSource, AstCode.Stsfld, enumInfoField,
                                  new AstExpression(AstNode.NoSource, AstCode.Newobj, enumInfoCtor)));

            // Instantiate values for each field
            var ordinal = 0;

            foreach (var field in XType.Fields.Where(x => x.IsStatic && !(x is XSyntheticFieldDefinition)))
            {
                // Find dex field
                object value;
                if (!field.TryGetEnumValue(out value))
                {
                    throw new CompilerException(string.Format("Cannot get enum value from field {0}", field.FullName));
                }
                value = isWide ? (object)XConvert.ToLong(value) : (object)XConvert.ToInt(value);
                XFieldDefinition existingField;
                AstExpression    valueExpr;
                if (valueToFieldMap.TryGetValue(value, out existingField))
                {
                    // Re-use instance of existing field
                    valueExpr = new AstExpression(AstNode.NoSource, AstCode.Ldsfld, existingField);
                }
                else
                {
                    // Record
                    valueToFieldMap[value] = field;

                    // Call ctor
                    valueExpr = new AstExpression(AstNode.NoSource, AstCode.Newobj, ctor,
                                                  new AstExpression(AstNode.NoSource, AstCode.Ldstr, field.Name),
                                                  new AstExpression(AstNode.NoSource, AstCode.Ldc_I4, ordinal),
                                                  new AstExpression(AstNode.NoSource, ldc, value));
                }

                // Initialize static field
                ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Stsfld, field, valueExpr));

                // Add to info
                var addMethod = new XMethodReference.Simple("Add", true, typeSystem.Void, internalEnumInfoType,
                                                            XParameter.Create("value", valueType),
                                                            XParameter.Create("instance", internalEnumType));
                ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Call, addMethod,
                                               new AstExpression(AstNode.NoSource, AstCode.Ldsfld, enumInfoField),
                                               new AstExpression(AstNode.NoSource, ldc, value),
                                               new AstExpression(AstNode.NoSource, AstCode.Ldsfld, field)));

                // Increment ordinal
                ordinal++;
            }

            // Initialize default field
            var getValueMethod = new XMethodReference.Simple("GetValue", true, internalEnumType, internalEnumInfoType,
                                                             XParameter.Create("value", valueType));

            ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Stsfld, defaultField,
                                           new AstExpression(AstNode.NoSource, AstCode.SimpleCastclass, XType,
                                                             new AstExpression(AstNode.NoSource, AstCode.Call, getValueMethod,
                                                                               new AstExpression(AstNode.NoSource, AstCode.Ldsfld, enumInfoField),
                                                                               new AstExpression(AstNode.NoSource, ldc, 0)))));

            // Return
            ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Ret, null));
            return(ast);
        }
Пример #5
0
        /// <summary>
        /// Convert node with code Cast.
        /// </summary>
        private static void ConvertCastclass(AssemblyCompiler compiler, AstExpression node, XTypeSystem typeSystem)
        {
            var type = (XTypeReference)node.Operand;

            if (type.IsSystemArray())
            {
                // Call cast method
                var arrayHelper     = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var castToArray     = arrayHelper.Methods.First(x => x.Name == "CastToArray");
                var castToArrayExpr = new AstExpression(node.SourceLocation, AstCode.Call, castToArray, node.Arguments).SetType(type);
                node.CopyFrom(castToArrayExpr);
                return;
            }

            string castMethod = null;

            if (type.IsSystemCollectionsIEnumerable())
            {
                castMethod = "CastToEnumerable";
            }
            else if (type.IsSystemCollectionsICollection())
            {
                castMethod = "CastToCollection";
            }
            else if (type.IsSystemCollectionsIList())
            {
                castMethod = "CastToList";
            }
            else if (type.IsSystemIFormattable())
            {
                castMethod = "CastToFormattable";
            }

            if (castMethod != null)
            {
                // Call cast method
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var castToArray = arrayHelper.Methods.First(x => x.Name == castMethod);

                // Call "(x instanceof T) ? (T)x : asMethod(x)"

                // "instanceof x"
                var instanceofExpr = new AstExpression(node.SourceLocation, AstCode.SimpleInstanceOf, type, node.Arguments[0]).SetType(typeSystem.Bool);

                // CastX(x)
                var castXExpr = new AstExpression(node.SourceLocation, AstCode.Call, castToArray, node.Arguments[0]).SetType(typeSystem.Object);

                // T(x)
                var txExpr = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, type, node.Arguments[0]).SetType(type);

                // Combine
                var conditional = new AstExpression(node.SourceLocation, AstCode.Conditional, type, instanceofExpr, txExpr, castXExpr).SetType(type);

                node.CopyFrom(conditional);
                return;
            }

            // Normal castclass
            node.Code = AstCode.SimpleCastclass;
        }
Пример #6
0
        /// <summary>
        /// Create the body of the valueOf(string) method.
        /// </summary>
        private AstBlock CreateValueOfBody(XSyntheticMethodDefinition method, XFieldDefinition enumInfoField, XTypeSystem typeSystem)
        {
            var internalEnumType     = Compiler.GetDot42InternalType("Enum");
            var internalEnumInfoType = Compiler.GetDot42InternalType("EnumInfo");
            var parseMethod          = new XMethodReference.Simple("Parse", true, internalEnumType, internalEnumInfoType,
                                                                   XParameter.Create("value", typeSystem.String),
                                                                   XParameter.Create("ignoreCase", typeSystem.Bool),
                                                                   XParameter.Create("throwIfNotFound", typeSystem.Bool));

            var ast = AstBlock.CreateOptimizedForTarget(
                new AstExpression(AstNode.NoSource, AstCode.Ret, null,
                                  new AstExpression(AstNode.NoSource, AstCode.SimpleCastclass, XType,
                                                    new AstExpression(AstNode.NoSource, AstCode.Call, parseMethod,
                                                                      new AstExpression(AstNode.NoSource, AstCode.Ldsfld, enumInfoField),
                                                                      new AstExpression(AstNode.NoSource, AstCode.Ldloc, method.AstParameters[0]),
                                                                      new AstExpression(AstNode.NoSource, AstCode.Ldc_I4, 0),
                                                                      new AstExpression(AstNode.NoSource, AstCode.Ldc_I4, 1)))));

            return(ast);
        }
        /// <summary>
        /// Load the GenericInstance of the current generic method.
        /// The result is a register that cannot be destroyed.
        /// </summary>
        private static AstExpression LoadMethodGenericArgument(ISourceLocation seqp, XTypeSystem typeSystem, XMethodDefinition method, int index)
        {
            bool loadFromArray = method.GenericParameters.Count > InternalConstants.GenericMethodParametersAsArrayThreshold;

            return(LoadGenericArgument(seqp, typeSystem, AstCode.LdGenericInstanceMethodArgument, index, loadFromArray));
        }
        /// <summary>
        /// Expand the loadExpression, so that primitive types are converted to their boxed counterparts,
        /// and marker types are converted to their underlying types.
        /// </summary>
        private static AstExpression EnsureGenericRuntimeType(AstExpression loadExpr, XTypeSystem typeSystem, XTypeDefinition typeHelper)
        {
            var ensureMethod = typeHelper.Methods.Single(x => x.Name == "EnsureGenericRuntimeType");

            return(new AstExpression(loadExpr.SourceLocation, AstCode.Call, ensureMethod, loadExpr)
                   .SetType(typeSystem.Type));
        }
Пример #9
0
        private static void ConvertUnboxStruct(AstExpression node, XTypeReference resultType, XTypeSystem typeSystem)
        {
            // Structs must never be null. We have to handle structs here, since a newobj
            // might need generic arguments. These would be difficult to provide at "UnboxFromGeneric",
            // but will be automatically filled in by the GenericInstanceConverter

            // convert to (temp$ = (T)x) != null ? temp$ : default(T)

            // replace any unbox, but keep if otherwise.
            var clone = node.Code == AstCode.Unbox ? new AstExpression(node.Arguments[0]) : new AstExpression(node);

            // make sure we don't evaluate the expression twice.
            var tempVar = new AstGeneratedVariable("temp$", "")
            {
                Type = typeSystem.Object
            };

            // T(x)
            var txExpr = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, resultType, clone)
                         .SetType(resultType);

            // temporary storage
            var storeTempVar = new AstExpression(node.SourceLocation, AstCode.Stloc, tempVar, txExpr)
            {
                ExpectedType = resultType
            };
            var loadTempVar = new AstExpression(node.SourceLocation, AstCode.Ldloc, tempVar)
                              .SetType(resultType);

            // default (T)
            var defaultT    = new AstExpression(node.SourceLocation, AstCode.DefaultValue, resultType).SetType(resultType);
            var constructor = StructCallConverter.GetDefaultValueCtor(resultType.Resolve());

            StructCallConverter.ConvertDefaultValue(defaultT, constructor);

            // Combine
            var conditional = new AstExpression(node.SourceLocation, AstCode.Conditional, resultType,
                                                storeTempVar, loadTempVar, defaultT)
                              .SetType(resultType);

            node.CopyFrom(conditional);
        }
Пример #10
0
        /// <summary>
        /// Convert node with code Callvirt.
        ///
        /// For arrays: intercepts call to IEnumerable.IEnumerable_GetEnumerator generated
        /// by foreach statements and swaps them out to System.Array.GetEnumerator.
        ///
        /// This call will then at a later compilation stage be replaced with the final destination.
        /// </summary>
        private static void ConvertCallvirtIEnumerable(AssemblyCompiler compiler, AstExpression node, XTypeSystem typeSystem)
        {
            var targetMethodRef      = ((XMethodReference)node.Operand);
            var targetMethodDefOrRef = targetMethodRef;

            if (targetMethodDefOrRef.DeclaringType.IsSystemCollectionsIEnumerable() &&
                targetMethodDefOrRef.Name == "IEnumerable_GetEnumerator" &&
                node.Arguments.Count == 1)
            {
                var argument = node.Arguments[0];
                if (!argument.InferredType.IsArray)
                {
                    return;
                }

                // swap the call to System.Array
                var systemArray   = compiler.GetDot42InternalType("System", "Array").Resolve();
                var getEnumerator = systemArray.Methods.First(x => x.Name == "GetEnumerator" && !x.IsStatic && x.Parameters.Count == 0);
                node.Operand = getEnumerator;
            }
            else if (targetMethodDefOrRef.DeclaringType.IsSystemCollectionsIEnumerableT() &&
                     targetMethodDefOrRef.Name.EndsWith("_GetEnumerator") &&
                     node.Arguments.Count == 1)
            {
                var argument = node.Arguments[0];
                if (!argument.InferredType.IsArray)
                {
                    return;
                }

                var elementType = argument.InferredType.ElementType;

                // Use As...Enumerable to convert
                var asEnumerableName   = FrameworkReferences.GetAsEnumerableTMethodName(elementType);
                var compilerHelper     = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var asEnumerableMethod = compilerHelper.Methods.First(x => x.Name == asEnumerableName);

                var call = new AstExpression(node.SourceLocation, AstCode.Call, asEnumerableMethod, argument)
                {
                    InferredType = asEnumerableMethod.ReturnType
                };
                node.Arguments[0] = call;

                argument.ExpectedType = argument.InferredType;
            }
        }
Пример #11
0
        /// <summary>
        /// Convert node with code IsInst.
        /// </summary>
        private static void ConvertIsInst(AssemblyCompiler compiler, AstExpression node, XTypeSystem typeSystem)
        {
            var type = (XTypeReference)node.Operand;

            if (type.IsSystemArray())
            {
                // Call ArrayHelper.AsArray
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var asArray     = arrayHelper.Methods.First(x => x.Name == "AsArray");
                var asArrayExpr = new AstExpression(node.SourceLocation, AstCode.Call, asArray, node.Arguments).SetType(typeSystem.Bool);
                node.CopyFrom(asArrayExpr);
                return;
            }

            string asMethod = GetCollectionConvertMethodName(type);

            if (asMethod != null)
            {
                asMethod = "As" + asMethod;
            }
            else if (type.IsSystemIFormattable())
            {
                asMethod = "AsFormattable";
            }

            // make sure we don't evaluate the expression twice.
            var tempVar = new AstGeneratedVariable("temp$$", null)
            {
                Type = compiler.Module.TypeSystem.Object
            };
            var storeTempVar = new AstExpression(node.SourceLocation, AstCode.Stloc, tempVar, node.Arguments[0])
            {
                ExpectedType = compiler.Module.TypeSystem.Object
            };
            var loadTempVar = new AstExpression(node.SourceLocation, AstCode.Ldloc, tempVar).SetType(compiler.Module.TypeSystem.Object);


            if (asMethod != null)
            {
                // Call "(x instanceof T) ? (T)x : asMethod(x)"
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var asArray     = arrayHelper.Methods.First(x => x.Name == asMethod);

                // "instanceof x"
                var instanceofExpr = new AstExpression(node.SourceLocation, AstCode.SimpleInstanceOf, type, storeTempVar).SetType(typeSystem.Bool);

                // AsX(x)
                var asXExpr = new AstExpression(node.SourceLocation, AstCode.Call, asArray, loadTempVar).SetType(typeSystem.Object);

                // T(x)
                var txExpr = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, type, loadTempVar).SetType(type);

                // Combine
                var conditional = new AstExpression(node.SourceLocation, AstCode.Conditional, type, instanceofExpr, txExpr, asXExpr).SetType(type);

                node.CopyFrom(conditional);
                return;
            }

            // Normal "as": Convert to (x instanceof T) ? (T)x : null
            if (!type.IsPrimitive)
            {
                // "instanceof x"
                var instanceofExpr = new AstExpression(node.SourceLocation, AstCode.SimpleInstanceOf, type, storeTempVar).SetType(typeSystem.Bool);

                // T(x)
                var txExpr = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, type, loadTempVar).SetType(type);

                // null
                var nullExpr = new AstExpression(node.SourceLocation, AstCode.Ldnull, null).SetType(typeSystem.Object);

                // Combine
                var conditional = new AstExpression(node.SourceLocation, AstCode.Conditional, type, instanceofExpr, txExpr, nullExpr).SetType(type);

                node.CopyFrom(conditional);
                return;
            }
            else
            {
                // treat as "x is T"
                if (!node.ExpectedType.IsBoolean())
                {
                    throw new NotImplementedException(); // can this happen?
                }
                node.Code = AstCode.SimpleInstanceOf;
            }
        }
Пример #12
0
 /// <summary>
 /// Load the GenericInstance of the current static method.
 /// The result is a register that cannot be destroyed.
 /// </summary>
 private static AstExpression LoadStaticClassGenericInstance(ISourceLocation seqp, XTypeSystem typeSystem)
 {
     return(new AstExpression(seqp, AstCode.LdGenericInstanceTypeArgument, null)
     {
         ExpectedType = new XArrayType(typeSystem.Type)
     });
 }
Пример #13
0
        /// <summary>
        /// Create an expression that loads the given type at runtime.
        /// </summary>
        private static AstExpression LoadTypeForGenericInstance(ISourceLocation seqp, MethodSource currentMethod, XTypeReference type, XTypeDefinition typeHelperType, XTypeSystem typeSystem, bool boxPrimitiveTypes = true)
        {
            if (type.IsArray)
            {
                // Array type
                var arrayType = (XArrayType)type;
                // Load element type
                var prefix = LoadTypeForGenericInstance(seqp, currentMethod, ((XArrayType)type).ElementType, typeHelperType, typeSystem, boxPrimitiveTypes);
                // Convert to array type
                if (arrayType.Dimensions.Count() == 1)
                {
                    var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 1));
                    return(new AstExpression(seqp, AstCode.Call, giCreateArray, prefix)
                    {
                        ExpectedType = typeSystem.Type
                    });
                }
                else
                {
                    var giCreateArray  = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 2));
                    var dimensionsExpr = new AstExpression(seqp, AstCode.Ldc_I4, arrayType.Dimensions.Count())
                    {
                        ExpectedType = typeSystem.Int
                    };
                    return(new AstExpression(seqp, AstCode.Call, giCreateArray, prefix, dimensionsExpr)
                    {
                        ExpectedType = typeSystem.Type
                    });
                }
            }

            var gp = type as XGenericParameter;

            if (gp != null)
            {
                AstExpression gi;
                if (gp.Owner is XTypeReference)
                {
                    // Class type parameter
                    var owner = (XTypeReference)gp.Owner;
                    if (owner.GetElementType().Resolve().HasDexImportAttribute())
                    {
                        // Imported type
                        return(new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object)
                        {
                            ExpectedType = typeSystem.Type
                        });
                    }
                    if (currentMethod.IsClassCtor)
                    {
                        // Class ctor's cannot have type information.
                        // Return Object instead
                        DLog.Warning(DContext.CompilerCodeGenerator, "Class constructor of {0} tries to use generic parameter. This will always yield Object.", currentMethod.DeclaringTypeFullName);
                        return(new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object)
                        {
                            ExpectedType = typeSystem.Type
                        });
                    }
                    gi = currentMethod.IsStatic ?
                         LoadStaticClassGenericInstance(seqp, typeSystem) :
                         LoadInstanceClassGenericInstance(seqp, typeSystem);
                }
                else
                {
                    // Method type parameter
                    var owner = (XMethodReference)gp.Owner;
                    if (owner.GetElementMethod().Resolve().DeclaringType.HasDexImportAttribute())
                    {
                        // Imported type
                        return(LoadTypeForGenericInstance(seqp, currentMethod, type.Module.TypeSystem.Object, typeHelperType, typeSystem, boxPrimitiveTypes));
                    }
                    gi = LoadMethodGenericInstance(seqp, typeSystem);
                }

                var indexExpr = new AstExpression(seqp, AstCode.Ldc_I4, gp.Position)
                {
                    ExpectedType = typeSystem.Int
                };
                return(new AstExpression(seqp, AstCode.Ldelem_Ref, null,
                                         gi, indexExpr)
                {
                    ExpectedType = typeSystem.Type
                });
            }

            if (type is XTypeSpecification)
            {
                // Just use the element type
                var typeSpec = (XTypeSpecification)type;
                return(LoadTypeForGenericInstance(seqp, currentMethod, typeSpec.ElementType, typeHelperType, typeSystem, boxPrimitiveTypes));
            }

            if (type.IsPrimitive && boxPrimitiveTypes)
            {
                return(new AstExpression(seqp, AstCode.BoxedTypeOf, type)
                {
                    ExpectedType = typeSystem.Type
                });
            }

            // Plain type reference or definition
            return(new AstExpression(seqp, AstCode.TypeOf, type)
            {
                ExpectedType = typeSystem.Type
            });
        }
Пример #14
0
        /// <summary>
        /// Add generic instance field initialization code.
        /// </summary>
        private static void AddGenericInstanceFieldInitializationCode(MethodSource source, AstBlock ast, XTypeSystem typeSystem)
        {
            int paramCount = source.Method.DeclaringType.GenericParameters.Count;

            if (paramCount > InternalConstants.GenericTypeParametersAsArrayThreshold)
            {
                var xArrayType = new XArrayType(typeSystem.Type);
                var loadExpr   = new AstExpression(ast.SourceLocation, AstCode.LdGenericInstanceTypeArgument, 0)
                {
                    ExpectedType = xArrayType
                };
                var initExpr = new AstExpression(ast.SourceLocation, AstCode.StGenericInstanceField, 0, loadExpr)
                {
                    ExpectedType = xArrayType
                };
                InsertAfter(ast, null, new[] { initExpr });
            }
            else
            {
                InsertAfter(ast, null, Enumerable.Range(0, paramCount).Select(i =>
                                                                              new AstExpression(ast.SourceLocation, AstCode.StGenericInstanceField, i,
                                                                                                new AstExpression(ast.SourceLocation, AstCode.LdGenericInstanceTypeArgument, i)
                {
                    ExpectedType = typeSystem.Type
                })
                {
                    ExpectedType = typeSystem.Type
                }));
            }
        }
Пример #15
0
        private static void UnboxByRefIfGeneric(XTypeReference type, AstExpression node, XTypeSystem typeSystem)
        {
            if (!type.IsGenericParameter)
            {
                return;
            }

            var resultType = node.InferredType ?? node.ExpectedType;

            if (resultType == null)
            {
                return;
            }

            if (!TreatAsStruct(type, resultType))
            {
                return;
            }

            // find the first unbox, which should be our target.
            var unbox = node.GetSelfAndChildrenRecursive <AstExpression>(n => n.Code == AstCode.Unbox).FirstOrDefault();

            if (unbox == null)
            {
                return;
            }

            // TODO: Of course we need to unbox generic instances as well,
            //       but at the moment the GenericInstanceConverter does
            //       not look at 'node.StoreByRefExpression' and thus
            //       does not add the required argument, resulting
            //       in unverifyable code. This should be fixed, and
            //       then these lines can be removed.
            if (resultType.IsGenericInstance)
            {
                return;
            }

            ConvertUnboxStruct(unbox, resultType, typeSystem);
        }
Пример #16
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem)
        {
            // Expand typeof
            foreach (var pair in ast.GetExpressionPairs())
            {
                var node = pair.Expression;
                switch (node.Code)
                {
                case AstCode.Ldfld:
                    //case AstCode.Ldsfld: // NOT YET
                {
                    var field = (XFieldReference)node.Operand;
                    UnboxIfGeneric(field.FieldType, node, typeSystem);
                }
                break;

                case AstCode.Stfld:
                {
                    var field = (XFieldReference)node.Operand;
                    BoxIfGeneric(field.FieldType, node.Arguments[1]);
                }
                break;

                case AstCode.Call:
                case AstCode.Calli:
                case AstCode.Callvirt:
                {
                    var method = (XMethodReference)node.Operand;
                    if ((!method.ReturnType.IsVoid()) && (pair.Parent != null))
                    {
                        UnboxIfGeneric(method.ReturnType, node, typeSystem);
                    }
                }
                break;

                case AstCode.Ret:
                {
                    if (node.Arguments.Count > 0)
                    {
                        var expectedType = currentMethod.Method.ReturnType;
                        BoxIfGeneric(expectedType, node.Arguments[0]);
                    }
                }
                break;

                case AstCode.Box:
                {
                    var type = (XTypeReference)node.Operand;

                    // Honestly, the whole Generics code seems to be quite
                    // complex. I hope this fix does not break anything else.
                    // Also: is there any sense in having two codes 'box' and 'boxtogeneric'?

                    // The Rosyln compiler apparently uses 'box' instructions to satisfy
                    // generic constraints. Not sure if this is the right place to handle
                    // this.
                    // What we want to achive is to perform this conversion code only if the
                    // expected type is assignable from any of the constraints. As we do not
                    // have an 'IsAssignableFrom' logic for XTypes, a simpler check must suffice.

                    if (type.IsGenericParameter &&
                        ((XGenericParameter)type).Constraints.Any() &&
                        node.ExpectedType != null && !node.ExpectedType.IsPrimitive &&
                        !node.ExpectedType.IsGenericParameter)
                    {
                        // or just enter the required cast here???
                        node.Code         = AstCode.BoxToGeneric;
                        node.InferredType = node.ExpectedType;
                    }
                }
                break;

                case AstCode.ByRefArray:
                case AstCode.ByRefOutArray:
                {
                    if (node.Arguments.Count > 1)
                    {
                        var originalType = (XTypeReference)node.Arguments[1].Operand;
                        UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem);
                    }
                }
                break;
                }
            }
        }
Пример #17
0
        /// <summary>
        /// Convert  ret or store field node.
        ///
        /// converts to IEnumerable, ICollection or IList if required.
        /// </summary>
        private static void ConvertRetOrStfldOrStsfld(AssemblyCompiler compiler, XTypeReference targetType, AstExpression node, XTypeSystem typeSystem)
        {
            var argument = node.Arguments.LastOrDefault();

            if (argument == null)
            {
                return;
            }

            if (argument.InferredType == null || !argument.InferredType.IsArray)
            {
                return;
            }

            var methodName = GetCollectionConvertMethodName(targetType);

            if (methodName == null)
            {
                return;
            }

            // Call "ret asMethod(x)"
            var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
            var asArray     = arrayHelper.Methods.First(x => x.Name == "As" + methodName);

            // AsX(x)
            var asXExpr = new AstExpression(node.SourceLocation, AstCode.Call, asArray, argument).SetType(typeSystem.Object);

            // replace argument.
            node.Arguments[node.Arguments.Count - 1] = asXExpr;
        }
        /// <summary>
        /// Create an expression that loads the given type at runtime.
        /// </summary>
        private static AstExpression LoadTypeForGenericInstance(ISourceLocation seqp, MethodSource currentMethod,
                                                                XTypeReference type, AssemblyCompiler compiler, XTypeDefinition typeHelperType, XTypeSystem typeSystem,
                                                                TypeConversion typeConversion, XGenericInstanceType typeGenericArguments = null)
        {
            if (type.IsArray)
            {
                // Array type
                var arrayType = (XArrayType)type;
                // Load element type
                var prefix = LoadTypeForGenericInstance(seqp, currentMethod, ((XArrayType)type).ElementType, compiler, typeHelperType, typeSystem, typeConversion);
                // Convert to array type
                if (arrayType.Dimensions.Count() == 1)
                {
                    var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 1));
                    return(new AstExpression(seqp, AstCode.Call, giCreateArray, prefix)
                    {
                        ExpectedType = typeSystem.Type
                    });
                }
                else
                {
                    var giCreateArray  = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 2));
                    var dimensionsExpr = new AstExpression(seqp, AstCode.Ldc_I4, arrayType.Dimensions.Count())
                    {
                        ExpectedType = typeSystem.Int
                    };
                    return(new AstExpression(seqp, AstCode.Call, giCreateArray, prefix, dimensionsExpr)
                    {
                        ExpectedType = typeSystem.Type
                    });
                }
            }

            var gp = type as XGenericParameter;

            if (gp != null)
            {
                AstExpression loadExpr;
                if (gp.Owner is XTypeReference)
                {
                    // Class type parameter
                    var owner = (XTypeReference)gp.Owner;
                    if (owner.GetElementType().Resolve().HasDexImportAttribute())
                    {
                        // Imported type
                        return(new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object)
                        {
                            ExpectedType = typeSystem.Type
                        });
                    }
                    if (currentMethod.IsClassCtor)
                    {
                        // Class ctor's cannot have type information.
                        // Return Object instead
                        if (currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("StaticConstructorUsesGenericParameter"))
                        {
                            var msg = "Class (static) constructor of '{0}' tries to use generic parameter. This will always yield Object. " +
                                      "You can suppress this warning with a [SuppressMessage(\"dot42\", \"StaticConstructorUsesGenericParameter\")] " +
                                      "attribute on the class.";

                            if (seqp != null && seqp.Document != null)
                            {
                                DLog.Warning(DContext.CompilerCodeGenerator, seqp.Document, seqp.StartColumn, seqp.StartLine, msg, currentMethod.DeclaringTypeFullName);
                            }
                            else
                            {
                                DLog.Warning(DContext.CompilerCodeGenerator, msg, currentMethod.DeclaringTypeFullName);
                            }
                        }
                        return(new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object)
                        {
                            ExpectedType = typeSystem.Type
                        });
                    }
                    loadExpr = currentMethod.IsStatic ?
                               LoadStaticClassGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position) :
                               LoadInstanceClassGenericArgument(seqp, typeSystem, currentMethod.Method.DeclaringType, gp.Position);
                }
                else
                {
                    // Method type parameter
                    var owner = (XMethodReference)gp.Owner;
                    if (owner.GetElementMethod().Resolve().DeclaringType.HasDexImportAttribute())
                    {
                        // Imported type
                        return(LoadTypeForGenericInstance(seqp, currentMethod, type.Module.TypeSystem.Object, compiler, typeHelperType, typeSystem, typeConversion));
                    }
                    loadExpr = LoadMethodGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position);
                }

                if (typeConversion == TypeConversion.EnsureRuntimeType)
                {
                    return(EnsureGenericRuntimeType(loadExpr, typeSystem, typeHelperType));
                }
                else
                {
                    return(loadExpr);
                }
            }

            if (type is XTypeSpecification)
            {
                var typeSpec = (XTypeSpecification)type;
                var git      = type as XGenericInstanceType;
                var baseType = LoadTypeForGenericInstance(seqp, currentMethod, typeSpec.ElementType, compiler, typeHelperType, typeSystem, typeConversion, git);

                if (typeConversion != TypeConversion.EnsureTrueOrMarkerType || typeSpec.GetElementType().IsNullableT())
                {
                    return(baseType);
                }

                // Use the element type and make a generic proxy with the generic arguments.
                var parameters = CreateGenericInstanceCallArguments(seqp, git, currentMethod, compiler);
                if (parameters.Count == 1 && parameters[0].GetResultType().IsArray)
                {
                    // array type call.
                    var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == 2 && m.Parameters[1].ParameterType.IsArray);
                    return(new AstExpression(seqp, AstCode.Call, method, baseType, parameters[0]));
                }
                else
                {
                    parameters.Insert(0, baseType);
                    var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == parameters.Count && !m.Parameters[1].ParameterType.IsArray);
                    return(new AstExpression(seqp, AstCode.Call, method, parameters.ToArray()));
                }
            }


            if (typeConversion == TypeConversion.EnsureTrueOrMarkerType && type.GetElementType().IsNullableT())
            {
                if (typeGenericArguments != null)
                {
                    var underlying = typeGenericArguments.GenericArguments[0];
                    var code       = underlying.IsPrimitive ? AstCode.BoxedTypeOf : AstCode.NullableTypeOf;
                    return(new AstExpression(seqp, code, underlying)
                    {
                        ExpectedType = typeSystem.Type
                    });
                }
                // if typeGenericArguments is null, this is a generic definition, e.g. typeof(Nullable<>).
            }

            // Plain type reference or definition
            return(new AstExpression(seqp, AstCode.TypeOf, type)
            {
                ExpectedType = typeSystem.Type
            });
        }
Пример #19
0
        /// <summary>
        /// Convert node with code InstanceOf.
        /// </summary>
        private static void ConvertInstanceOf(AssemblyCompiler compiler, AstExpression node, XTypeSystem typeSystem)
        {
            var type = (XTypeReference)node.Operand;

            if (type.IsSystemArray()) // "is System.Array"
            {
                // Call ArrayHelper.IsArray
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var isArray     = arrayHelper.Methods.First(x => x.Name == "IsArray");
                var isArrayExpr = new AstExpression(node.SourceLocation, AstCode.Call, isArray, node.Arguments).SetType(typeSystem.Bool);
                node.CopyFrom(isArrayExpr);
                return;
            }

            // make sure we don't evaluate the expression twice.
            var tempVar = new AstGeneratedVariable("temp$$", null)
            {
                Type = compiler.Module.TypeSystem.Object
            };
            var storeTempVar = new AstExpression(node.SourceLocation, AstCode.Stloc, tempVar, node.Arguments[0])
            {
                ExpectedType = compiler.Module.TypeSystem.Object
            };
            var loadTempVar = new AstExpression(node.SourceLocation, AstCode.Ldloc, tempVar).SetType(compiler.Module.TypeSystem.Object);

            if (type.IsSystemCollectionsIEnumerable() ||
                type.IsSystemCollectionsICollection() ||
                type.IsSystemCollectionsIList())
            {
                // Call "(is x) || IsArray(x)"
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var isArray     = arrayHelper.Methods.First(x => x.Name == "IsArray" && x.Parameters.Count == 1);

                // "is"
                var isExpr = new AstExpression(node).SetArguments(storeTempVar).SetCode(AstCode.SimpleInstanceOf);

                // Call IsArray
                var isArrayExpr = new AstExpression(node.SourceLocation, AstCode.Call, isArray, loadTempVar).SetType(typeSystem.Bool);

                // Combined
                var combined = new AstExpression(node.SourceLocation, AstCode.Or, null, isExpr, isArrayExpr).SetType(typeSystem.Bool);
                node.CopyFrom(combined);
                return;
            }

            if (type.IsSystemCollectionsIEnumerableT() ||
                type.IsSystemCollectionsICollectionT() ||
                type.IsSystemCollectionsIListT())
            {
                // TODO: implement InstanceOf with type check for array types.
                // (is that even possible here?)
            }

            if (type.IsSystemIFormattable())
            {
                // Call "(is x) || IsFormattable(x)"
                var formattable   = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var isFormattable = formattable.Methods.First(x => x.Name == "IsVirtualFormattable");

                // "is"
                var isExpr = new AstExpression(node).SetArguments(storeTempVar).SetCode(AstCode.SimpleInstanceOf);

                // Call IsFormattable
                var isFormattableExpr = new AstExpression(node.SourceLocation, AstCode.Call, isFormattable, loadTempVar).SetType(typeSystem.Bool);

                // Combined
                var combined = new AstExpression(node.SourceLocation, AstCode.Or, null, isExpr, isFormattableExpr).SetType(typeSystem.Bool);
                node.CopyFrom(combined);
                return;
            }

            // Normal instanceof
            node.Code = AstCode.SimpleInstanceOf;
        }
        /// <summary>
        /// Load the GenericInstance of the current instance.
        /// The result is a temporary register.
        /// </summary>
        private static AstExpression LoadInstanceClassGenericArgument(ISourceLocation seqp, XTypeSystem typeSystem, XTypeDefinition type, int index)
        {
            bool loadFromArray = type.GenericParameters.Count > InternalConstants.GenericTypeParametersAsArrayThreshold;

            return(LoadGenericArgument(seqp, typeSystem, AstCode.LdGenericInstanceField, index, loadFromArray));
        }
Пример #21
0
        /// <summary>
        /// Convert node with code IsInst.
        /// </summary>
        private static void ConvertIsInst(AssemblyCompiler compiler, AstExpression node, XTypeSystem typeSystem)
        {
            var type = (XTypeReference)node.Operand;

            if (type.IsSystemArray())
            {
                // Call ArrayHelper.AsArray
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var asArray     = arrayHelper.Methods.First(x => x.Name == "AsArray");
                var asArrayExpr = new AstExpression(node.SourceLocation, AstCode.Call, asArray, node.Arguments).SetType(typeSystem.Bool);
                node.CopyFrom(asArrayExpr);
                return;
            }

            string asMethod = null;

            if (type.IsSystemCollectionsIEnumerable())
            {
                asMethod = "AsEnumerable";
            }
            else if (type.IsSystemCollectionsICollection())
            {
                asMethod = "AsCollection";
            }
            else if (type.IsSystemCollectionsIList())
            {
                asMethod = "AsList";
            }
            else if (type.IsSystemIFormattable())
            {
                asMethod = "AsFormattable";
            }

            if (asMethod != null)
            {
                // Call "(x instanceof T) ? (T)x : asMethod(x)"
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var asArray     = arrayHelper.Methods.First(x => x.Name == asMethod);

                // "instanceof x"
                var instanceofExpr = new AstExpression(node.SourceLocation, AstCode.SimpleInstanceOf, type, node.Arguments[0]).SetType(typeSystem.Bool);

                // AsX(x)
                var asXExpr = new AstExpression(node.SourceLocation, AstCode.Call, asArray, node.Arguments[0]).SetType(typeSystem.Object);

                // T(x)
                var txExpr = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, type, node.Arguments[0]).SetType(type);

                // Combine
                var conditional = new AstExpression(node.SourceLocation, AstCode.Conditional, type, instanceofExpr, txExpr, asXExpr).SetType(type);

                node.CopyFrom(conditional);
                return;
            }

            // Normal "as": Convert to (x instanceof T) ? T(x) : null
            {
                // "instanceof x"
                var instanceofExpr = new AstExpression(node.SourceLocation, AstCode.SimpleInstanceOf, type, node.Arguments[0]).SetType(typeSystem.Bool);

                // T(x)
                var txExpr = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, type, node.Arguments[0]).SetType(type);

                // null
                var nullExpr = new AstExpression(node.SourceLocation, AstCode.Ldnull, null).SetType(typeSystem.Object);

                // Combine
                var conditional = new AstExpression(node.SourceLocation, AstCode.Conditional, type, instanceofExpr, txExpr, nullExpr).SetType(type);

                node.CopyFrom(conditional);
                return;
            }
        }
Пример #22
0
 /// <summary>
 /// Reference to java.lang.String.equals(string)
 /// </summary>
 internal static XMethodReference StringEquals(XTypeSystem typeSystem)
 {
     return(new XMethodReference.Simple("equals", true, typeSystem.Bool, typeSystem.String, XParameter.Create("other", typeSystem.Object)));
 }
Пример #23
0
        /// <summary>
        /// Convert node with code InstanceOf.
        /// </summary>
        private static void ConvertInstanceOf(AssemblyCompiler compiler, AstExpression node, XTypeSystem typeSystem)
        {
            var type = (XTypeReference)node.Operand;

            if (type.IsSystemArray()) // "is System.Array"
            {
                // Call ArrayHelper.IsArray
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var isArray     = arrayHelper.Methods.First(x => x.Name == "IsArray");
                var isArrayExpr = new AstExpression(node.SourceLocation, AstCode.Call, isArray, node.Arguments).SetType(typeSystem.Bool);
                node.CopyFrom(isArrayExpr);
                return;
            }

            if (type.IsSystemCollectionsIEnumerable() || type.IsSystemCollectionsICollection() ||
                type.IsSystemCollectionsIList())
            {
                // Call "(is x) || IsArray(x)"
                var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var isArray     = arrayHelper.Methods.First(x => x.Name == "IsArray");

                // "is"
                var isExpr = new AstExpression(node).SetCode(AstCode.SimpleInstanceOf);

                // Call IsArray
                var isArrayExpr = new AstExpression(node.SourceLocation, AstCode.Call, isArray, node.Arguments).SetType(typeSystem.Bool);

                // Combined
                var combined = new AstExpression(node.SourceLocation, AstCode.Or, null, isExpr, isArrayExpr).SetType(typeSystem.Bool);
                node.CopyFrom(combined);
                return;
            }
            if (type.IsSystemIFormattable())
            {
                // Call "(is x) || IsFormattable(x)"
                var formattable   = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var isFormattable = formattable.Methods.First(x => x.Name == "IsVirtualFormattable");

                // "is"
                var isExpr = new AstExpression(node).SetCode(AstCode.SimpleInstanceOf);

                // Call IsFormattable
                var isFormattableExpr = new AstExpression(node.SourceLocation, AstCode.Call, isFormattable, node.Arguments).SetType(typeSystem.Bool);

                // Combined
                var combined = new AstExpression(node.SourceLocation, AstCode.Or, null, isExpr, isFormattableExpr).SetType(typeSystem.Bool);
                node.CopyFrom(combined);
                return;
            }

            // Normal instanceof
            node.Code = AstCode.SimpleInstanceOf;
        }