Exemple #1
0
        /// <summary>
        /// Is the given any of binary operations.
        /// </summary>
        public static bool IsBinaryOperation(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Add:
            case AstCode.Add_Ovf:
            case AstCode.Add_Ovf_Un:
            case AstCode.Sub:
            case AstCode.Sub_Ovf:
            case AstCode.Sub_Ovf_Un:
            case AstCode.Mul:
            case AstCode.Mul_Ovf:
            case AstCode.Mul_Ovf_Un:
            case AstCode.Div:
            case AstCode.Div_Un:
            case AstCode.Rem:
            case AstCode.Rem_Un:
            case AstCode.And:
            case AstCode.Or:
            case AstCode.Xor:
            case AstCode.Shl:
            case AstCode.Shr:
            case AstCode.Shr_Un:
                return(true);

            default:
                return(false);
            }
        }
Exemple #2
0
        /// <summary>
        /// Get a dex if-test opcode for the given code
        /// </summary>
        internal static RCode ToIfTest(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Cle:
                return(RCode.If_le);

            case AstCode.Cle_Un:
                return(RCode.If_le);

            case AstCode.Clt:
                return(RCode.If_lt);

            case AstCode.Clt_Un:
                return(RCode.If_lt);

            case AstCode.Ceq:
                return(RCode.If_eq);

            case AstCode.Cne:
                return(RCode.If_ne);

            case AstCode.Cgt:
                return(RCode.If_gt);

            case AstCode.Cgt_Un:
                return(RCode.If_gt);

            case AstCode.Cge:
                return(RCode.If_ge);

            case AstCode.Cge_Un:
                return(RCode.If_ge);

            case AstCode.__Beq:
                return(RCode.If_eq);

            case AstCode.__Bne_Un:
                return(RCode.If_ne);

            case AstCode.__Ble:
            case AstCode.__Ble_Un:
                return(RCode.If_le);

            case AstCode.__Blt:
            case AstCode.__Blt_Un:
                return(RCode.If_lt);

            case AstCode.__Bgt:
            case AstCode.__Bgt_Un:
                return(RCode.If_gt);

            case AstCode.__Bge:
            case AstCode.__Bge_Un:
                return(RCode.If_ge);

            default:
                throw new ArgumentOutOfRangeException("code", code.ToString());
            }
        }
Exemple #3
0
        /// <summary>
        /// Convert condition to branch/zero.
        ///
        /// </summary>
        public static AstCode ToBranchZ(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Cle:
            case AstCode.Cle_Un:
                return(AstCode.BrIfLe);

            case AstCode.Clt:
            case AstCode.Clt_Un:
                return(AstCode.BrIfLt);

            case AstCode.Ceq:
                return(AstCode.BrIfEq);

            case AstCode.Cne:
                return(AstCode.BrIfNe);

            case AstCode.Cgt:
            case AstCode.Cgt_Un:
                return(AstCode.BrIfGt);

            case AstCode.Cge:
            case AstCode.Cge_Un:
                return(AstCode.BrIfGe);

            default:
                throw new ArgumentOutOfRangeException("code", code.ToString());
            }
        }
 private static bool IsEqualsBranchOrComparison(AstCode code)
 {
     return(code == AstCode.Ceq || code == AstCode.Cne ||
            code == AstCode.Brtrue || code == AstCode.Brfalse ||
            code == AstCode.BrIfNe || code == AstCode.BrIfEq ||
            code == AstCode.__Beq || code == AstCode.__Beq ||
            code == AstCode.__Bne_Un || code == AstCode.__Bne_Un);
 }
        /// <summary>
        /// Convert the result of the given node to uint8/uint16 if needed.
        /// </summary>
        private static void Convert(AstExpression node, AstCode convertCode, XTypeReference expectedType)
        {
            // Copy load expression
            var clone = new AstExpression(node);

            // Convert node
            node.Code = convertCode;
            node.SetArguments(clone);
            node.Operand = null;
            node.SetType(expectedType);
        }
        private static void Convert(AstExpression node, AstCode convertCode, XTypeReference expectedType)
        {
            // Copy load expression
            var clone = new AstExpression(node);

            // Convert node
            node.Code = convertCode;
            node.SetArguments(clone);
            node.Operand = null;
            node.SetType(expectedType);
        }
Exemple #7
0
        /// <summary>
        /// Match expression with given code and one argument.
        /// </summary>
        public static bool Match(this AstNode node, AstCode code, out AstExpression arg)
        {
            List <AstExpression> args;

            if (node.Match(code, out args) && args.Count == 1)
            {
                arg = args[0];
                return(true);
            }
            arg = null;
            return(false);
        }
Exemple #8
0
 /// <summary>
 /// Match basic block ending with an expression with code code and one argument, followed by a branch.
 /// </summary>
 public static bool MatchLastAndBr <T>(this AstBasicBlock bb, AstCode code, out T operand, out AstExpression arg, out AstLabel brLabel)
 {
     if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out operand, out arg) &&
         bb.Body.LastOrDefault().Match(AstCode.Br, out brLabel))
     {
         return(true);
     }
     operand = default(T);
     arg     = null;
     brLabel = null;
     return(false);
 }
Exemple #9
0
        /// <summary>
        /// Match expression with given code and no arguments.
        /// </summary>
        public static bool Match <T>(this AstNode node, AstCode code, out T operand)
        {
            var expr = node as AstExpression;

            if ((expr != null) && (expr.Prefixes == null) && (expr.Code == code) && (expr.Arguments.Count == 0))
            {
                operand = (T)expr.Operand;
                return(true);
            }
            operand = default(T);
            return(false);
        }
Exemple #10
0
 /// <summary>
 /// Match basic block with one label followed by an expression with code code and one argument.
 /// </summary>
 public static bool MatchSingle <T>(this AstBasicBlock bb, AstCode code, out T operand, out AstExpression arg)
 {
     if (bb.Body.Count == 2 &&
         bb.Body[0] is AstLabel &&
         bb.Body[1].Match(code, out operand, out arg))
     {
         return(true);
     }
     operand = default(T);
     arg     = null;
     return(false);
 }
Exemple #11
0
        public AstExpression(ISourceLocation sourceLocation, AstCode code, object operand, params AstExpression[] args)
            : base(sourceLocation)
        {
            if (operand is AstExpression)
            {
                throw new ArgumentException("operand");
            }

            Code      = code;
            Operand   = operand;
            Arguments = new List <AstExpression>(args);
            ILRanges  = new List <InstructionRange>(1);
        }
Exemple #12
0
        /// <summary>
        /// Match expression with given code and zero or more arguments.
        /// </summary>
        public static bool Match(this AstNode node, AstCode code, out List <AstExpression> args)
        {
            var expr = node as AstExpression;

            if ((expr != null) && (expr.Prefixes == null) && (expr.Code == code))
            {
                Debug.Assert(expr.Operand == null);
                args = expr.Arguments;
                return(true);
            }
            args = null;
            return(false);
        }
Exemple #13
0
 /// <summary>
 /// Match basic block with one label followed by an expression with code code and one argument, followed by a branch.
 /// </summary>
 public static bool MatchSingleAndBr <T>(this AstBasicBlock bb, AstCode code, out T operand, out AstExpression arg, out AstLabel brLabel)
 {
     if (bb.Body.Count == 3 &&
         bb.Body[0] is AstLabel &&
         bb.Body[1].Match(code, out operand, out arg) &&
         bb.Body[2].Match(AstCode.Br, out brLabel))
     {
         return(true);
     }
     operand = default(T);
     arg     = null;
     brLabel = null;
     return(false);
 }
Exemple #14
0
        /// <summary>
        /// Match expression with given code and two arguments.
        /// </summary>
        public static bool Match <T>(this AstNode node, AstCode code, out T operand, out AstExpression arg1, out AstExpression arg2)
        {
            List <AstExpression> args;

            if (node.Match(code, out operand, out args) && args.Count == 2)
            {
                arg1 = args[0];
                arg2 = args[1];
                return(true);
            }
            arg1 = null;
            arg2 = null;
            return(false);
        }
Exemple #15
0
        /// <summary>
        /// Match expression with given code and zero or more arguments.
        /// </summary>
        public static bool Match <T>(this AstNode node, AstCode code, out T operand, out List <AstExpression> args)
        {
            var expr = node as AstExpression;

            if ((expr != null) && (expr.Prefixes == null) && (expr.Code == code))
            {
                operand = (T)expr.Operand;
                args    = expr.Arguments;
                return(true);
            }
            operand = default(T);
            args    = null;
            return(false);
        }
Exemple #16
0
        /// <summary>
        /// Is the given any of the call codes.
        /// </summary>
        public static bool IsCall(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Call:
            case AstCode.Calli:
            case AstCode.CallIntf:
            case AstCode.Callvirt:
            case AstCode.CallSpecial:
                return(true);

            default:
                return(false);
            }
        }
        /// <summary>
        /// Reverses the code, taking account float/double NaN comparisons
        /// </summary>
        private static AstCode ReverseCode(AstCode code, XTypeReference type)
        {
            bool isFlt = type.IsDouble() || type.IsFloat();

            if (!isFlt)
            {
                return(code.Reverse());
            }

            switch (code)
            {
            case AstCode.Ceq:
                return(AstCode.Cne);

            case AstCode.Cne:
                return(AstCode.Ceq);

            case AstCode.Cle:
                return(AstCode.Cgt_Un);

            case AstCode.Cle_Un:
                return(AstCode.Cgt);

            case AstCode.Clt:
                return(AstCode.Cge_Un);

            case AstCode.Clt_Un:
                return(AstCode.Cge);

            case AstCode.Cgt:
                return(AstCode.Cle_Un);

            case AstCode.Cgt_Un:
                return(AstCode.Cle);

            case AstCode.Cge:
                return(AstCode.Clt_Un);

            case AstCode.Cge_Un:
                return(AstCode.Clt);

            default:
                throw new ArgumentOutOfRangeException("code", code.ToString());
            }
        }
        private static bool CanPullComparisonUp(AstCode code, XTypeReference arg1, XTypeReference arg2, PullTarget target)
        {
            if (arg1 == null || arg2 == null)
            {
                return(false);
            }

            bool isReference = arg1.IsDexObject() && arg1.IsDexObject();

            if (!isReference && !arg1.IsSame(arg2))
            {
                return(false);
            }

            if (target == PullTarget.Comparison)
            {
                return(true);
            }

            if (arg1.Is(XTypeReferenceKind.Float))
            {
                return(false);
            }
            if (arg1.IsDexWide())
            {
                return(false);
            }

            bool isEq = IsEqualsBranchOrComparison(code);

            if (isEq)
            {
                return(true);
            }


            bool isUnsigned = arg1.IsUInt16() || arg1.IsUInt32(); // TODO: check if we really have to exclude unsigned.

            if (isReference || isUnsigned)
            {
                return(false);
            }

            return(true);
        }
Exemple #19
0
        /// <summary>
        /// Create a single bytecode.
        /// </summary>
        private ByteCode CreateByteCode(Instruction inst, AstCode code, object operand, int popCount, int pushCount, Category category, XTypeReference type = null)
        {
            var next     = codeAttr.GetNext(inst);
            var byteCode = new ByteCode
            {
                Category       = category,
                Offset         = inst.Offset,
                EndOffset      = (next != null) ? next.Offset : codeAttr.Code.Length,
                Code           = code,
                Operand        = operand,
                PopCount       = popCount,
                PushCount      = pushCount,
                SourceLocation = new SourceLocation(codeAttr, inst),
                Type           = type
            };

            return(byteCode);
        }
Exemple #20
0
        /// <summary>
        /// Is the given code a Cxx comparision code that requires an integer?
        /// </summary>
        public static bool IsIntegerOnlyCompare(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Cle:
            case AstCode.Cle_Un:
            case AstCode.Clt:
            case AstCode.Clt_Un:
            case AstCode.Cgt:
            case AstCode.Cgt_Un:
            case AstCode.Cge:
            case AstCode.Cge_Un:
                return(true);

            default:
                return(false);
            }
        }
Exemple #21
0
        /// <summary>
        /// Reverse conditions
        /// </summary>
        public static AstCode Reverse(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Cle:
                return(AstCode.Cgt);

            case AstCode.Cle_Un:
                return(AstCode.Cgt_Un);

            case AstCode.Clt:
                return(AstCode.Cge);

            case AstCode.Clt_Un:
                return(AstCode.Cge_Un);

            case AstCode.Ceq:
                return(AstCode.Cne);

            case AstCode.Cne:
                return(AstCode.Ceq);

            case AstCode.Cgt:
                return(AstCode.Cle);

            case AstCode.Cgt_Un:
                return(AstCode.Cle_Un);

            case AstCode.Cge:
                return(AstCode.Clt);

            case AstCode.Cge_Un:
                return(AstCode.Clt_Un);

            case AstCode.CIsNull:
                return(AstCode.CIsNotNull);

            case AstCode.CIsNotNull:
                return(AstCode.CIsNull);

            default:
                throw new ArgumentOutOfRangeException("code", code.ToString());
            }
        }
Exemple #22
0
        private static void MarkReachableForSerialization(ReachableContext context, Instruction arg, MethodBody body)
        {
            object  operand = arg.Operand;
            AstCode astCode = (AstCode)arg.OpCode.Code;

            AstCodeUtil.ExpandMacro(ref astCode, ref operand, body);


            FieldReference     fieldRef;
            MethodReference    methodRef;
            TypeReference      typeRef;
            VariableReference  varRef;
            ParameterReference paramRef;

            if ((fieldRef = operand as FieldReference) != null)
            {
                fieldRef.FieldType.MarkReachable(context, true);
            }
            else if ((methodRef = operand as MethodReference) != null)
            {
                if (arg.OpCode == OpCodes.Newobj)
                {
                    methodRef.DeclaringType.MarkReachable(context, true);
                }
                else
                {
                    methodRef.ReturnType.MarkReachable(context, true);
                }
            }
            else if ((typeRef = operand as TypeReference) != null)
            {
                typeRef.SetReachable(context, true);
            }
            else if ((paramRef = operand as ParameterReference) != null)
            {
                paramRef.ParameterType.MarkReachable(context, true);
            }
            else if ((varRef = operand as VariableReference) != null)
            {
                varRef.VariableType.MarkReachable(context, true);
            }
            // don't know what to do!
        }
Exemple #23
0
        public static bool IsStoreToArray(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Stelem_Any:
            case AstCode.Stelem_I:
            case AstCode.Stelem_I1:
            case AstCode.Stelem_I2:
            case AstCode.Stelem_I4:
            case AstCode.Stelem_I8:
            case AstCode.Stelem_R4:
            case AstCode.Stelem_R8:
            case AstCode.Stelem_Ref:
                return(true);

            default:
                return(false);
            }
        }
Exemple #24
0
        public static bool IsUnconditionalControlFlow(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Br:
            case AstCode.__Br_S:
            case AstCode.Leave:
            case AstCode.__Leave_S:
            case AstCode.Ret:
            case AstCode.Endfilter:
            case AstCode.Endfinally:
            case AstCode.Throw:
            case AstCode.Rethrow:
            case AstCode.LoopOrSwitchBreak:
                return(true);

            default:
                return(false);
            }
        }
Exemple #25
0
        public static bool IsLoadFromArray(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Ldelem_Any:
            case AstCode.Ldelem_I:
            case AstCode.Ldelem_I1:
            case AstCode.Ldelem_I2:
            case AstCode.Ldelem_I4:
            case AstCode.Ldelem_I8:
            case AstCode.Ldelem_U1:
            case AstCode.Ldelem_U2:
            case AstCode.Ldelem_U4:
            case AstCode.Ldelem_R4:
            case AstCode.Ldelem_R8:
            case AstCode.Ldelem_Ref:
                return(true);

            default:
                return(false);
            }
        }
Exemple #26
0
        /// <summary>
        /// Convert condition to branch
        /// </summary>
        public static AstCode ToBranch(this AstCode code)
        {
            switch (code)
            {
            case AstCode.Cle:
                return(AstCode.__Ble);

            case AstCode.Cle_Un:
                return(AstCode.__Ble_Un);

            case AstCode.Clt:
                return(AstCode.__Blt);

            case AstCode.Clt_Un:
                return(AstCode.__Blt_Un);

            case AstCode.Ceq:
                return(AstCode.__Beq);

            case AstCode.Cne:
                return(AstCode.__Bne_Un);

            case AstCode.Cgt:
                return(AstCode.__Bgt);

            case AstCode.Cgt_Un:
                return(AstCode.__Bgt_Un);

            case AstCode.Cge:
                return(AstCode.__Bge);

            case AstCode.Cge_Un:
                return(AstCode.__Bge_Un);

            default:
                throw new ArgumentOutOfRangeException("code", code.ToString());
            }
        }
Exemple #27
0
        public static bool IsConditionalControlFlow(this AstCode code)
        {
            switch (code)
            {
            case AstCode.__Brfalse_S:
            case AstCode.__Brtrue_S:
            case AstCode.__Beq_S:
            case AstCode.__Bge_S:
            case AstCode.__Bgt_S:
            case AstCode.__Ble_S:
            case AstCode.__Blt_S:
            case AstCode.__Bne_Un_S:
            case AstCode.__Bge_Un_S:
            case AstCode.__Bgt_Un_S:
            case AstCode.__Ble_Un_S:
            case AstCode.__Blt_Un_S:
            case AstCode.Brfalse:
            case AstCode.Brtrue:
            case AstCode.__Beq:
            case AstCode.__Bge:
            case AstCode.__Bgt:
            case AstCode.__Ble:
            case AstCode.__Blt:
            case AstCode.__Bne_Un:
            case AstCode.__Bge_Un:
            case AstCode.__Bgt_Un:
            case AstCode.__Ble_Un:
            case AstCode.__Blt_Un:
            case AstCode.Switch:
            case AstCode.LookupSwitch:
                return(true);

            default:
                return(false);
            }
        }
        bool IntroducePostIncrementForVariables(List <AstNode> body, AstExpression expr, int pos)
        {
            // Works for variables and static fields/properties

            // expr = ldloc(i)
            // stloc(i, add(expr, ldc.i4(1)))
            // ->
            // expr = postincrement(1, ldloca(i))
            AstVariable   exprVar;
            AstExpression exprInit;

            if (!(expr.Match(AstCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated))
            {
                return(false);
            }

            //The next expression
            AstExpression nextExpr = body.ElementAtOrDefault(pos + 1) as AstExpression;

            if (nextExpr == null)
            {
                return(false);
            }

            AstCode loadInstruction   = exprInit.Code;
            AstCode storeInstruction  = nextExpr.Code;
            bool    recombineVariable = false;

            // We only recognise local variables, static fields, and static getters with no arguments
            switch (loadInstruction)
            {
            case AstCode.Ldloc:
                //Must be a matching store type
                if (storeInstruction != AstCode.Stloc)
                {
                    return(false);
                }
                AstVariable loadVar  = (AstVariable)exprInit.Operand;
                AstVariable storeVar = (AstVariable)nextExpr.Operand;
                if (loadVar != storeVar)
                {
                    if (loadVar.OriginalVariable != null && loadVar.OriginalVariable == storeVar.OriginalVariable)
                    {
                        recombineVariable = true;
                    }
                    else
                    {
                        return(false);
                    }
                }
                break;

            case AstCode.Ldsfld:
                if (storeInstruction != AstCode.Stsfld)
                {
                    return(false);
                }
                if (exprInit.Operand != nextExpr.Operand)
                {
                    return(false);
                }
                break;

            default:
                return(false);
            }

            AstExpression addExpr = nextExpr.Arguments[0];

            int     incrementAmount;
            AstCode incrementCode = GetIncrementCode(addExpr, out incrementAmount);

            if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar)))
            {
                return(false);
            }

            if (recombineVariable)
            {
                // Split local variable, unsplit these two instances
                // replace nextExpr.Operand with exprInit.Operand
                ReplaceVariables(method, oldVar => oldVar == nextExpr.Operand ? (AstVariable)exprInit.Operand : oldVar);
            }

            switch (loadInstruction)
            {
            case AstCode.Ldloc:
                exprInit.Code = AstCode.Ldloca;
                break;

            case AstCode.Ldsfld:
                exprInit.Code = AstCode.Ldsflda;
                break;
            }
            expr.Arguments[0] = new AstExpression(incrementCode, incrementAmount, exprInit);
            body.RemoveAt(pos + 1);             // TODO ILRanges
            return(true);
        }
Exemple #29
0
 private static bool IsEqualsBranchOrComparison(AstCode code)
 {
     return (code == AstCode.Ceq     || code == AstCode.Cne 
          || code == AstCode.Brtrue  || code == AstCode.Brfalse
          || code == AstCode.BrIfNe  || code == AstCode.BrIfEq
          || code == AstCode.__Beq   || code == AstCode.__Beq
          || code == AstCode.__Bne_Un|| code == AstCode.__Bne_Un);
 }
Exemple #30
0
        private static bool CanPullComparisonUp(AstCode code, XTypeReference arg1, XTypeReference arg2, PullTarget target)
        {
            if (arg1 == null || arg2 == null)
                return false;

            bool isReference = arg1.IsDexObject() && arg1.IsDexObject();

            if (!isReference && !arg1.IsSame(arg2))
                return false;

            if (target == PullTarget.Comparison)
                return true;

            if (arg1.Is(XTypeReferenceKind.Float))
                return false;
            if (arg1.IsDexWide())
                return false;

            bool isEq = IsEqualsBranchOrComparison(code);

            if (isEq)
                return true;

            
            bool isUnsigned = arg1.IsUInt16() || arg1.IsUInt32(); // TODO: check if we really have to exclude unsigned.

            if (isReference || isUnsigned)
                return false;

            return true;
        }
Exemple #31
0
        /// <summary>
        /// Reverses the code, taking account float/double NaN comparisons
        /// </summary>
        private static AstCode ReverseCode(AstCode code, XTypeReference type)
        {
            bool isFlt = type.IsDouble() || type.IsFloat();

            if (!isFlt)
                return code.Reverse();

            switch (code)
            {
                case AstCode.Ceq:
                    return AstCode.Cne;
                case AstCode.Cne:
                    return AstCode.Ceq;
                case AstCode.Cle:
                    return AstCode.Cgt_Un;
                case AstCode.Cle_Un:
                    return AstCode.Cgt;
                case AstCode.Clt:
                    return AstCode.Cge_Un;
                case AstCode.Clt_Un:
                    return AstCode.Cge;
                case AstCode.Cgt:
                    return AstCode.Cle_Un;
                case AstCode.Cgt_Un:
                    return AstCode.Cle;
                case AstCode.Cge:
                    return AstCode.Clt_Un;
                case AstCode.Cge_Un:
                    return AstCode.Clt;
                default:
                    throw new ArgumentOutOfRangeException("code", code.ToString());
            }            
        }
Exemple #32
0
 private static bool IsToEnum(AstCode code)
 {
     return code == AstCode.Int_to_enum || code == AstCode.Long_to_enum;
 }
 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 };
     }
 }
Exemple #34
0
        /// <summary>
        /// Gets the first prefix of the given code.
        /// </summary>
        public AstExpressionPrefix GetPrefix(AstCode code)
        {
            var prefixes = Prefixes;

            return((prefixes != null) ? prefixes.FirstOrDefault(p => p.Code == code) : null);
        }
        AstExpression IntroducePostIncrementForInstanceFields(AstExpression expr)
        {
            // stfld(field, ldloc(instance), add(stloc(helperVar, ldfld(field, ldloc(instance))), ldc.i4(1)))
            // -> stloc(helperVar, postincrement(1, ldflda(field, ldloc(instance))))

            // Also works for array elements and pointers:

            // stelem.any(T, ldloc(instance), ldloc(pos), add(stloc(helperVar, ldelem.any(T, ldloc(instance), ldloc(pos))), ldc.i4(1)))
            // -> stloc(helperVar, postincrement(1, ldelema(ldloc(instance), ldloc(pos))))

            // stobj(T, ldloc(ptr), add(stloc(helperVar, ldobj(T, ldloc(ptr)), ldc.i4(1))))
            // -> stloc(helperVar, postIncrement(1, ldloc(ptr)))

            // callsetter(set_P, ldloc(instance), add(stloc(helperVar, callgetter(get_P, ldloc(instance))), ldc.i4(1)))
            // -> stloc(helperVar, postIncrement(1, propertyaddress. callgetter(get_P, ldloc(instance))))

            if (!(expr.Code == AstCode.Stfld || expr.Code.IsStoreToArray() || expr.Code == AstCode.Stobj))
            {
                return(null);
            }

            // Test that all arguments except the last are ldloc (1 arg for fields and pointers, 2 args for arrays)
            for (int i = 0; i < expr.Arguments.Count - 1; i++)
            {
                if (expr.Arguments[i].Code != AstCode.Ldloc)
                {
                    return(null);
                }
            }

            AstExpression addExpr = expr.Arguments[expr.Arguments.Count - 1];
            int           incrementAmount;
            AstCode       incrementCode = GetIncrementCode(addExpr, out incrementAmount);
            AstVariable   helperVar;
            AstExpression initialValue;

            if (!(incrementAmount != 0 && addExpr.Arguments[0].Match(AstCode.Stloc, out helperVar, out initialValue)))
            {
                return(null);
            }

            if (expr.Code == AstCode.Stfld)
            {
                if (initialValue.Code != AstCode.Ldfld)
                {
                    return(null);
                }
                // There might be two different FieldReference instances, so we compare the field's signatures:
                FieldReference getField = (FieldReference)initialValue.Operand;
                FieldReference setField = (FieldReference)expr.Operand;
                if (!(TypeAnalysis.IsSameType(getField.DeclaringType, setField.DeclaringType) &&
                      getField.Name == setField.Name && TypeAnalysis.IsSameType(getField.FieldType, setField.FieldType)))
                {
                    return(null);
                }
            }
            else if (expr.Code == AstCode.Stobj)
            {
                if (!(initialValue.Code == AstCode.Ldobj && initialValue.Operand == expr.Operand))
                {
                    return(null);
                }
            }
            else
            {
                if (!initialValue.Code.IsLoadFromArray())
                {
                    return(null);
                }
            }
            Debug.Assert(expr.Arguments.Count - 1 == initialValue.Arguments.Count);
            for (int i = 0; i < initialValue.Arguments.Count; i++)
            {
                if (!initialValue.Arguments[i].MatchLdloc((AstVariable)expr.Arguments[i].Operand))
                {
                    return(null);
                }
            }

            AstExpression stloc = addExpr.Arguments[0];

            if (expr.Code == AstCode.Stobj)
            {
                stloc.Arguments[0] = new AstExpression(AstCode.PostIncrement, incrementAmount, initialValue.Arguments[0]);
            }
            else
            {
                stloc.Arguments[0] = new AstExpression(AstCode.PostIncrement, incrementAmount, initialValue);
                initialValue.Code  = (expr.Code == AstCode.Stfld ? AstCode.Ldflda : AstCode.Ldelema);
            }
            // TODO: ILRanges?

            return(stloc);
        }
 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
         });
     }
 }
Exemple #37
0
		public static void ExpandMacro(ref AstCode code, ref object operand, MethodBody methodBody)
		{
			switch (code) {
					case AstCode.__Ldarg_0:   code = AstCode.__Ldarg; operand = methodBody.GetParameter(0); break;
					case AstCode.__Ldarg_1:   code = AstCode.__Ldarg; operand = methodBody.GetParameter(1); break;
					case AstCode.__Ldarg_2:   code = AstCode.__Ldarg; operand = methodBody.GetParameter(2); break;
					case AstCode.__Ldarg_3:   code = AstCode.__Ldarg; operand = methodBody.GetParameter(3); break;
					case AstCode.__Ldloc_0:   code = AstCode.Ldloc; operand = methodBody.Variables[0]; break;
					case AstCode.__Ldloc_1:   code = AstCode.Ldloc; operand = methodBody.Variables[1]; break;
					case AstCode.__Ldloc_2:   code = AstCode.Ldloc; operand = methodBody.Variables[2]; break;
					case AstCode.__Ldloc_3:   code = AstCode.Ldloc; operand = methodBody.Variables[3]; break;
					case AstCode.__Stloc_0:   code = AstCode.Stloc; operand = methodBody.Variables[0]; break;
					case AstCode.__Stloc_1:   code = AstCode.Stloc; operand = methodBody.Variables[1]; break;
					case AstCode.__Stloc_2:   code = AstCode.Stloc; operand = methodBody.Variables[2]; break;
					case AstCode.__Stloc_3:   code = AstCode.Stloc; operand = methodBody.Variables[3]; break;
					case AstCode.__Ldarg_S:   code = AstCode.__Ldarg; break;
					case AstCode.__Ldarga_S:  code = AstCode.__Ldarga; break;
					case AstCode.__Starg_S:   code = AstCode.__Starg; break;
					case AstCode.__Ldloc_S:   code = AstCode.Ldloc; break;
					case AstCode.__Ldloca_S:  code = AstCode.Ldloca; break;
					case AstCode.__Stloc_S:   code = AstCode.Stloc; break;
					case AstCode.__Ldc_I4_M1: code = AstCode.Ldc_I4; operand = -1; break;
					case AstCode.__Ldc_I4_0:  code = AstCode.Ldc_I4; operand = 0; break;
					case AstCode.__Ldc_I4_1:  code = AstCode.Ldc_I4; operand = 1; break;
					case AstCode.__Ldc_I4_2:  code = AstCode.Ldc_I4; operand = 2; break;
					case AstCode.__Ldc_I4_3:  code = AstCode.Ldc_I4; operand = 3; break;
					case AstCode.__Ldc_I4_4:  code = AstCode.Ldc_I4; operand = 4; break;
					case AstCode.__Ldc_I4_5:  code = AstCode.Ldc_I4; operand = 5; break;
					case AstCode.__Ldc_I4_6:  code = AstCode.Ldc_I4; operand = 6; break;
					case AstCode.__Ldc_I4_7:  code = AstCode.Ldc_I4; operand = 7; break;
					case AstCode.__Ldc_I4_8:  code = AstCode.Ldc_I4; operand = 8; break;
					case AstCode.__Ldc_I4_S:  code = AstCode.Ldc_I4; operand = (int) (sbyte) operand; break;
					case AstCode.__Br_S:      code = AstCode.Br; break;
					case AstCode.__Brfalse_S: code = AstCode.Brfalse; break;
					case AstCode.__Brtrue_S:  code = AstCode.Brtrue; break;
					case AstCode.__Beq_S:     code = AstCode.__Beq; break;
					case AstCode.__Bge_S:     code = AstCode.__Bge; break;
					case AstCode.__Bgt_S:     code = AstCode.__Bgt; break;
					case AstCode.__Ble_S:     code = AstCode.__Ble; break;
					case AstCode.__Blt_S:     code = AstCode.__Blt; break;
					case AstCode.__Bne_Un_S:  code = AstCode.__Bne_Un; break;
					case AstCode.__Bge_Un_S:  code = AstCode.__Bge_Un; break;
					case AstCode.__Bgt_Un_S:  code = AstCode.__Bgt_Un; break;
					case AstCode.__Ble_Un_S:  code = AstCode.__Ble_Un; break;
					case AstCode.__Blt_Un_S:  code = AstCode.__Blt_Un; break;
					case AstCode.__Leave_S:   code = AstCode.Leave; break;
					case AstCode.__Ldind_I:   code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break;
					case AstCode.__Ldind_I1:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.SByte; break;
					case AstCode.__Ldind_I2:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int16; break;
					case AstCode.__Ldind_I4:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int32; break;
					case AstCode.__Ldind_I8:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int64; break;
					case AstCode.__Ldind_U1:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Byte; break;
					case AstCode.__Ldind_U2:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt16; break;
					case AstCode.__Ldind_U4:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt32; break;
					case AstCode.__Ldind_R4:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Single; break;
					case AstCode.__Ldind_R8:  code = AstCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Double; break;
					case AstCode.__Stind_I:   code = AstCode.Stobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break;
					case AstCode.__Stind_I1:  code = AstCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Byte; break;
					case AstCode.__Stind_I2:  code = AstCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int16; break;
					case AstCode.__Stind_I4:  code = AstCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int32; break;
					case AstCode.__Stind_I8:  code = AstCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int64; break;
					case AstCode.__Stind_R4:  code = AstCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Single; break;
					case AstCode.__Stind_R8:  code = AstCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Double; break;
			}
		}
 /// <summary>
 /// Create a single bytecode.
 /// </summary>
 private ByteCode CreateByteCode(Instruction inst, AstCode code, object operand, int popCount, int pushCount, Category category, XTypeReference type = null)
 {
     var next = codeAttr.GetNext(inst);
     var byteCode = new ByteCode
     {
         Category = category,
         Offset = inst.Offset,
         EndOffset = (next != null) ? next.Offset : codeAttr.Code.Length,
         Code = code,
         Operand = operand,
         PopCount = popCount,
         PushCount = pushCount,
         SourceLocation = new SourceLocation(codeAttr, inst),
         Type = type
     };
     return byteCode;
 }
 /// <summary>
 /// Default ctor
 /// </summary>
 public AstExpressionPrefix(AstCode code, object operand = null)
 {
     Code = code;
     Operand = operand;
 }