Browse Source

Fix dynamic compound assignments

pull/1612/head
Siegfried Pammer 6 years ago
parent
commit
adc443e4e2
  1. 37
      ICSharpCode.Decompiler/IL/Transforms/DynamicIsEventAssignmentTransform.cs
  2. 6
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

37
ICSharpCode.Decompiler/IL/Transforms/DynamicIsEventAssignmentTransform.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Linq;
namespace ICSharpCode.Decompiler.IL.Transforms namespace ICSharpCode.Decompiler.IL.Transforms
{ {
public class DynamicIsEventAssignmentTransform : IStatementTransform public class DynamicIsEventAssignmentTransform : IStatementTransform
@ -24,6 +26,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// if (logic.not(ldloc V_1)) Block IL_004a { /// if (logic.not(ldloc V_1)) Block IL_004a {
/// stloc V_2(dynamic.getmember B(target)) /// stloc V_2(dynamic.getmember B(target))
/// } /// }
/// [stloc copyOfValue(value)]
/// if (logic.not(ldloc V_1)) Block IL_0149 { /// if (logic.not(ldloc V_1)) Block IL_0149 {
/// dynamic.setmember.compound B(target, dynamic.binary.operator AddAssign(ldloc V_2, value)) /// dynamic.setmember.compound B(target, dynamic.binary.operator AddAssign(ldloc V_2, value))
/// } else Block IL_0151 { /// } else Block IL_0151 {
@ -41,11 +44,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return; return;
if (!(flagVar.IsSingleDefinition && flagVar.LoadCount == 2)) if (!(flagVar.IsSingleDefinition && flagVar.LoadCount == 2))
return; return;
if (!(MatchLhsCacheIfInstruction(block.Instructions[pos + 1], flagVar, out var dynamicGetMemberStore))) if (!MatchLhsCacheIfInstruction(block.Instructions[pos + 1], flagVar, out var dynamicGetMemberStore))
return; return;
if (!(dynamicGetMemberStore.MatchStLoc(out var getMemberVar, out inst) && inst is DynamicGetMemberInstruction getMemberInst)) if (!(dynamicGetMemberStore.MatchStLoc(out var getMemberVar, out inst) && inst is DynamicGetMemberInstruction getMemberInst))
return; return;
foreach (var descendant in block.Instructions[pos + 2].Descendants) { int offset = 2;
if (block.Instructions[pos + offset].MatchStLoc(out var valueVariable)
&& pos + 4 < block.Instructions.Count && valueVariable.IsSingleDefinition && valueVariable.LoadCount == 2
&& valueVariable.LoadInstructions.All(ld => ld.Parent is DynamicInstruction)) {
offset++;
}
foreach (var descendant in block.Instructions[pos + offset].Descendants) {
if (!MatchIsEventAssignmentIfInstruction(descendant, isEvent, flagVar, getMemberVar, out var setMemberInst, out var getMemberVarUse, out var isEventConditionUse)) if (!MatchIsEventAssignmentIfInstruction(descendant, isEvent, flagVar, getMemberVar, out var setMemberInst, out var getMemberVarUse, out var isEventConditionUse))
continue; continue;
context.Step("DynamicIsEventAssignmentTransform", block.Instructions[pos]); context.Step("DynamicIsEventAssignmentTransform", block.Instructions[pos]);
@ -86,12 +95,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
isEventConditionUse = condition; isEventConditionUse = condition;
} else } else
return false; return false;
setMemberInst = Block.Unwrap(trueInst) as DynamicSetMemberInstruction; setMemberInst = UnwrapBlockAndUnusedStore(trueInst) as DynamicSetMemberInstruction;
if (!(setMemberInst != null)) if (setMemberInst == null)
return false; return false;
if (!isEvent.Argument.Match(setMemberInst.Target).Success) if (!isEvent.Argument.Match(setMemberInst.Target).Success)
return false; return false;
if (!(Block.Unwrap(falseInst) is DynamicInvokeMemberInstruction invokeMemberInst && invokeMemberInst.Arguments.Count == 2)) if (!(UnwrapBlockAndUnusedStore(falseInst) is DynamicInvokeMemberInstruction invokeMemberInst && invokeMemberInst.Arguments.Count == 2))
return false; return false;
if (!isEvent.Argument.Match(invokeMemberInst.Arguments[0]).Success) if (!isEvent.Argument.Match(invokeMemberInst.Arguments[0]).Success)
return false; return false;
@ -101,6 +110,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true; return true;
} }
/// <summary>
/// If <paramref name="inst"/> is a Block unwraps the block, otherwise returns inst,
/// if the block contains a stloc to a stack slot that is unused, returns the value,
/// otherwise returns inst
/// </summary>
internal static ILInstruction UnwrapBlockAndUnusedStore(ILInstruction inst)
{
var unwrapped = Block.Unwrap(inst);
if (unwrapped is StLoc stloc
&& stloc.Variable.IsSingleDefinition
&& stloc.Variable.LoadCount == 0)
{
return stloc.Value;
}
return unwrapped;
}
/// <summary> /// <summary>
/// if (logic.not(ldloc V_1)) Block IL_004a { /// if (logic.not(ldloc V_1)) Block IL_004a {
/// stloc V_2(dynamic.getmember B(target)) /// stloc V_2(dynamic.getmember B(target))

6
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -497,8 +497,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!(condition is DynamicIsEventInstruction isEvent)) if (!(condition is DynamicIsEventInstruction isEvent))
return false; return false;
trueInst = Block.Unwrap(trueInst); trueInst = DynamicIsEventAssignmentTransform.UnwrapBlockAndUnusedStore(trueInst);
falseInst = Block.Unwrap(falseInst); falseInst = DynamicIsEventAssignmentTransform.UnwrapBlockAndUnusedStore(falseInst);
if (!(falseInst is DynamicCompoundAssign dynamicCompoundAssign)) if (!(falseInst is DynamicCompoundAssign dynamicCompoundAssign))
return false; return false;
if (!(dynamicCompoundAssign.Target is DynamicGetMemberInstruction getMember)) if (!(dynamicCompoundAssign.Target is DynamicGetMemberInstruction getMember))
@ -582,7 +582,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
for (int j = 0; j < dynamicGetIndex.Arguments.Count; j++) { for (int j = 0; j < dynamicGetIndex.Arguments.Count; j++) {
if (!SemanticHelper.IsPure(dynamicGetIndex.Arguments[j].Flags)) if (!SemanticHelper.IsPure(dynamicGetIndex.Arguments[j].Flags))
return; return;
if (!dynamicGetIndex.Arguments[j].Match(dynamicGetIndex.Arguments[j]).Success) if (!dynamicGetIndex.Arguments[j].Match(inst.Arguments[j]).Success)
return; return;
} }
if (!DynamicCompoundAssign.IsExpressionTypeSupported(binaryOp.Operation)) if (!DynamicCompoundAssign.IsExpressionTypeSupported(binaryOp.Operation))

Loading…
Cancel
Save