diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 66ebbd3ff..d1ae0d7f1 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -953,7 +953,7 @@ namespace ICSharpCode.Decompiler.IL private ILInstruction LdElem(IType type) { - return Push(new LdObj(new LdElema(indices: Pop(), array: Pop(), type: type), type)); + return Push(new LdObj(new LdElema(indices: Pop(), array: Pop(), type: type) { DelayExceptions = true }, type)); } private ILInstruction StElem(IType type) @@ -961,7 +961,7 @@ namespace ICSharpCode.Decompiler.IL var value = Pop(type.GetStackType()); var index = Pop(); var array = Pop(); - return new StObj(new LdElema(type, array, index), value, type); + return new StObj(new LdElema(type, array, index) { DelayExceptions = true }, value, type); } ILInstruction InitObj(ILInstruction target, IType type) diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index d5bedce57..c7e8cb131 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -2177,17 +2177,18 @@ namespace ICSharpCode.Decompiler.IL clone.Target = this.target.Clone(); return clone; } + public bool DelayExceptions; readonly IField field; /// Returns the field operand. public IField Field { get { return field; } } public override StackType ResultType { get { return StackType.Ref; } } protected override InstructionFlags ComputeFlags() { - return target.Flags | InstructionFlags.MayThrow; + return target.Flags | (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow); } public override InstructionFlags DirectFlags { get { - return InstructionFlags.MayThrow; + return (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow); } } public override void WriteTo(ITextOutput output) @@ -3223,16 +3224,17 @@ namespace ICSharpCode.Decompiler.IL clone.Indices.AddRange(this.Indices.Select(arg => arg.Clone())); return clone; } + public bool DelayExceptions; public override StackType ResultType { get { return StackType.Ref; } } /// Gets whether the 'readonly' prefix was applied to this instruction. public bool IsReadOnly { get; set; } protected override InstructionFlags ComputeFlags() { - return array.Flags | Indices.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.MayThrow; + return array.Flags | Indices.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow); } public override InstructionFlags DirectFlags { get { - return InstructionFlags.MayThrow; + return (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow); } } public override void WriteTo(ITextOutput output) diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index dfd067207..15e50b638 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -150,7 +150,7 @@ CustomClassName("LdFld"), CustomArguments("target"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, HasFieldOperand, ResultType("field.Type.GetStackType()")), new OpCode("ldflda", "Load address of instance field", - CustomClassName("LdFlda"), CustomArguments("target"), MayThrow, HasFieldOperand, ResultType("Ref")), + CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")), new OpCode("stfld", "Store value to instance field", CustomClassName("StFld"), CustomArguments("target", "value"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, HasFieldOperand, @@ -199,7 +199,7 @@ CustomClassName("LdLen"), CustomArguments("array"), CustomConstructor, CustomWriteTo, MayThrow), new OpCode("ldelema", "Load address of array element.", CustomClassName("LdElema"), HasTypeOperand, CustomChildren(new [] { new ArgumentInfo("array"), new ArgumentInfo("indices") { IsCollection = true } }, true), - MayThrow, ResultType("Ref"), SupportsReadonlyPrefix), + MayThrowIfNotDelayed, ResultType("Ref"), SupportsReadonlyPrefix), new OpCode("array.to.pointer", "Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty." + Environment.NewLine + "Also used to convert a string to a reference to the first character.", CustomArguments("array"), ResultType("Ref")), @@ -534,6 +534,10 @@ namespace ICSharpCode.Decompiler.IL // Instructions without this trait must evaluate all arguments left-to-right before having any effect of their own. static Action ControlFlow = HasFlag("InstructionFlags.ControlFlow"); + static Action MayThrowIfNotDelayed = HasFlag("(DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow)") + (opCode => { + opCode.Members.Add("public bool DelayExceptions;"); + }); + static Action BaseClass(string name) { return opCode => {