Browse Source

Use the simple pattern matching in yield return

pull/100/head
David Srbecký 15 years ago
parent
commit
05b3bfbff2
  1. 6
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  2. 80
      ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

6
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -731,6 +731,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -731,6 +731,12 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
public static bool MatchThis(this ILNode node)
{
ParameterDefinition parDef;
return node.Match(ILCode.Ldarg, out parDef) && parDef.Index == -1;
}
/// <summary>
/// Perform one pass of a given optimization on this block.
/// This block must consist of only basicblocks.

80
ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

@ -181,11 +181,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -181,11 +181,17 @@ namespace ICSharpCode.Decompiler.ILAst
{
ILBlock method = CreateILAst(enumeratorCtor);
ILExpression stfldPattern = new ILExpression(ILCode.Stfld, ILExpression.AnyOperand, LoadFromArgument.This, new LoadFromArgument(0));
foreach (ILNode node in method.Body) {
if (stfldPattern.Match(node)) {
stateField = GetFieldDefinition(((ILExpression)node).Operand as FieldReference);
FieldReference field;
ILExpression instExpr;
ILExpression stExpr;
ParameterDefinition arg;
if (node.Match(ILCode.Stfld, out field, out instExpr, out stExpr) &&
instExpr.MatchThis() &&
stExpr.Match(ILCode.Ldarg, out arg) &&
arg.Index == 0)
{
stateField = GetFieldDefinition(field);
}
}
if (stateField == null)
@ -210,8 +216,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -210,8 +216,6 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
#region Figure out what the 'current' field is (analysis of get_Current())
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.
/// </summary>
@ -223,18 +227,29 @@ namespace ICSharpCode.Decompiler.ILAst @@ -223,18 +227,29 @@ namespace ICSharpCode.Decompiler.ILAst
ILBlock method = CreateILAst(getCurrentMethod);
if (method.Body.Count == 1) {
// release builds directly return the current field
if (returnFieldFromThisPattern.Match(method.Body[0])) {
currentField = GetFieldDefinition(((ILExpression)method.Body[0]).Arguments[0].Operand as FieldReference);
ILExpression retExpr;
FieldReference field;
ILExpression ldFromObj;
if (method.Body[0].Match(ILCode.Ret, out retExpr) &&
retExpr.Match(ILCode.Ldfld, out field, out ldFromObj) &&
ldFromObj.MatchThis())
{
currentField = GetFieldDefinition(field);
}
} else {
StoreToVariable v = new StoreToVariable(new ILExpression(ILCode.Ldfld, ILExpression.AnyOperand, LoadFromArgument.This));
if (v.Match(method.Body[0])) {
int i = 1;
if (i == method.Body.Count - 1) {
if (new ILExpression(ILCode.Ret, null, new LoadFromVariable(v)).Match(method.Body[i])) {
currentField = GetFieldDefinition(((ILExpression)method.Body[0]).Arguments[0].Operand as FieldReference);
}
}
} else if (method.Body.Count == 2) {
ILVariable v, v2;
ILExpression stExpr;
FieldReference field;
ILExpression ldFromObj;
ILExpression retExpr;
if (method.Body[0].Match(ILCode.Stloc, out v, out stExpr) &&
stExpr.Match(ILCode.Ldfld, out field, out ldFromObj) &&
ldFromObj.MatchThis() &&
method.Body[1].Match(ILCode.Ret, out retExpr) &&
retExpr.Match(ILCode.Ldloc, out v2) &&
v == v2)
{
currentField = GetFieldDefinition(field);
}
}
if (currentField == null)
@ -251,16 +266,19 @@ namespace ICSharpCode.Decompiler.ILAst @@ -251,16 +266,19 @@ namespace ICSharpCode.Decompiler.ILAst
if (getEnumeratorMethod == null)
return; // no mappings (maybe it's just an IEnumerator implementation?)
ILExpression mappingPattern = new ILExpression(
ILCode.Stfld, ILExpression.AnyOperand, new AnyILExpression(),
new ILExpression(ILCode.Ldfld, ILExpression.AnyOperand, LoadFromArgument.This));
ILBlock method = CreateILAst(getEnumeratorMethod);
foreach (ILNode node in method.Body) {
if (mappingPattern.Match(node)) {
ILExpression stfld = (ILExpression)node;
FieldDefinition storedField = GetFieldDefinition(stfld.Operand as FieldReference);
FieldDefinition loadedField = GetFieldDefinition(stfld.Arguments[1].Operand as FieldReference);
FieldReference stField;
ILExpression stToObj;
ILExpression stExpr;
FieldReference ldField;
ILExpression ldFromObj;
if (node.Match(ILCode.Stfld, out stField, out stToObj, out stExpr) &&
stExpr.Match(ILCode.Ldfld, out ldField, out ldFromObj) &&
ldFromObj.MatchThis())
{
FieldDefinition storedField = GetFieldDefinition(stField);
FieldDefinition loadedField = GetFieldDefinition(ldField);
if (storedField != null && loadedField != null) {
ParameterDefinition mappedParameter;
if (fieldToParameterMap.TryGetValue(loadedField, out mappedParameter))
@ -671,7 +689,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -671,7 +689,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression disposeArg;
if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg))
throw new YieldAnalysisFailedException();
if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !LoadFromArgument.This.Match(disposeArg))
if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !disposeArg.MatchThis())
throw new YieldAnalysisFailedException();
if (!faultBlock.Body[1].Match(ILCode.Endfinally))
throw new YieldAnalysisFailedException();
@ -757,7 +775,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -757,7 +775,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Copy all instructions from the old body to newBody.
for (int pos = startPos; pos < bodyLength; pos++) {
ILExpression expr = body[pos] as ILExpression;
if (expr != null && expr.Code == ILCode.Stfld && LoadFromArgument.This.Match(expr.Arguments[0])) {
if (expr != null && expr.Code == ILCode.Stfld && expr.Arguments[0].MatchThis()) {
// Handle stores to 'state' or 'current'
if (GetFieldDefinition(expr.Operand as FieldReference) == stateField) {
if (expr.Arguments[1].Code != ILCode.Ldc_I4)
@ -794,7 +812,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -794,7 +812,7 @@ namespace ICSharpCode.Decompiler.ILAst
} else {
throw new YieldAnalysisFailedException();
}
} else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && LoadFromArgument.This.Match(expr.Arguments[0])) {
} else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && expr.Arguments[0].MatchThis()) {
MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference);
if (method == null)
throw new YieldAnalysisFailedException();
@ -857,7 +875,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -857,7 +875,7 @@ namespace ICSharpCode.Decompiler.ILAst
FieldReference stfld;
List<ILExpression> args;
if (block.Body.Count > 0 && block.Body[0].Match(ILCode.Stfld, out stfld, out args)) {
if (GetFieldDefinition(stfld) == stateField && LoadFromArgument.This.Match(args[0]))
if (GetFieldDefinition(stfld) == stateField && args[0].MatchThis())
block.Body.RemoveAt(0);
}
// Convert ret to endfinally
@ -879,7 +897,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -879,7 +897,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (field != null) {
switch (expr.Code) {
case ILCode.Ldfld:
if (LoadFromArgument.This.Match(expr.Arguments[0])) {
if (expr.Arguments[0].MatchThis()) {
if (fieldToParameterMap.ContainsKey(field)) {
expr.Code = ILCode.Ldarg;
expr.Operand = fieldToParameterMap[field];
@ -891,7 +909,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -891,7 +909,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
break;
case ILCode.Stfld:
if (LoadFromArgument.This.Match(expr.Arguments[0])) {
if (expr.Arguments[0].MatchThis()) {
if (fieldToParameterMap.ContainsKey(field)) {
expr.Code = ILCode.Starg;
expr.Operand = fieldToParameterMap[field];

Loading…
Cancel
Save