/// <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
                }));
            }
        }
Example #2
0
        private bool TransformMultidimensionalArrayInitializers(List <AstNode> body, AstExpression expr, int pos)
        {
            AstVariable          v;
            AstExpression        newarrExpr;
            XMethodReference     ctor;
            List <AstExpression> ctorArgs;
            XArrayType           arrayType;

            if (expr.Match(AstCode.Stloc, out v, out newarrExpr) &&
                newarrExpr.Match(AstCode.Newobj, out ctor, out ctorArgs) &&
                (arrayType = (ctor.DeclaringType as XArrayType)) != null &&
                arrayType.Rank == ctorArgs.Count)
            {
                // Clone the type, so we can muck about with the Dimensions
                var arrayLengths = new int[arrayType.Rank];
                var dimensions   = new XArrayDimension[arrayType.Rank];
                for (int i = 0; i < arrayType.Rank; i++)
                {
                    if (!ctorArgs[i].Match(AstCode.Ldc_I4, out arrayLengths[i]))
                    {
                        return(false);
                    }
                    if (arrayLengths[i] <= 0)
                    {
                        return(false);
                    }
                    dimensions[i] = new XArrayDimension(0, arrayLengths[i]);
                }
                arrayType = new XArrayType(arrayType.ElementType, dimensions);

                var   totalElements = arrayLengths.Aggregate(1, (t, l) => t * l);
                Array newArr;
                int   initArrayPos;
                if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, totalElements, out newArr,
                                                            out initArrayPos))
                {
                    body[pos] = new AstExpression(expr.SourceLocation, AstCode.Stloc, v,
                                                  new AstExpression(expr.SourceLocation, AstCode.InitArray,
                                                                    new InitArrayData(arrayType, newArr)));
                    body.RemoveAt(initArrayPos);
                    return(true);
                }
            }
            return(false);
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            // Expand typeof
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.TypeOf))
            {
                var type           = (XTypeReference)node.Operand;
                var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                var loadExpr       = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureTrueOrMarkerType);
                node.CopyFrom(loadExpr);
            }

            // Expand instanceOf
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.SimpleInstanceOf))
            {
                var type = (XTypeReference)node.Operand;
                var gp   = type as XGenericParameter;
                if (gp == null)
                {
                    continue;
                }

                var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                var loadExpr       = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType);
                //// both types are boxed, no need for conversion.
                var typeType         = compiler.GetDot42InternalType("System", "Type").Resolve();
                var isInstanceOfType = typeType.Methods.Single(n => n.Name == "JavaIsInstance" && n.Parameters.Count == 1);
                var call             = new AstExpression(node.SourceLocation, AstCode.Call, isInstanceOfType, loadExpr, node.Arguments[0]);
                node.CopyFrom(call);
            }

            // Expand newarr
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Newarr))
            {
                var type = (XTypeReference)node.Operand;
                if (!type.IsDefinitionOrReferenceOrPrimitive())
                {
                    // Resolve type to a Class<?>
                    var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                    // while having primitive arrays for primitive types would be nice, a lot of boxing and unboxing
                    // would be needed. only for-primitive-specialized generic classes we could optimize this.
                    var ldType          = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType);
                    var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance, null, ldType, node.Arguments[0])
                    {
                        ExpectedType = typeSystem.Object
                    };
                    var arrayType = new XArrayType(type);
                    var cast      = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, arrayType, newInstanceExpr)
                    {
                        ExpectedType = arrayType
                    };
                    node.CopyFrom(cast);
                }
            }

            // Add generic instance call arguments
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code.IsCall()))
            {
                var method = (XMethodReference)node.Operand;
                if (method.DeclaringType.IsArray)
                {
                    continue;
                }
                XMethodDefinition methodDef;
                if (!method.TryResolve(out methodDef))
                {
                    continue;
                }
                if (methodDef.HasDexNativeAttribute())
                {
                    continue;
                }

                if (methodDef.NeedsGenericInstanceTypeParameter)
                {
                    // Add generic instance type parameter value
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method.DeclaringType, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }

                if (methodDef.NeedsGenericInstanceMethodParameter)
                {
                    // Add generic instance method parameter
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }
            }

            // Add generic instance Delegate arguments for static methods.
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Delegate))
            {
                var delegateInfo = (Tuple <XTypeDefinition, XMethodReference>)node.Operand;

                var genMethodDef = delegateInfo.Item2 as IXGenericInstance;
                var genTypeDef   = delegateInfo.Item2.DeclaringType as IXGenericInstance;

                // Add generic instance type parameter value, if method is static
                if (genTypeDef != null && delegateInfo.Item2.Resolve().IsStatic)
                {
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2.DeclaringType, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }

                // add generic method type parameter value.
                if (genMethodDef != null)
                {
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }
            }

            // Convert NewObj when needed
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Newobj))
            {
                var ctorRef       = (XMethodReference)node.Operand;
                var declaringType = ctorRef.DeclaringType;
                if (declaringType.IsArray)
                {
                    // New multi dimensional array
                    // Get element type
                    var elemType = ((XArrayType)declaringType).ElementType;
                    var typeExpr = new AstExpression(node.SourceLocation, AstCode.TypeOf, elemType);

                    // Create dimensions array
                    var intArrayType = new XArrayType(typeSystem.Int);
                    var dimArrayExpr = new AstExpression(node.SourceLocation, AstCode.InitArrayFromArguments, intArrayType, node.Arguments).SetType(intArrayType);

                    // Call java.lang.reflect.Array.newInstance(type, int[])
                    var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance2, null, typeExpr, dimArrayExpr).SetType(typeSystem.Object);

                    // Cast to correct type
                    var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, declaringType, newInstanceExpr).SetType(declaringType);

                    // Replace node
                    node.CopyFrom(cast);
                }
                else
                {
                    // Normal "new object"
                    XMethodDefinition ctorDef;
                    if (ctorRef.TryResolve(out ctorDef) && ctorDef.NeedsGenericInstanceTypeParameter)
                    {
                        // Add generic instance type parameter value
                        var arg = CreateGenericInstanceCallArguments(node.SourceLocation, ctorRef.DeclaringType, currentMethod, compiler);
                        node.Arguments.AddRange(arg);
                        node.GenericInstanceArgCount += arg.Count;
                    }
                }
            }
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(DecompilerContext context, AstBlock ast, AssemblyCompiler compiler)
        {
            // Convert stobj/stind_ref
            foreach (var node in ast.GetExpressions(x => (x.Arguments.Count == 2) && ((x.Code == AstCode.Stobj) || (x.Code == AstCode.Stind_Ref))))
            {
                var addrNode  = node.Arguments[0];
                var valueNode = node.Arguments[1];

                AstVariable variable;
                if ((addrNode.GetResultType().IsByReference) && addrNode.Match(AstCode.Ldloc, out variable))
                {
                    if (variable.IsThis && valueNode.Match(AstCode.DefaultValue))
                    {
                        // Struct init : this()
                        node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Nop, null));
                    }
                    else if (!variable.IsThis)
                    {
                        // Convert byref type to array type
                        var addrType  = (XByReferenceType)addrNode.GetResultType();
                        var arrayType = new XArrayType(addrType.ElementType);
                        addrNode.ExpectedType = arrayType;
                        addrNode.InferredType = arrayType;

                        // Convert to stelem array, index, value
                        var int32Type = compiler.Module.TypeSystem.Int;
                        node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type));
                        node.Code = arrayType.ElementType.GetStElemCode();
                    }
                    else
                    {
                        // Convert to stloc
                    }
                }
            }

            // Convert ldobj
            var resetTypes = false;
            var processed  = new HashSet <AstExpression>();

            foreach (var pair in ast.GetExpressionPairs())
            {
                var node = pair.Expression;
                if ((node.Arguments.Count == 1) && ((node.Code == AstCode.Ldobj) || (node.Code == AstCode.Ldind_Ref)))
                {
                    var parent         = pair.Parent;
                    var useAsValue     = true;
                    var isCallArgument = (parent != null) && (parent.Code.IsCall());
                    var isBoxArgument  = (parent != null) && (parent.Match(AstCode.Box));
                    if (isCallArgument && (node.Code == AstCode.Ldobj))
                    {
                        if (IsArgByRefOrOut(node, parent))
                        {
                            useAsValue = false;
                        }
                    }

                    if (isBoxArgument)
                    {
                        var boxType = (XTypeReference)parent.Operand;
                        if (!boxType.IsGenericParameter)
                        {
                            useAsValue = false;
                        }
                    }

                    var ldlocNode = node.Arguments[0];
                    processed.Add(ldlocNode);
                    var addrNodeType = ldlocNode.GetResultType();

                    if (ldlocNode.MatchThis())
                    {
                        useAsValue = false;
                    }

                    if (useAsValue)
                    {
                        if ((addrNodeType.IsByReference) && (ldlocNode.Code == AstCode.Ldloc))
                        {
                            // Convert byref type to array type
                            var addrType  = (XByReferenceType)ldlocNode.GetResultType();
                            var arrayType = new XArrayType(addrType.ElementType);
                            ldlocNode.ExpectedType = arrayType;
                            ldlocNode.InferredType = arrayType;

                            // Convert to ldelem array, index, value
                            var int32Type = compiler.Module.TypeSystem.Int;
                            node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type));
                            node.Code = arrayType.ElementType.GetLdElemCode();
                            node.SetType(arrayType.ElementType);
                            resetTypes = true;
                        }
                    }
                    else if (isCallArgument && (ldlocNode.Code == AstCode.Ldloc))
                    {
                        var             typeRef = (XTypeReference)node.Operand;
                        XTypeDefinition typeDef;
                        if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsValueType &&
                            !typeDef.IsPrimitive)
                        {
                            // Replace by ldloc
                            node.Code    = AstCode.Ldloc;
                            node.Operand = ldlocNode.Operand;
                            node.Arguments.Clear();
                        }
                    }
                }
                else if ((node.Code == AstCode.Ldloc) && ((AstVariable)node.Operand).IsParameter && (node.GetResultType().IsByReference))
                {
                    var parent = pair.Parent;
                    if ((parent != null) && (parent.Code == AstCode.Ldobj))
                    {
                        continue;
                    }
                    var useAsValue     = true;
                    var isCallArgument = (parent != null) && (parent.Code.IsCall());
                    var isBoxArgument  = (parent != null) && (parent.Match(AstCode.Box));
                    if (isCallArgument)
                    {
                        if (IsArgByRefOrOut(node, parent))
                        {
                            useAsValue = false;
                        }
                    }

                    if (isBoxArgument)
                    {
                        useAsValue = false;
                    }

                    if (node.MatchThis())
                    {
                        useAsValue = false;
                    }

                    if (useAsValue)
                    {
                        // Convert byref type to array type
                        var addrType  = (XByReferenceType)node.GetResultType();
                        var arrayType = new XArrayType(addrType.ElementType);
                        var clone     = new AstExpression(node).SetType(arrayType);

                        // Convert to ldelem array, index, value
                        var int32Type = compiler.Module.TypeSystem.Int;
                        node.SetArguments(clone, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type));
                        node.Code = arrayType.ElementType.GetLdElemCode();
                        node.SetType(arrayType.ElementType);
                        resetTypes = true;
                    }
                }
            }

            if (resetTypes)
            {
                TypeAnalysis.Run(context, ast);
            }
        }
Example #5
0
        bool TransformArrayInitializers(List <AstNode> body, AstExpression expr, int pos)
        {
            AstVariable    v, v3;
            AstExpression  newarrExpr;
            XTypeReference elementType;
            AstExpression  lengthExpr;
            int            arrayLength;

            if (expr.Match(AstCode.Stloc, out v, out newarrExpr) &&
                newarrExpr.Match(AstCode.Newarr, out elementType, out lengthExpr) &&
                lengthExpr.Match(AstCode.Ldc_I4, out arrayLength) &&
                arrayLength > 0)
            {
                Array newArr;
                int   initArrayPos;
                if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out newArr, out initArrayPos))
                {
                    var arrayType = new XArrayType(elementType, new XArrayDimension(0, arrayLength));
                    body[pos] = new AstExpression(expr.SourceLocation, AstCode.Stloc, v, new AstExpression(expr.SourceLocation, AstCode.InitArray,
                                                                                                           new InitArrayData(arrayType, newArr)));
                    body.RemoveAt(initArrayPos);
                }
#if !NOTUSED
                // Put in a limit so that we don't consume too much memory if the code allocates a huge array
                // and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
                const int maxConsecutiveDefaultValueExpressions = 0;                // 300;
                var       operands = new List <AstExpression>();
                int       numberOfInstructionsToRemove = 0;
                for (int j = pos + 1; j < body.Count; j++)
                {
                    var nextExpr = body[j] as AstExpression;
                    int arrayPos;
                    if (nextExpr != null &&
                        nextExpr.Code.IsStoreToArray() &&
                        nextExpr.Arguments[0].Match(AstCode.Ldloc, out v3) &&
                        v == v3 &&
                        nextExpr.Arguments[1].Match(AstCode.Ldc_I4, out arrayPos) &&
                        arrayPos >= operands.Count &&
                        arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions)
                    {
                        while (operands.Count < arrayPos)
                        {
                            operands.Add(new AstExpression(expr.SourceLocation, AstCode.DefaultValue, elementType));
                        }
                        operands.Add(nextExpr.Arguments[2]);
                        numberOfInstructionsToRemove++;
                    }
                    else
                    {
                        break;
                    }
                }

                /*if (operands.Count == arrayLength) {
                 *      var arrayType = new XArrayType(elementType, new XArrayDimension(0, arrayLength));
                 *      expr.Arguments[0] = new AstExpression(expr.SourceLocation, AstCode.InitArray, arrayType, operands);
                 *      body.RemoveRange(pos + 1, numberOfInstructionsToRemove);
                 *
                 *      new AstInlining(method).InlineIfPossible(body, ref pos);
                 *      return true;
                 * }*/
#endif
            }
            return(false);
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            // Expand typeof
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.TypeOf))
            {
                var type           = (XTypeReference)node.Operand;
                var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                var loadExpr       = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, typeHelperType, typeSystem, false);
                node.CopyFrom(loadExpr);
            }

            // Expand newarr
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Newarr))
            {
                var type = (XTypeReference)node.Operand;
                if (!type.IsDefinitionOrReferenceOrPrimitive())
                {
                    // Resolve type to a Class<?>
                    var typeHelperType  = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                    var ldType          = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, typeHelperType, typeSystem, false);
                    var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance, null, ldType, node.Arguments[0])
                    {
                        ExpectedType = typeSystem.Object
                    };
                    var arrayType = new XArrayType(type);
                    var cast      = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, arrayType, newInstanceExpr)
                    {
                        ExpectedType = arrayType
                    };
                    node.CopyFrom(cast);
                }
            }

            // Add generic instance call arguments
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code.IsCall()))
            {
                var method = (XMethodReference)node.Operand;
                if (method.DeclaringType.IsArray)
                {
                    continue;
                }
                XMethodDefinition methodDef;
                if (!method.TryResolve(out methodDef))
                {
                    continue;
                }
                if (methodDef.HasDexNativeAttribute())
                {
                    continue;
                }

                if (methodDef.NeedsGenericInstanceTypeParameter)
                {
                    // Add generic instance type parameter value
                    var arg = CreateGenericInstance(node.SourceLocation, method.DeclaringType, currentMethod, compiler);
                    node.Arguments.Add(arg);
                    node.GenericInstanceArgCount++;
                }

                if (methodDef.NeedsGenericInstanceMethodParameter)
                {
                    // Add generic instance method parameter
                    var arg = CreateGenericInstance(node.SourceLocation, method, currentMethod, compiler);
                    node.Arguments.Add(arg);
                    node.GenericInstanceArgCount++;
                }
            }

            // Convert NewObj when needed
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Newobj))
            {
                var ctorRef       = (XMethodReference)node.Operand;
                var declaringType = ctorRef.DeclaringType;
                if (declaringType.IsArray)
                {
                    // New multi dimensional array
                    // Get element type
                    var elemType = ((XArrayType)declaringType).ElementType;
                    var typeExpr = new AstExpression(node.SourceLocation, AstCode.TypeOf, elemType);

                    // Create dimensions array
                    var intArrayType = new XArrayType(typeSystem.Int);
                    var dimArrayExpr = new AstExpression(node.SourceLocation, AstCode.InitArrayFromArguments, intArrayType, node.Arguments).SetType(intArrayType);

                    // Call java.lang.reflect.Array.newInstance(type, int[])
                    var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance2, null, typeExpr, dimArrayExpr).SetType(typeSystem.Object);

                    // Cast to correct type
                    var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, declaringType, newInstanceExpr).SetType(declaringType);

                    // Replace node
                    node.CopyFrom(cast);
                }
                else
                {
                    // Normal "new object"
                    XMethodDefinition ctorDef;
                    if (ctorRef.TryResolve(out ctorDef) && ctorDef.NeedsGenericInstanceTypeParameter)
                    {
                        // Add generic instance type parameter value
                        var arg = CreateGenericInstance(node.SourceLocation, ctorRef.DeclaringType, currentMethod, compiler);
                        node.Arguments.Add(arg);
                        node.GenericInstanceArgCount++;
                    }
                }
            }
        }
Example #7
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public InitArrayData(XArrayType arrayType, Array values)
 {
     this.arrayType = arrayType;
     this.values    = values;
 }