|
|
|
@ -59,6 +59,18 @@ namespace ICSharpCode.Decompiler.ILAst
@@ -59,6 +59,18 @@ namespace ICSharpCode.Decompiler.ILAst
|
|
|
|
|
static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos) |
|
|
|
|
{ |
|
|
|
|
bool modified = false; |
|
|
|
|
expr = SimplifyLdObjAndStObj(expr, ref modified); |
|
|
|
|
if (modified && body != null) |
|
|
|
|
body[pos] = expr; |
|
|
|
|
for (int i = 0; i < expr.Arguments.Count; i++) { |
|
|
|
|
expr.Arguments[i] = SimplifyLdObjAndStObj(expr.Arguments[i], ref modified); |
|
|
|
|
modified |= SimplifyLdObjAndStObj(null, expr.Arguments[i], -1); |
|
|
|
|
} |
|
|
|
|
return modified; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static ILExpression SimplifyLdObjAndStObj(ILExpression expr, ref bool modified) |
|
|
|
|
{ |
|
|
|
|
if (expr.Code == ILCode.Initobj) { |
|
|
|
|
expr.Code = ILCode.Stobj; |
|
|
|
|
expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand)); |
|
|
|
@ -84,13 +96,17 @@ namespace ICSharpCode.Decompiler.ILAst
@@ -84,13 +96,17 @@ namespace ICSharpCode.Decompiler.ILAst
|
|
|
|
|
} |
|
|
|
|
if (newCode != null) { |
|
|
|
|
arg.Code = newCode.Value; |
|
|
|
|
if (expr.Code == ILCode.Stobj) |
|
|
|
|
if (expr.Code == ILCode.Stobj) { |
|
|
|
|
arg.InferredType = expr.InferredType; |
|
|
|
|
arg.ExpectedType = expr.ExpectedType; |
|
|
|
|
arg.Arguments.Add(arg2); |
|
|
|
|
} |
|
|
|
|
arg.ILRanges.AddRange(expr.ILRanges); |
|
|
|
|
body[pos] = arg; |
|
|
|
|
modified = true; |
|
|
|
|
return arg; |
|
|
|
|
} else { |
|
|
|
|
return expr; |
|
|
|
|
} |
|
|
|
|
return modified; |
|
|
|
|
} |
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
@ -214,11 +230,118 @@ namespace ICSharpCode.Decompiler.ILAst
@@ -214,11 +230,118 @@ namespace ICSharpCode.Decompiler.ILAst
|
|
|
|
|
|
|
|
|
|
bool StoreCanBeConvertedToAssignment(ILExpression store, ILVariable exprVar) |
|
|
|
|
{ |
|
|
|
|
if (store != null && (store.Code == ILCode.Stloc || store.Code == ILCode.Stfld || store.Code == ILCode.Stsfld)) { |
|
|
|
|
if (store != null && (store.Code == ILCode.Stloc || store.Code == ILCode.Stfld || store.Code == ILCode.Stsfld || IsArrayStore(store.Code))) { |
|
|
|
|
return store.Arguments.Last().Code == ILCode.Ldloc && store.Arguments.Last().Operand == exprVar; |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool IsArrayStore(ILCode code) |
|
|
|
|
{ |
|
|
|
|
switch (code) { |
|
|
|
|
case ILCode.Stelem_Any: |
|
|
|
|
case ILCode.Stelem_Ref: |
|
|
|
|
case ILCode.Stelem_I: |
|
|
|
|
case ILCode.Stelem_I1: |
|
|
|
|
case ILCode.Stelem_I2: |
|
|
|
|
case ILCode.Stelem_I4: |
|
|
|
|
case ILCode.Stelem_I8: |
|
|
|
|
case ILCode.Stelem_R4: |
|
|
|
|
case ILCode.Stelem_R8: |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region MakeCompoundAssignments
|
|
|
|
|
bool MakeCompoundAssignments(List<ILNode> body, ILExpression expr, int pos) |
|
|
|
|
{ |
|
|
|
|
bool modified = false; |
|
|
|
|
modified |= MakeCompoundAssignmentForArray(expr); |
|
|
|
|
modified |= MakeCompoundAssignmentForInstanceField(expr); |
|
|
|
|
// Static fields and local variables are not handled here - those are expressions without side effects
|
|
|
|
|
// and get handled by ReplaceMethodCallsWithOperators
|
|
|
|
|
// (which does a reversible transform to the short operator form, as the introduction of checked/unchecked might have to revert to the long form).
|
|
|
|
|
foreach (ILExpression arg in expr.Arguments) { |
|
|
|
|
modified |= MakeCompoundAssignments(null, arg, -1); |
|
|
|
|
} |
|
|
|
|
if (modified && body != null) |
|
|
|
|
new ILInlining(method).InlineInto(body, pos, aggressive: false); |
|
|
|
|
return modified; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool MakeCompoundAssignmentForArray(ILExpression expr) |
|
|
|
|
{ |
|
|
|
|
// stelem.any(..., ldloc(array), ldloc(pos), <OP>(ldelem.any(int32, ldloc(array), ldloc(pos)), <RIGHT>))
|
|
|
|
|
if (!IsArrayStore(expr.Code)) |
|
|
|
|
return false; |
|
|
|
|
ILVariable arrayVar, posVar; |
|
|
|
|
if (!(expr.Arguments[0].Match(ILCode.Ldloc, out arrayVar) && expr.Arguments[1].Match(ILCode.Ldloc, out posVar))) |
|
|
|
|
return false; |
|
|
|
|
// At least one of the variables must be generated; otherwise we just keep the expanded form.
|
|
|
|
|
if (!(arrayVar.IsGenerated || posVar.IsGenerated)) |
|
|
|
|
return false; |
|
|
|
|
ILExpression op = expr.Arguments[2]; |
|
|
|
|
if (!CanBeRepresentedAsCompoundAssignment(op.Code)) |
|
|
|
|
return false; |
|
|
|
|
ILExpression ldelem = op.Arguments[0]; |
|
|
|
|
if (!(ldelem.Code == ILCode.Ldelem_Any && ldelem.Arguments[0].MatchLdloc(arrayVar) && ldelem.Arguments[1].MatchLdloc(posVar))) |
|
|
|
|
return false; |
|
|
|
|
expr.Code = ILCode.CompoundAssignment; |
|
|
|
|
expr.Operand = null; |
|
|
|
|
expr.Arguments.RemoveRange(0, 2); |
|
|
|
|
// result is "CompoundAssignment(<OP>(ldelem.any(...), <RIGHT>))"
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool MakeCompoundAssignmentForInstanceField(ILExpression expr) |
|
|
|
|
{ |
|
|
|
|
// stfld(field, expr, <OP>(ldfld(field, expr), <RIGHT>))
|
|
|
|
|
FieldReference field; |
|
|
|
|
ILExpression firstLoad, op; |
|
|
|
|
ILVariable exprVar; |
|
|
|
|
if (!(expr.Match(ILCode.Stfld, out field, out firstLoad, out op) && firstLoad.Match(ILCode.Ldloc, out exprVar) && exprVar.IsGenerated)) |
|
|
|
|
return false; |
|
|
|
|
if (!CanBeRepresentedAsCompoundAssignment(op.Code)) |
|
|
|
|
return false; |
|
|
|
|
ILExpression ldfld = op.Arguments[0]; |
|
|
|
|
if (!(ldfld.Code == ILCode.Ldfld && ldfld.Operand == field && ldfld.Arguments[0].MatchLdloc(exprVar))) |
|
|
|
|
return false; |
|
|
|
|
expr.Code = ILCode.CompoundAssignment; |
|
|
|
|
expr.Operand = null; |
|
|
|
|
expr.Arguments.RemoveAt(0); |
|
|
|
|
// result is "CompoundAssignment(<OP>(ldfld(...), <RIGHT>))"
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool CanBeRepresentedAsCompoundAssignment(ILCode code) |
|
|
|
|
{ |
|
|
|
|
switch (code) { |
|
|
|
|
case ILCode.Add: |
|
|
|
|
case ILCode.Add_Ovf: |
|
|
|
|
case ILCode.Add_Ovf_Un: |
|
|
|
|
case ILCode.Sub: |
|
|
|
|
case ILCode.Sub_Ovf: |
|
|
|
|
case ILCode.Sub_Ovf_Un: |
|
|
|
|
case ILCode.Mul: |
|
|
|
|
case ILCode.Mul_Ovf: |
|
|
|
|
case ILCode.Mul_Ovf_Un: |
|
|
|
|
case ILCode.Div: |
|
|
|
|
case ILCode.Div_Un: |
|
|
|
|
case ILCode.Rem: |
|
|
|
|
case ILCode.Rem_Un: |
|
|
|
|
case ILCode.And: |
|
|
|
|
case ILCode.Or: |
|
|
|
|
case ILCode.Xor: |
|
|
|
|
case ILCode.Shl: |
|
|
|
|
case ILCode.Shr: |
|
|
|
|
case ILCode.Shr_Un: |
|
|
|
|
return true; |
|
|
|
|
default: |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region IntroduceFixedStatements
|
|
|
|
|