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); }
protected internal override void VisitLdObj(LdObj inst) { if (inst.Target.MatchLdLoca(thisVariable)) { inst.ReplaceWith(target.Clone()); return; } base.VisitLdObj(inst); }
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); }
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; } }
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); }
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); } }
protected internal override void VisitLdObj(LdObj inst) { base.VisitLdObj(inst); EarlyExpressionTransforms.LdObjToLdLoc(inst, context); }
protected internal override void VisitLdObj(LdObj inst) { base.VisitLdObj(inst); LdObjToLdLoc(inst, context); }
/// <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); }
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); }