Browse Source

Adjust yield return decompiler to David's pattern matching refactoring.

pull/70/head
Daniel Grunwald 15 years ago
parent
commit
e71935144a
  1. 107
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  2. 10
      ICSharpCode.Decompiler/ILAst/Pattern.cs
  3. 95
      ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

107
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -110,17 +110,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -110,17 +110,17 @@ namespace ICSharpCode.Decompiler.ILAst
expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
expr.ILRanges.Clear();
continue;
case ILCode.__Brfalse: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break;
case ILCode.__Beq: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break;
case ILCode.__Bne_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break;
case ILCode.__Bgt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break;
case ILCode.__Bgt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break;
case ILCode.__Ble: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break;
case ILCode.__Ble_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break;
case ILCode.__Blt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break;
case ILCode.__Blt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break;
case ILCode.__Bge: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break;
case ILCode.__Bge_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break;
case ILCode.__Brfalse: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break;
case ILCode.__Beq: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break;
case ILCode.__Bne_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break;
case ILCode.__Bgt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break;
case ILCode.__Bgt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break;
case ILCode.__Ble: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break;
case ILCode.__Ble_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break;
case ILCode.__Blt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break;
case ILCode.__Blt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break;
case ILCode.__Bge: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break;
case ILCode.__Bge_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break;
default:
continue;
}
@ -495,36 +495,36 @@ namespace ICSharpCode.Decompiler.ILAst @@ -495,36 +495,36 @@ namespace ICSharpCode.Decompiler.ILAst
// Use loop to implement the condition
result.Add(new ILBasicBlock() {
EntryLabel = basicBlock.EntryLabel,
Body = new List<ILNode>() {
new ILWhileLoop() {
Condition = condExpr,
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, trueLabel),
Body = FindLoops(loopContents, node, true)
}
},
new ILExpression(ILCode.Br, falseLabel)
},
FallthoughGoto = null
});
EntryLabel = basicBlock.EntryLabel,
Body = new List<ILNode>() {
new ILWhileLoop() {
Condition = condExpr,
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, trueLabel),
Body = FindLoops(loopContents, node, true)
}
},
new ILExpression(ILCode.Br, falseLabel)
},
FallthoughGoto = null
});
}
}
// Fallback method: while(true)
if (scope.Contains(node)) {
result.Add(new ILBasicBlock() {
EntryLabel = new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
Body = new List<ILNode>() {
new ILWhileLoop() {
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel),
Body = FindLoops(loopContents, node, true)
}
},
},
FallthoughGoto = null
});
EntryLabel = new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
Body = new List<ILNode>() {
new ILWhileLoop() {
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel),
Body = FindLoops(loopContents, node, true)
}
},
},
FallthoughGoto = null
});
}
// Move the content into loop block
@ -643,7 +643,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -643,7 +643,7 @@ namespace ICSharpCode.Decompiler.ILAst
var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) };
ilSwitch.CaseBlocks.Add(caseBlock);
newBB.FallthoughGoto = null;
scope.ExceptWith(content);
caseBlock.Body.AddRange(FindConditions(content, fallTarget));
// Add explicit break which should not be used by default, but the goto removal might decide to use it
@ -671,9 +671,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -671,9 +671,9 @@ namespace ICSharpCode.Decompiler.ILAst
FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
};
result.Add(new ILBasicBlock() {
EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilCond }
});
EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilCond }
});
// Remove the item immediately so that it is not picked up as content
scope.RemoveOrThrow(node);
@ -870,6 +870,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -870,6 +870,17 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
public static bool Match(this ILNode node, ILCode code, out ILExpression arg)
{
List<ILExpression> args;
if (node.Match(code, out args) && args.Count == 1) {
arg = args[0];
return true;
}
arg = null;
return false;
}
public static bool Match<T>(this ILNode node, ILCode code, out T operand, out List<ILExpression> args)
{
ILExpression expr = node as ILExpression;
@ -886,14 +897,27 @@ namespace ICSharpCode.Decompiler.ILAst @@ -886,14 +897,27 @@ namespace ICSharpCode.Decompiler.ILAst
public static bool Match<T>(this ILNode node, ILCode code, out T operand, out ILExpression arg)
{
List<ILExpression> args;
if (node.Match(code, out operand, out args)) {
arg = args.Single();
if (node.Match(code, out operand, out args) && args.Count == 1) {
arg = args[0];
return true;
}
arg = null;
return false;
}
public static bool Match<T>(this ILNode node, ILCode code, out T operand, out ILExpression arg1, out ILExpression arg2)
{
List<ILExpression> args;
if (node.Match(code, out operand, out args) && args.Count == 2) {
arg1 = args[0];
arg2 = args[1];
return true;
}
arg1 = null;
arg2 = null;
return false;
}
public static bool Match<T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel)
{
if (bb.Body.Count == 1) {
@ -910,7 +934,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -910,7 +934,6 @@ namespace ICSharpCode.Decompiler.ILAst
public static bool CanFallThough(this ILNode node)
{
// TODO: similar to ILCodes.CanFallThough, but handles slightly different cases??
ILExpression expr = node as ILExpression;
if (expr != null) {
return expr.Code.CanFallThough();

10
ICSharpCode.Decompiler/ILAst/Pattern.cs

@ -59,18 +59,20 @@ namespace ICSharpCode.Decompiler.ILAst @@ -59,18 +59,20 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
public class LoadFromThis : ILExpression
public class LoadFromArgument : ILExpression
{
public static readonly LoadFromThis Instance = new LoadFromThis();
int index;
public static readonly LoadFromArgument This = new LoadFromArgument(-1);
public LoadFromThis() : base(ILCode.Pattern, null)
public LoadFromArgument(int index) : base(ILCode.Pattern, null)
{
this.index = index;
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
return expr != null && expr.Code == ILCode.Ldarg && ((ParameterDefinition)expr.Operand).Index < 0;
return expr != null && expr.Code == ILCode.Ldarg && ((ParameterDefinition)expr.Operand).Index == index;
}
}

95
ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

@ -69,47 +69,51 @@ namespace ICSharpCode.Decompiler.ILAst @@ -69,47 +69,51 @@ namespace ICSharpCode.Decompiler.ILAst
{
if (method.Body.Count == 0)
return false;
ILExpression ret;
ILExpression newObj;
if (method.Body.Count == 1) {
// ret(newobj(...))
if (method.Body[0].Match(ILCode.Ret, out ret) && ret.Arguments.Count == 1)
return MatchEnumeratorCreationNewObj(ret.Arguments[0], out enumeratorCtor);
if (method.Body[0].Match(ILCode.Ret, out newObj))
return MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor);
else
return false;
}
// stloc(var_1, newobj(..)
ILExpression stloc;
if (!method.Body[0].Match(ILCode.Stloc, out stloc))
ILVariable var1;
if (!method.Body[0].Match(ILCode.Stloc, out var1, out newObj))
return false;
if (!MatchEnumeratorCreationNewObj(stloc.Arguments[0], out enumeratorCtor))
if (!MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor))
return false;
int i = 1;
ILExpression stfld;
while (i < method.Body.Count && method.Body[i].Match(ILCode.Stfld, out stfld)) {
int i;
for (i = 1; i < method.Body.Count; i++) {
// stfld(..., ldloc(var_1), ldarg(...))
FieldReference storedField;
ILExpression ldloc, ldarg;
if (!(stfld.Arguments[0].Match(ILCode.Ldloc, out ldloc) && stfld.Arguments[1].Match(ILCode.Ldarg, out ldarg)))
if (!method.Body[i].Match(ILCode.Stfld, out storedField, out ldloc, out ldarg))
break;
if (ldloc.Code != ILCode.Ldloc || ldarg.Code != ILCode.Ldarg)
return false;
if (ldloc.Operand != stloc.Operand || !(stfld.Operand is FieldDefinition))
if (ldloc.Operand != storedField || !(storedField is FieldDefinition))
return false;
fieldToParameterMap[(FieldDefinition)stfld.Operand] = (ParameterDefinition)ldarg.Operand;
i++;
fieldToParameterMap[(FieldDefinition)storedField] = (ParameterDefinition)ldarg.Operand;
}
ILExpression stloc2;
if (i < method.Body.Count && method.Body[i].Match(ILCode.Stloc, out stloc2)) {
ILVariable var2;
ILExpression ldlocForStloc2;
if (i < method.Body.Count && method.Body[i].Match(ILCode.Stloc, out var2, out ldlocForStloc2)) {
// stloc(var_2, ldloc(var_1))
if (stloc2.Arguments[0].Code != ILCode.Ldloc || stloc2.Arguments[0].Operand != stloc.Operand)
if (ldlocForStloc2.Code != ILCode.Ldloc || ldlocForStloc2.Operand != var1)
return false;
i++;
} else {
// the compiler might skip the above instruction in release builds; in that case, it directly returns stloc.Operand
stloc2 = stloc;
var2 = var1;
}
if (!SkipDummyBr(method, ref i))
return false;
if (i < method.Body.Count && method.Body[i].Match(ILCode.Ret, out ret)) {
if (ret.Arguments[0].Code == ILCode.Ldloc && ret.Arguments[0].Operand == stloc2.Operand) {
ILExpression retArg;
if (i < method.Body.Count && method.Body[i].Match(ILCode.Ret, out retArg)) {
// ret(ldloc(var_2))
if (retArg.Code == ILCode.Ldloc && retArg.Operand == var2) {
return true;
}
}
@ -118,9 +122,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -118,9 +122,9 @@ namespace ICSharpCode.Decompiler.ILAst
bool SkipDummyBr(ILBlock method, ref int i)
{
ILExpression br;
if (i + 1 < method.Body.Count && method.Body[i].Match(ILCode.Br, out br)) {
if (br.Operand != method.Body[i + 1])
ILLabel target;
if (i + 1 < method.Body.Count && method.Body[i].Match(ILCode.Br, out target)) {
if (target != method.Body[i + 1])
return false;
i += 2;
}
@ -154,13 +158,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -154,13 +158,12 @@ namespace ICSharpCode.Decompiler.ILAst
void AnalyzeCtor()
{
ILBlock method = CreateILAst(enumeratorCtor);
ILExpression stfldPattern = new ILExpression(ILCode.Stfld, ILExpression.AnyOperand, LoadFromArgument.This, new LoadFromArgument(0));
foreach (ILNode node in method.Body) {
ILExpression stfld;
if (node.Match(ILCode.Stfld, out stfld)
&& stfld.Arguments[0].Code == ILCode.Ldarg && ((ParameterDefinition)stfld.Arguments[0].Operand).Index < 0
&& stfld.Arguments[1].Code == ILCode.Ldarg && ((ParameterDefinition)stfld.Arguments[1].Operand).Index == 0)
{
stateField = stfld.Operand as FieldDefinition;
if (stfldPattern.Match(node)) {
stateField = ((ILExpression)node).Operand as FieldDefinition;
}
}
if (stateField == null)
@ -185,7 +188,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -185,7 +188,7 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
#region Figure out what the 'current' field is
static readonly ILExpression returnFieldFromThisPattern = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldfld, ILExpression.AnyOperand, LoadFromThis.Instance));
static readonly ILExpression returnFieldFromThisPattern = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldfld, ILExpression.AnyOperand, LoadFromArgument.This));
/// <summary>
/// Looks at the enumerator's get_Current method and figures out which of the fields holds the current value.
@ -202,7 +205,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -202,7 +205,7 @@ namespace ICSharpCode.Decompiler.ILAst
currentField = ((ILExpression)method.Body[0]).Arguments[0].Operand as FieldDefinition;
}
} else {
StoreToVariable v = new StoreToVariable(new ILExpression(ILCode.Ldfld, ILExpression.AnyOperand, LoadFromThis.Instance));
StoreToVariable v = new StoreToVariable(new ILExpression(ILCode.Ldfld, ILExpression.AnyOperand, LoadFromArgument.This));
if (v.Match(method.Body[0])) {
int i = 1;
if (SkipDummyBr(method, ref i) && i == method.Body.Count - 1) {
@ -228,7 +231,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -228,7 +231,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression mappingPattern = new ILExpression(
ILCode.Stfld, ILExpression.AnyOperand, new AnyILExpression(),
new ILExpression(ILCode.Ldfld, ILExpression.AnyOperand, LoadFromThis.Instance));
new ILExpression(ILCode.Ldfld, ILExpression.AnyOperand, LoadFromArgument.This));
ILBlock method = CreateILAst(getEnumeratorMethod);
foreach (ILNode node in method.Body) {
@ -506,16 +509,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -506,16 +509,16 @@ namespace ICSharpCode.Decompiler.ILAst
if (ilMethod.Body.Count == 0)
throw new YieldAnalysisFailedException();
ILExpression lastReturn;
if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturn))
ILExpression lastReturnArg;
if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg))
throw new YieldAnalysisFailedException();
ilMethod.Body.RemoveAll(n => n.Match(ILCode.Nop)); // remove nops
// There are two possibilities:
if (lastReturn.Arguments[0].Code == ILCode.Ldloc) {
if (lastReturnArg.Code == ILCode.Ldloc) {
// a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks)
returnVariable = (ILVariable)lastReturn.Arguments[0].Operand;
returnVariable = (ILVariable)lastReturnArg.Operand;
returnLabel = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel;
if (returnLabel == null)
throw new YieldAnalysisFailedException();
@ -524,7 +527,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -524,7 +527,7 @@ namespace ICSharpCode.Decompiler.ILAst
returnVariable = null;
returnLabel = null;
// In this case, the last return must return false.
if (lastReturn.Arguments[0].Code != ILCode.Ldc_I4 || (int)lastReturn.Arguments[0].Operand != 0)
if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0)
throw new YieldAnalysisFailedException();
}
@ -574,7 +577,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -574,7 +577,7 @@ namespace ICSharpCode.Decompiler.ILAst
throw new YieldAnalysisFailedException();
// Verify that the first instruction is a switch on this.state, and that the 2nd instruction is br
if (!new ILExpression(ILCode.Switch, ILExpression.AnyOperand, new ILExpression(ILCode.Ldfld, stateField, LoadFromThis.Instance)).Match(body[0]))
if (!new ILExpression(ILCode.Switch, ILExpression.AnyOperand, new ILExpression(ILCode.Ldfld, stateField, LoadFromArgument.This)).Match(body[0]))
throw new YieldAnalysisFailedException();
if (!body[1].Match(ILCode.Br))
@ -597,8 +600,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -597,8 +600,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression call;
if (!(faultBlock.Body.Count == 2 || faultBlock.Body.Count == 3))
throw new YieldAnalysisFailedException();
if (!faultBlock.Body[0].Match(ILCode.Call, out call) && call.Operand == disposeMethod
&& call.Arguments.Count == 1 && LoadFromThis.Instance.Match(call.Arguments[0]))
if (!new ILExpression(ILCode.Call, disposeMethod, LoadFromArgument.This).Match(faultBlock.Body[0]))
throw new YieldAnalysisFailedException();
if (faultBlock.Body.Count == 3 && !faultBlock.Body[1].Match(ILCode.Nop))
throw new YieldAnalysisFailedException();
@ -668,7 +670,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -668,7 +670,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Copy all instructions from the old body to newBody.
for (int pos = 2; pos < bodyLength; pos++) {
ILExpression expr = body[pos] as ILExpression;
if (expr != null && expr.Code == ILCode.Stfld && LoadFromThis.Instance.Match(expr.Arguments[0])) {
if (expr != null && expr.Code == ILCode.Stfld && LoadFromArgument.This.Match(expr.Arguments[0])) {
// Handle stores to 'state' or 'current'
if (expr.Operand == stateField) {
if (expr.Arguments[1].Code != ILCode.Ldc_I4)
@ -711,7 +713,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -711,7 +713,7 @@ namespace ICSharpCode.Decompiler.ILAst
} else {
throw new YieldAnalysisFailedException();
}
} else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && LoadFromThis.Instance.Match(expr.Arguments[0])) {
} else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && LoadFromArgument.This.Match(expr.Arguments[0])) {
MethodDefinition method = expr.Operand as MethodDefinition;
if (method == null)
throw new YieldAnalysisFailedException();
@ -764,9 +766,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -764,9 +766,10 @@ namespace ICSharpCode.Decompiler.ILAst
ILBlock block = CreateILAst(finallyMethod);
block.Body.RemoveAll(n => n.Match(ILCode.Nop));
// Get rid of assignment to state
ILExpression stfld;
if (block.Body.Count > 0 && block.Body[0].Match(ILCode.Stfld, out stfld)) {
if (stfld.Operand == stateField && LoadFromThis.Instance.Match(stfld.Arguments[0]))
FieldReference stfld;
List<ILExpression> args;
if (block.Body.Count > 0 && block.Body[0].Match(ILCode.Stfld, out stfld, out args)) {
if (stfld == stateField && LoadFromArgument.This.Match(args[0]))
block.Body.RemoveAt(0);
}
// Convert ret to endfinally
@ -788,7 +791,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -788,7 +791,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (field != null) {
switch (expr.Code) {
case ILCode.Ldfld:
if (LoadFromThis.Instance.Match(expr.Arguments[0])) {
if (LoadFromArgument.This.Match(expr.Arguments[0])) {
if (fieldToParameterMap.ContainsKey(field)) {
expr.Code = ILCode.Ldarg;
expr.Operand = fieldToParameterMap[field];
@ -800,7 +803,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -800,7 +803,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
break;
case ILCode.Stfld:
if (LoadFromThis.Instance.Match(expr.Arguments[0])) {
if (LoadFromArgument.This.Match(expr.Arguments[0])) {
if (fieldToParameterMap.ContainsKey(field)) {
expr.Code = ILCode.Starg;
expr.Operand = fieldToParameterMap[field];

Loading…
Cancel
Save