Example #1
0
        private static void UnboxIfGeneric(XTypeReference type, AstExpression node, XTypeSystem typeSystem)
        {
            if (type.IsGenericParameter || type.IsGenericParameterArray())
            {
                var resultType = node.GetResultType();
                if (resultType.IsByReference && !type.IsByReference)
                {
                    var elementType = resultType.ElementType;

                    var clone = new AstExpression(node);
                    node.SetCode(AstCode.SimpleCastclass).SetArguments(clone).Operand = elementType;
                }
                else
                {
                    if (TreatAsStruct(type, resultType))
                    {
                        ConvertUnboxStruct(node, resultType, typeSystem);
                    }
                    else
                    {
                        var clone = new AstExpression(node);
                        node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = type;
                    }
                }
            }
        }
Example #2
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;
        }
Example #3
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public AstBuilder(XModule module, MethodDefinition methodDef, XTypeDefinition declaringType, bool optimize)
 {
     this.module = module;
     typeSystem = module.TypeSystem;
     this.methodDef = methodDef;
     this.declaringType = declaringType;
     this.optimize = optimize;
     codeAttr = methodDef.Attributes.OfType<CodeAttribute>().FirstOrDefault();
     validExceptionHandlers = (codeAttr != null) ? codeAttr.ExceptionHandlers.Where(IsValid).ToList() : null;
 }
Example #4
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.ByRefArray:
             case AstCode.ByRefOutArray:
             {
                 if (node.Arguments.Count > 1)
                 {
                     var originalType = (XTypeReference) node.Arguments[1].Operand;
                     UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem);
                 }
             }
             break;
         }
     }
 }
Example #5
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;
				}
			}
		}
Example #6
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;
        }
Example #7
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;                
            }
        }
Example #8
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;            
        }
 /// <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);
 }
 private static AstExpression LoadGenericArgument(ISourceLocation seqp, XTypeSystem typeSystem, AstCode ldCode, int index, bool loadFromArray)
 {
     if (loadFromArray)
     {
         var getField = new AstExpression(seqp, ldCode, 0) { ExpectedType = new XArrayType(typeSystem.Type) };
         var indexExpr = new AstExpression(seqp, AstCode.Ldc_I4, index) { ExpectedType = typeSystem.Int };
         var loadExpr = new AstExpression(seqp, AstCode.Ldelem_Ref, null, getField, indexExpr) { ExpectedType = typeSystem.Type };
         return loadExpr;
     }
     else
     {
         return new AstExpression(seqp, ldCode, index) { ExpectedType = typeSystem.Type };
     }
 }
Example #11
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public XModule()
 {
     typeSystem = new XTypeSystem(this);
 }
Example #12
0
 /// <summary>
 /// Load the GenericInstance of the current generic method.
 /// The result is a register that cannot be destroyed.
 /// </summary>
 private static AstExpression LoadMethodGenericInstance(ISourceLocation seqp, XTypeSystem typeSystem)
 {
     return new AstExpression(seqp, AstCode.LdGenericInstanceMethodArgument, null) { ExpectedType = new XArrayType(typeSystem.Type) };
 }
Example #13
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;
            }
        }
Example #14
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;
        }
Example #15
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;
        }
Example #16
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);
        }
Example #17
0
 private TypeAnalysis(DecompilerContext context)
 {
     this.context = context;
     module = context.CurrentModule;
     typeSystem = module.TypeSystem;
 }
Example #18
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;
        }
Example #19
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 }));
     }
 }
Example #20
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())
                return;
            if (targetMethodDefOrRef.Name != "IEnumerable_GetEnumerator")
                return;

            if (node.Arguments.Count != 1) return;

            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;
        }
Example #21
0
        private static void ConvertAsNativeIFormattable(AstExpression node, XTypeSystem typeSystem)
        {
            var method = (XMethodReference)node.Operand;
            var type = method.ReturnType;

            if (method.Name == "AsNativeIFormattable"
                && method.DeclaringType.Name == InternalConstants.CompilerHelperName
                && type.FullName == "System.IFormattable")
            {
                // make sure we don't evaluate the expression twice.
                var tempVar = new AstGeneratedVariable("temp$$", null) { Type = typeSystem.Object };
                var storeTempVar = new AstExpression(node.SourceLocation, AstCode.Stloc, tempVar, node.Arguments[0]) { ExpectedType = typeSystem.Object };
                var loadTempVar = new AstExpression(node.SourceLocation, AstCode.Ldloc, tempVar).SetType(typeSystem.Object);

                // Convert to "(x instanceof T) ? (T)x : null"

                // "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(type);
                // Combine
                var conditional = new AstExpression(node.SourceLocation, AstCode.Conditional, type,
                                        instanceofExpr, txExpr, nullExpr).SetType(type);
                node.CopyFrom(conditional);
            }
        }
Example #22
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);
        }
Example #23
0
        /// <summary>
        /// Create the body of the valueOf(string) method.
        /// </summary>
        private AstBlock CreateValueOfBody(XSyntheticMethodDefinition method, XTypeSystem typeSystem)
        {
            var fields = XType.Fields.Where(x => x.IsStatic && !(x is XSyntheticFieldDefinition)).ToList();
            var ast = AstBlock.Create<AstExpression>();

            // Find name
            foreach (var field in fields)
            {
                var notEqualLabel = new AstLabel(AstNode.NoSource, "not_equal_to" + field.Name);
                var equalsExpr = new AstExpression(AstNode.NoSource, AstCode.Call, FrameworkReferences.StringEquals(typeSystem),
                    new AstExpression(AstNode.NoSource, AstCode.Ldstr, field.Name),
                    new AstExpression(AstNode.NoSource, AstCode.Ldloc, method.AstParameters[0]));

                // If !equals(name, field.name) goto notEqualLabel
                ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Brfalse, notEqualLabel, equalsExpr));
                // Return field object
                ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Ret, null,
                    new AstExpression(AstNode.NoSource, AstCode.Ldsfld, field)));
                // notEqualLabel:
                ast.Body.Add(notEqualLabel);
            }

            // Return null
            ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Ret, null,
                new AstExpression(AstNode.NoSource, AstCode.Ldnull, null)));
            return ast;
        }
Example #24
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;
                }
            }
        }
        /// <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 };
        }
Example #26
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;
            }
        }
 /// <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);
 }
Example #28
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);
 }
Example #30
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));
 }
Example #31
0
 /// <summary>
 /// Load the GenericInstance of the current instance.
 /// The result is a temporary register.
 /// </summary>
 private static AstExpression LoadInstanceClassGenericInstance(ISourceLocation seqp, XTypeSystem typeSystem)
 {
     return new AstExpression(seqp, AstCode.LdGenericInstanceField, null) { ExpectedType = new XArrayType(typeSystem.Type) };
 }