Esempio n. 1
0
 public static XTypeReference SubstituteTypeArgs(XTypeReference type, XMemberReference member)
 {
     if (type is XTypeSpecification)
     {
         var arrayType = type as XArrayType;
         if (arrayType != null)
         {
             var elementType = SubstituteTypeArgs(arrayType.ElementType, member);
             if (elementType != arrayType.ElementType)
             {
                 var newArrayType = new XArrayType(elementType, arrayType.Dimensions);
                 return newArrayType;
             }
             else
             {
                 return type;
             }
         }
         var refType = type as XByReferenceType;
         if (refType != null)
         {
             var elementType = SubstituteTypeArgs(refType.ElementType, member);
             return elementType != refType.ElementType ? new XByReferenceType(elementType) : type;
         }
         var giType = type as XGenericInstanceType;
         if (giType != null)
         {
             var genericArgs = giType.GenericArguments.ToArray();
             var isChanged = false;
             for (int i = 0; i < giType.GenericArguments.Count; i++)
             {
                 var argType = SubstituteTypeArgs(giType.GenericArguments[i], member);
                 if (genericArgs[i] != argType)
                 {
                     isChanged = true;
                     genericArgs[i] = argType;
                 }
             }
             return isChanged ? new XGenericInstanceType(giType.ElementType, genericArgs) : type;
         }
         var optmodType = type as XOptionalModifierType;
         if (optmodType != null)
         {
             var elementType = SubstituteTypeArgs(optmodType.ElementType, member);
             return elementType != optmodType.ElementType ? new XOptionalModifierType(optmodType.ModifierType, elementType) : type;
         }
         var reqmodType = type as XRequiredModifierType;
         if (reqmodType != null)
         {
             var elementType = SubstituteTypeArgs(reqmodType.ElementType, member);
             return elementType != reqmodType.ElementType ? new XRequiredModifierType(reqmodType.ModifierType, elementType) : type;
         }
         var ptrType = type as XPointerType;
         if (ptrType != null)
         {
             var elementType = SubstituteTypeArgs(ptrType.ElementType, member);
             return elementType != ptrType.ElementType ? new XPointerType(elementType) : type;
         }
     }
     var gp = type as XGenericParameter;
     if (gp != null)
     {
         var declaringType = member.DeclaringType;
         if (declaringType is XArrayType)
         {
             return ((XArrayType)declaringType).ElementType;
         }
         if (gp.Owner is XMethodReference)
         {
             var giMethod = member as XGenericInstanceMethod;
             if (giMethod != null)
                 return giMethod.GenericArguments[gp.Position];
         }
         else if (declaringType.IsGenericInstance)
         {
             return ((XGenericInstanceType)declaringType).GenericArguments[gp.Position];
         }
     }
     return type;
 }
        /// <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>
        /// Generate code for a call to a method of an array type.
        /// </summary>
        private bool TryVisitArrayTypeMethodCallExpression(AstExpression node, XMethodReference ilMethodRef, List<RLRange> args, AstNode parent, out RLRange result)
        {
            var methodName = ilMethodRef.Name;
            var dimensions = (methodName == "Set") ? args.Count - 2 : args.Count - 1;

            // Get all but last dimensions
            var arr = frame.AllocateTemp(FrameworkReferences.Object);
            var first = this.Add(node.SourceLocation, RCode.Move_object, arr, args[0].Result);
            for (var d = 0; d < dimensions - 1; d++)
            {
                this.Add(node.SourceLocation, RCode.Aget_object, arr, arr, args[d + 1].Result);
            }

            // Get/Set value
            switch (methodName)
            {
                case "Get":
                    {
                        var valueType = node.GetResultType();
                        var lastIndexArg = args[args.Count - 1];
                        var agetCode = new XArrayType(valueType).AGet();
                        var resultReg = frame.AllocateTemp(valueType.GetReference(targetPackage));
                        var last = this.Add(node.SourceLocation, agetCode, resultReg, arr, lastIndexArg.Result);
                        result = new RLRange(first, last, resultReg);
                        return true;
                    }
                case "Set":
                    {
                        var valueType = node.Arguments[node.Arguments.Count - 1].GetResultType();
                        var lastIndexArg = args[args.Count - 2];
                        var aputCode = new XArrayType(valueType).APut();

                        // Perform type conversion if needed
                        bool isConverted;
                        var valueR = args[args.Count - 1].Result;
                        var converted = this.ConvertTypeBeforeStore(node.SourceLocation, valueType, valueType, valueR, targetPackage, frame, compiler, out isConverted);
                        if (isConverted) valueR = converted.Result;
                        
                        var last = this.Add(node.SourceLocation, aputCode, valueR, arr, lastIndexArg.Result);
                        result = new RLRange(first, last, arr);
                        return true;
                    }
                default:
                    result = null;
                    return false;
            }
        }
Esempio n. 4
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 }));
     }
 }
        /// <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);
            }
        }
Esempio n. 6
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public InitArrayData(XArrayType arrayType, Array values)
 {
     this.arrayType = arrayType;
     this.values = values;
 }
Esempio n. 7
0
        /// <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++;
                    }
                }
            }
        }