예제 #1
0
 bool TransformDecimalFieldToConstant(LdObj inst, out LdcDecimal result)
 {
     if (inst.MatchLdsFld(out var field) && field.DeclaringType.IsKnownType(KnownTypeCode.Decimal))
     {
         decimal?value = null;
         if (field.Name == "One")
         {
             value = decimal.One;
         }
         else if (field.Name == "MinusOne")
         {
             value = decimal.MinusOne;
         }
         else if (field.Name == "Zero")
         {
             value = decimal.Zero;
         }
         if (value != null)
         {
             result = new LdcDecimal(value.Value).WithILRange(inst).WithILRange(inst.Target);
             return(true);
         }
     }
     result = null;
     return(false);
 }
예제 #2
0
 protected internal override void VisitLdObj(LdObj inst)
 {
     if (inst.Target.MatchLdLoca(thisVariable))
     {
         inst.ReplaceWith(target.Clone());
         return;
     }
     base.VisitLdObj(inst);
 }
예제 #3
0
 internal static bool LdObjToLdLoc(LdObj inst, ILTransformContext context)
 {
     if (inst.Target.MatchLdLoca(out ILVariable v) &&
         TypeUtils.IsCompatibleTypeForMemoryAccess(v.Type, inst.Type) &&
         inst.UnalignedPrefix == 0 &&
         !inst.IsVolatile)
     {
         context.Step($"ldobj(ldloca {v.Name}) => ldloc {v.Name}", inst);
         inst.ReplaceWith(new LdLoc(v).WithILRange(inst));
         return(true);
     }
     return(false);
 }
예제 #4
0
 protected internal override void VisitLdObj(LdObj inst)
 {
     base.VisitLdObj(inst);
     EarlyExpressionTransforms.AddressOfLdLocToLdLoca(inst, context);
     if (EarlyExpressionTransforms.LdObjToLdLoc(inst, context))
     {
         return;
     }
     if (TransformDecimalFieldToConstant(inst, out LdcDecimal decimalConstant))
     {
         context.Step("TransformDecimalFieldToConstant", inst);
         inst.ReplaceWith(decimalConstant);
         return;
     }
 }
예제 #5
0
 internal static bool LdObjToLdLoc(LdObj inst, ILTransformContext context)
 {
     if (inst.Target.MatchLdLoca(out ILVariable v) &&
         TypeUtils.IsCompatibleTypeForMemoryAccess(v.Type, inst.Type) &&
         inst.UnalignedPrefix == 0 &&
         !inst.IsVolatile)
     {
         context.Step($"ldobj(ldloca {v.Name}) => ldloc {v.Name}", inst);
         ILInstruction replacement = new LdLoc(v).WithILRange(inst);
         if (v.StackType == StackType.Unknown && inst.Type.Kind != TypeKind.Unknown)
         {
             replacement = new Conv(replacement, inst.Type.ToPrimitiveType(),
                                    checkForOverflow: false, Sign.None);
         }
         inst.ReplaceWith(replacement);
         return(true);
     }
     return(false);
 }
예제 #6
0
        internal static void AddressOfLdLocToLdLoca(LdObj inst, ILTransformContext context)
        {
            // ldobj(...(addressof(ldloc V))) where ... can be zero or more ldflda instructions
            // =>
            // ldobj(...(ldloca V))
            var temp  = inst.Target;
            var range = temp.ILRanges;

            while (temp.MatchLdFlda(out var ldfldaTarget, out _))
            {
                temp  = ldfldaTarget;
                range = range.Concat(temp.ILRanges);
            }
            if (temp.MatchAddressOf(out var addressOfTarget, out _) && addressOfTarget.MatchLdLoc(out var v))
            {
                context.Step($"ldobj(...(addressof(ldloca {v.Name}))) => ldobj(...(ldloca {v.Name}))", inst);
                var replacement = new LdLoca(v).WithILRange(addressOfTarget);
                foreach (var r in range)
                {
                    replacement = replacement.WithILRange(r);
                }
                temp.ReplaceWith(replacement);
            }
        }
예제 #7
0
 protected internal override void VisitLdObj(LdObj inst)
 {
     base.VisitLdObj(inst);
     EarlyExpressionTransforms.LdObjToLdLoc(inst, context);
 }
예제 #8
0
 protected internal override void VisitLdObj(LdObj inst)
 {
     base.VisitLdObj(inst);
     LdObjToLdLoc(inst, context);
 }
예제 #9
0
        /// <summary>
        /// Matches Roslyn C# switch on nullable.
        /// </summary>
        bool MatchRoslynSwitchOnNullable(InstructionCollection <ILInstruction> instructions, int i, out SwitchInstruction newSwitch)
        {
            newSwitch = null;
            // match first block:
            // if (logic.not(call get_HasValue(target))) br nullCaseBlock
            // br switchBlock
            if (!instructions[i].MatchIfInstruction(out var condition, out var trueInst))
            {
                return(false);
            }
            if (!instructions[i + 1].MatchBranch(out var switchBlock) || !trueInst.MatchBranch(out var nullCaseBlock))
            {
                return(false);
            }
            if (!condition.MatchLogicNot(out var getHasValue) || !NullableLiftingTransform.MatchHasValueCall(getHasValue, out ILInstruction target) || !SemanticHelper.IsPure(target.Flags))
            {
                return(false);
            }
            // match second block: switchBlock
            // note: I have seen cases where switchVar is inlined into the switch.
            // stloc switchVar(call GetValueOrDefault(ldloca tmp))
            // switch (ldloc switchVar) {
            //  case [0..1): br caseBlock1
            // ... more cases ...
            //  case [long.MinValue..0),[1..5),[6..10),[11..long.MaxValue]: br defaultBlock
            // }
            if (switchBlock.IncomingEdgeCount != 1)
            {
                return(false);
            }
            SwitchInstruction switchInst;

            switch (switchBlock.Instructions.Count)
            {
            case 2:
            {
                // this is the normal case described by the pattern above
                if (!switchBlock.Instructions[0].MatchStLoc(out var switchVar, out var getValueOrDefault))
                {
                    return(false);
                }
                if (!switchVar.IsSingleDefinition || switchVar.LoadCount != 1)
                {
                    return(false);
                }
                if (!(NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, out ILInstruction target2) && target2.Match(target).Success))
                {
                    return(false);
                }
                if (!(switchBlock.Instructions[1] is SwitchInstruction si))
                {
                    return(false);
                }
                switchInst = si;
                break;
            }

            case 1:
            {
                // this is the special case where `call GetValueOrDefault(ldloca tmp)` is inlined into the switch.
                if (!(switchBlock.Instructions[0] is SwitchInstruction si))
                {
                    return(false);
                }
                if (!(NullableLiftingTransform.MatchGetValueOrDefault(si.Value, out ILInstruction target2) && target2.Match(target).Success))
                {
                    return(false);
                }
                switchInst = si;
                break;
            }

            default:
            {
                return(false);
            }
            }
            ILInstruction switchValue;

            if (target.MatchLdLoca(out var v))
            {
                switchValue = new LdLoc(v).WithILRange(target);
            }
            else
            {
                switchValue = new LdObj(target, ((CallInstruction)getHasValue).Method.DeclaringType);
            }
            newSwitch = BuildLiftedSwitch(nullCaseBlock, switchInst, switchValue);
            return(true);
        }
예제 #10
0
        static ILInstruction GetRef(ILVariable v, string Name)
        {
            var ty = TypeInference.GetVariableType(v);

            if (ty == null)
            {
                // happens on ldNull;
                return(null);
            }
            var isPointer = false;

            if (ty.Kind == TypeKind.Pointer)
            {
                ty        = ((ICSharpCode.Decompiler.TypeSystem.PointerType)ty).ElementType;
                isPointer = true;
            }

            IType         etype;
            ILInstruction loadInst;

            if (ty.IsReferenceType.Value)
            {
                etype = GetETypeBase(ty);
                if (isPointer)
                {
                    loadInst = new LdObj(new LdLoc(v), ty);
                }
                else
                {
                    loadInst = new LdLoc(v);
                }



                if (etype == null && !ty.FullName.StartsWith("System."))
                {
                    Debug.Assert(false, "Type is broken??");
                }

                // only do ref counting for our own types
                if (etype == null)
                {
                    return(null);
                }

                // avoid compiler warnings
                loadInst = new CastClass(loadInst, etype);
            }
            else                 // value type
            {
                etype = ty;

                if (v.StackType == StackType.O)
                {
                    loadInst = new Conv(new LdLoca(v), PrimitiveType.I, false, Sign.None);
                }
                else
                {
                    loadInst = new Conv(new LdLoc(v), PrimitiveType.I, false, Sign.None);
                }
            }


            // make sure we don't end up with crazy unintended names
            //v.HasGeneratedName = false;

            //var test = (DefaultResolvedTypeDefinition)ty;

            var m    = etype.GetMethods().First(x => x.Name.EndsWith(Name + "Ref"));
            var inst = new Call(m);

            inst.Arguments.Add(loadInst);

            return(inst);
        }