Example #1
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     // 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;
                     var clone = new AstExpression(node);
                     node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = field.FieldType;
                 }
                 break;
             case AstCode.Call:
             case AstCode.Calli:
             case AstCode.Callvirt:
                 {
                     var method = (XMethodReference)node.Operand;
                     if ((!method.ReturnType.IsVoid()) && (pair.Parent != null))
                     {
                         var clone = new AstExpression(node);
                         node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = method.ReturnType;
                     }
                 }
                 break;
         }
     }
 }
Example #2
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            // 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;
                    var clone = new AstExpression(node);
                    node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = field.FieldType;
                }
                break;

                case AstCode.Call:
                case AstCode.Calli:
                case AstCode.Callvirt:
                {
                    var method = (XMethodReference)node.Operand;
                    if ((!method.ReturnType.IsVoid()) && (pair.Parent != null))
                    {
                        var clone = new AstExpression(node);
                        node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = method.ReturnType;
                    }
                }
                break;
                }
            }
        }
Example #3
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;
         }
     }
 }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast)
        {
            foreach (var pair in ast.GetExpressionPairs())
            {
                var node = pair.Expression;
                switch (node.Code)
                {
                case AstCode.Ldc_I4:
                {
                    var constType = node.GetResultType();
                    if (constType.IsByte())
                    {
                        node.Operand = System.Convert.ToInt32(node.Operand) & 0xFF;
                    }
                    else if (constType.IsUInt16())
                    {
                        node.Operand = System.Convert.ToInt32(node.Operand) & 0xFFFF;
                    }
                }
                break;

                case AstCode.Ldloc:
                {
                    var variable = (AstVariable)node.Operand;
                    var varType  = variable.Type;
                    ConvertIfNeeded(node, varType, pair.Parent);
                }
                break;

                case AstCode.Ldfld:
                case AstCode.Ldsfld:
                {
                    var field     = (XFieldReference)node.Operand;
                    var fieldType = field.FieldType;
                    ConvertIfNeeded(node, fieldType, pair.Parent);
                }
                break;

                case AstCode.Ldelem_U1:
                case AstCode.Ldelem_U2:
                {
                    var arrayType   = (XArrayType)node.Arguments[0].GetResultType();
                    var elementType = arrayType.ElementType;
                    ConvertIfNeeded(node, elementType, pair.Parent);
                }
                break;
                }
            }
        }
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast)
 {
     foreach (var pair in ast.GetExpressionPairs())
     {
         var node = pair.Expression;
         switch (node.Code)
         {
             case AstCode.Ldc_I4:
                 {
                     var constType = node.GetResultType();
                     if (constType.IsByte())
                     {
                         node.Operand = System.Convert.ToInt32(node.Operand) & 0xFF;
                     }
                     else if (constType.IsUInt16())
                     {
                         node.Operand = System.Convert.ToInt32(node.Operand) & 0xFFFF;
                     }
                 }
                 break;
             case AstCode.Ldloc:
                 {
                     var variable = (AstVariable) node.Operand;
                     var varType = variable.Type;
                     ConvertIfNeeded(node, varType, pair.Parent);
                 }
                 break;
             case AstCode.Ldfld:
             case AstCode.Ldsfld:
                 {
                     var field = (XFieldReference) node.Operand;
                     var fieldType = field.FieldType;
                     ConvertIfNeeded(node, fieldType, pair.Parent);
                 }
                 break;
             case AstCode.Ldelem_U1:
             case AstCode.Ldelem_U2:
                 {
                     var arrayType = (XArrayType) node.Arguments[0].GetResultType();
                     var elementType = arrayType.ElementType;
                     ConvertIfNeeded(node, elementType, pair.Parent);
                 }
                 break;
         }
     }
 }
Example #6
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            foreach (var pair in ast.GetExpressionPairs())
            {
                var node = pair.Expression;
                switch (node.Code)
                {
                case AstCode.Call:
                case AstCode.Calli:
                case AstCode.Callvirt:
                    var methodRef = (XMethodReference)node.Operand;
                    XMethodDefinition method;
                    if (methodRef.TryResolve(out method))
                    {
                        var targetType = method.DeclaringType;
                        var prefix     = node.GetPrefix(AstCode.Constrained);
                        if (prefix != null)
                        {
                            // Calls to object::ToString for value types have a constrained prefix with the target type in the prefix operand.
                            var             prefixTypeRef = (XTypeReference)prefix.Operand;
                            XTypeDefinition prefixTypeDef;
                            if (prefixTypeRef.TryResolve(out prefixTypeDef))
                            {
                                targetType = prefixTypeDef;
                            }
                        }
                        if (targetType.IsValueType && !targetType.IsPrimitive &&
                            !/*targetType*/ method.DeclaringType.IsSystemNullable())
                        {
                            if (method.IsConstructor && (!node.Arguments[0].MatchThis()))
                            {
                                // Convert ctor call
                                ConvertCtorCall(node, methodRef);
                            }
                            else
                            {
                                // Convert normal method call
                                for (var i = 0; i < node.Arguments.Count; i++)
                                {
                                    ProcessArgument(node, method, i, compiler.Module);
                                }
                            }
                        }

                        // Clone all struct arguments
                        for (var i = 0; i < node.Arguments.Count; i++)
                        {
                            CloneStructArgument(node, method, i);
                        }
                    }
                    break;

                case AstCode.DefaultValue:
                {
                    var             typeRef = (XTypeReference)node.Operand;
                    XTypeDefinition type;
                    if (typeRef.TryResolve(out type))
                    {
                        if (type.IsStruct)
                        {
                            var defaultCtor = GetDefaultValueCtor(type);
                            ConvertDefaultValue(node, defaultCtor);
                        }
                    }
                }
                break;

                case AstCode.Newarr:
                {
                    var             typeRef = (XTypeReference)node.Operand;
                    XTypeDefinition type;
                    if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive &&
                        !type.IsSystemNullable())
                    {
                        var parentCode = (pair.Parent != null) ? pair.Parent.Code : AstCode.Nop;
                        if (type.IsEnum)
                        {
                            // Initialize enum array
                            if (parentCode != AstCode.InitEnumArray)         // Avoid recursion
                            {
                                ConvertNewArrEnum(node);
                            }
                        }
                        else
                        {
                            // Initialize struct array
                            if (parentCode != AstCode.InitStructArray)         // Avoid recursion
                            {
                                var defaultCtor = GetDefaultValueCtor(type);
                                ConvertNewArrStruct(node, defaultCtor);
                            }
                        }
                    }
                }
                break;

                case AstCode.Ldloca:
                    node.Code = AstCode.Ldloc;
                    break;

                case AstCode.Ldflda:
                    node.Code = AstCode.Ldfld;
                    break;

                case AstCode.Ldsflda:
                    node.Code = AstCode.Ldsfld;
                    break;

                case AstCode.Ldelema:
                    node.Code = AstCode.Ldelem_Any;
                    break;

                case AstCode.Ldobj:
                    if ((node.Arguments.Count == 1) && (node.Arguments[0].Code == AstCode.Ldloc))
                    {
                        node.CopyFrom(node.Arguments[0]);
                    }
                    break;

                case AstCode.Stelem_Any:
                {
                    var             arrayType = node.Arguments[0].GetResultType() as XArrayType;
                    XTypeDefinition elementType;
                    if ((arrayType != null) &&
                        (arrayType.ElementType.IsStruct(out elementType) &&
                         !elementType.IsImmutableStruct))
                    {
                        // Call $Clone
                        var cloneMethod = GetCloneMethod(elementType);
                        var valueArg    = node.Arguments[2];
                        if (IsCloneNeeded(valueArg))
                        {
                            var clone = new AstExpression(node.SourceLocation, AstCode.Call, arrayType.ElementType.CreateReference(cloneMethod), valueArg);
                            node.Arguments[2] = clone;
                        }
                    }
                }
                break;

                case AstCode.Stfld:
                case AstCode.Stsfld:
                {
                    var             field = (XFieldReference)node.Operand;
                    XTypeDefinition fieldType;
                    if (field.FieldType.IsStruct(out fieldType) && !fieldType.IsImmutableStruct)
                    {
                        // Call $Clone
                        var cloneMethod   = GetCloneMethod(fieldType);
                        var valueArgIndex = node.Arguments.Count - 1;         // Last argument
                        var valueArg      = node.Arguments[valueArgIndex];
                        if (IsCloneNeeded(valueArg))
                        {
                            var clone = new AstExpression(node.SourceLocation, AstCode.Call, field.FieldType.CreateReference(cloneMethod), valueArg);
                            node.Arguments[valueArgIndex] = clone;
                        }
                    }
                }
                break;

                case AstCode.Stloc:
                {
                    var             variable = (AstVariable)node.Operand;
                    XTypeDefinition varType;
                    if (variable.Type.IsStruct(out varType))
                    {
                        if (variable.IsThis)
                        {
                            // Call this.$CopyFrom
                            var copyFromMethod = GetCopyFromMethod(varType);
                            node.Code    = AstCode.Call;
                            node.Operand = variable.Type.CreateReference(copyFromMethod);
                        }
                        else
                        {
                            if (!varType.IsImmutableStruct)
                            {
                                // Call $Clone
                                var cloneMethod   = GetCloneMethod(varType);
                                var valueArgIndex = node.Arguments.Count - 1;         // Last argument
                                var valueArg      = node.Arguments[valueArgIndex];
                                if (IsCloneNeeded(valueArg))
                                {
                                    var clone = new AstExpression(node.SourceLocation, AstCode.Call,
                                                                  variable.Type.CreateReference(cloneMethod), valueArg);
                                    node.Arguments[valueArgIndex] = clone;
                                }
                            }
                        }
                    }
                }
                break;

                case AstCode.Stobj:
                {
                    var             type = (XTypeReference)node.Operand;
                    XTypeDefinition typeDef;
                    if (type.IsStruct(out typeDef) && !typeDef.IsImmutableStruct)
                    {
                        // Convert to arg0.$CopyFrom(arg1)
                        var copyFromMethod = GetCopyFromMethod(typeDef);
                        node.Code    = AstCode.Call;
                        node.Operand = type.CreateReference(copyFromMethod);
                    }
                }
                break;

                case AstCode.Box:
                    if (node.Arguments.Count == 1)
                    {
                        var             typeRef = (XTypeReference)node.Operand;
                        XTypeDefinition type;
                        if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive &&
                            !type.IsSystemNullable())
                        {
                            var ldObjExpr = node.Arguments[0];
                            if ((ldObjExpr.Code == AstCode.Ldobj) && (ldObjExpr.Arguments.Count == 1))
                            {
                                var ldThisExpr = ldObjExpr.Arguments[0];
                                if (ldThisExpr.MatchThis())
                                {
                                    // box(ldobj(ldthis)) -> ldthis
                                    // TODO: think about making a clone here.
                                    node.CopyFrom(ldThisExpr);
                                }
                            }
                        }
                    }
                    break;

                case AstCode.Ret:
                    if (node.Arguments.Count == 1)
                    {
                        var ldObjExpr = node.Arguments[0];
                        if ((ldObjExpr.Code == AstCode.Ldobj) && (ldObjExpr.Arguments.Count == 1))
                        {
                            var             typeRef = ldObjExpr.GetResultType();
                            XTypeDefinition type;
                            if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive &&
                                !type.IsSystemNullable())
                            {
                                var ldThisExpr = ldObjExpr.Arguments[0];
                                if (ldThisExpr.MatchThis())
                                {
                                    // box(ldobj(ldthis)) -> ldthis
                                    ldObjExpr.CopyFrom(ldThisExpr);
                                }
                            }
                        }
                    }
                    break;
                }
            }
        }
Example #7
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>
        /// 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;
                }
            }
        }
Example #9
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, AssemblyCompiler compiler)
        {
            foreach (var pair in ast.GetExpressionPairs())
            {
                var node = pair.Expression;
                switch (node.Code)
                {
                    case AstCode.Call:
                    case AstCode.Calli:
                    case AstCode.Callvirt:
                        var methodRef = (XMethodReference) node.Operand;
                        XMethodDefinition method;
                        if (methodRef.TryResolve(out method))
                        {
                            var targetType = method.DeclaringType;
                            var prefix = node.GetPrefix(AstCode.Constrained);
                            if (prefix != null)
                            {
                                // Calls to object::ToString for value types have a constrained prefix with the target type in the prefix operand.
                                var prefixTypeRef = (XTypeReference) prefix.Operand;
                                XTypeDefinition prefixTypeDef;
                                if (prefixTypeRef.TryResolve(out prefixTypeDef))
                                {
                                    targetType = prefixTypeDef;
                                }
                            }
                            if (targetType.IsValueType && !targetType.IsPrimitive &&
                                ! /*targetType*/method.DeclaringType.IsSystemNullable())
                            {
                                if (method.IsConstructor && (!node.Arguments[0].MatchThis()))
                                {
                                    // Convert ctor call
                                    ConvertCtorCall(node, methodRef);
                                }
                                else
                                {
                                    // Convert normal method call
                                    for (var i = 0; i < node.Arguments.Count; i++)
                                    {
                                        ProcessArgument(node, method, i, compiler.Module);
                                    }
                                }
                            }

                            // Clone all struct arguments
                            for (var i = 0; i < node.Arguments.Count; i++)
                            {
                                CloneStructArgument(node, method, i);
                            }
                        }
                        break;
                    case AstCode.DefaultValue:
                        {
                            var typeRef = (XTypeReference) node.Operand;
                            XTypeDefinition type;
                            if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive && !type.IsEnum &&
                                !type.IsSystemNullable())
                            {
                                var defaultCtor = GetDefaultValueCtor(type);
                                ConvertDefaultValue(node, defaultCtor);
                            }
                        }
                        break;
                    case AstCode.Newarr:
                        {
                            var typeRef = (XTypeReference) node.Operand;
                            XTypeDefinition type;
                            if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive &&
                                !type.IsSystemNullable())
                            {
                                var parentCode = (pair.Parent != null) ? pair.Parent.Code : AstCode.Nop;
                                if (type.IsEnum)
                                {
                                    // Initialize enum array
                                    if (parentCode != AstCode.InitEnumArray) // Avoid recursion
                                    {
                                        ConvertNewArrEnum(node);
                                    }
                                }
                                else
                                {
                                    // Initialize struct array
                                    if (parentCode != AstCode.InitStructArray) // Avoid recursion
                                    {
                                        var defaultCtor = GetDefaultValueCtor(type);
                                        ConvertNewArrStruct(node, defaultCtor);
                                    }
                                }
                            }
                        }
                        break;

                    case AstCode.Ldloca:
                        node.Code = AstCode.Ldloc;
                        break;
                    case AstCode.Ldflda:
                        node.Code = AstCode.Ldfld;
                        break;
                    case AstCode.Ldsflda:
                        node.Code = AstCode.Ldsfld;
                        break;
                    case AstCode.Ldelema:
                        node.Code = AstCode.Ldelem_Any;
                        break;
                    case AstCode.Ldobj:
                        if ((node.Arguments.Count == 1) && (node.Arguments[0].Code == AstCode.Ldloc))
                        {
                            node.CopyFrom(node.Arguments[0]);
                        }
                        break;

                    case AstCode.Stelem_Any:
                        {
                            var arrayType = node.Arguments[0].GetResultType() as XArrayType;
                            XTypeDefinition elementType;
                            if ((arrayType != null) && (arrayType.ElementType.IsStruct(out elementType)))
                            {
                                // Call $Clone
                                var cloneMethod = GetCloneMethod(elementType);
                                var valueArg = node.Arguments[2];
                                if (IsCloneNeeded(valueArg))
                                {
                                    var clone = new AstExpression(node.SourceLocation, AstCode.Call, arrayType.ElementType.CreateReference(cloneMethod), valueArg);
                                    node.Arguments[2] = clone;
                                }
                            }
                        }
                        break;
                    case AstCode.Stfld:
                    case AstCode.Stsfld:
                        {
                            var field = (XFieldReference) node.Operand;
                            XTypeDefinition fieldType;
                            if (field.FieldType.IsStruct(out fieldType))
                            {
                                // Call $Clone
                                var cloneMethod = GetCloneMethod(fieldType);
                                var valueArgIndex = node.Arguments.Count - 1; // Last argument
                                var valueArg = node.Arguments[valueArgIndex];
                                if (IsCloneNeeded(valueArg))
                                {
                                    var clone = new AstExpression(node.SourceLocation, AstCode.Call, field.FieldType.CreateReference(cloneMethod), valueArg);
                                    node.Arguments[valueArgIndex] = clone;
                                }
                            }
                        }
                        break;
                    case AstCode.Stloc:
                        {
                            var variable = (AstVariable) node.Operand;
                            XTypeDefinition varType;
                            if (variable.Type.IsStruct(out varType))
                            {
                                if (variable.IsThis)
                                {
                                    // Call this.$CopyFrom
                                    var copyFromMethod = GetCopyFromMethod(varType);
                                    node.Code = AstCode.Call;
                                    node.Operand = variable.Type.CreateReference(copyFromMethod);
                                }
                                else
                                {
                                    // Call $Clone
                                    var cloneMethod = GetCloneMethod(varType);
                                    var valueArgIndex = node.Arguments.Count - 1; // Last argument
                                    var valueArg = node.Arguments[valueArgIndex];
                                    if (IsCloneNeeded(valueArg))
                                    {
                                        var clone = new AstExpression(node.SourceLocation, AstCode.Call, variable.Type.CreateReference(cloneMethod), valueArg);
                                        node.Arguments[valueArgIndex] = clone;
                                    }
                                }
                            }
                        }
                        break;
                    case AstCode.Stobj:
                        {
                            var type = (XTypeReference) node.Operand;
                            XTypeDefinition typeDef;
                            if (type.IsStruct(out typeDef))
                            {
                                // Convert to arg0.$CopyFrom(arg1)
                                var copyFromMethod = GetCopyFromMethod(typeDef);
                                node.Code = AstCode.Call;
                                node.Operand = type.CreateReference(copyFromMethod);
                            }
                        }
                        break;
                    case AstCode.Box:
                        if (node.Arguments.Count == 1)
                        {
                            var typeRef = (XTypeReference) node.Operand;
                            XTypeDefinition type;
                            if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive &&
                                !type.IsSystemNullable())
                            {
                                var ldObjExpr = node.Arguments[0];
                                if ((ldObjExpr.Code == AstCode.Ldobj) && (ldObjExpr.Arguments.Count == 1))
                                {
                                    var ldThisExpr = ldObjExpr.Arguments[0];
                                    if (ldThisExpr.MatchThis())
                                    {
                                        // box(ldobj(ldthis)) -> ldthis
                                        node.CopyFrom(ldThisExpr);
                                    }
                                }
                            }
                        }
                        break;
                    case AstCode.Ret:
                        if (node.Arguments.Count == 1)
                        {
                            var ldObjExpr = node.Arguments[0];
                            if ((ldObjExpr.Code == AstCode.Ldobj) && (ldObjExpr.Arguments.Count == 1))
                            {
                                var typeRef = ldObjExpr.GetResultType();
                                XTypeDefinition type;
                                if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive &&
                                    !type.IsSystemNullable())
                                {
                                    var ldThisExpr = ldObjExpr.Arguments[0];
                                    if (ldThisExpr.MatchThis())
                                    {
                                        // box(ldobj(ldthis)) -> ldthis
                                        ldObjExpr.CopyFrom(ldThisExpr);
                                    }
                                }
                            }
                        }
                        break;
                }
            }
        }