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
return false; return false;
} }
public static bool MatchThis(this ILNode node)
{
ParameterDefinition parDef;
return node.Match(ILCode.Ldarg, out parDef) && parDef.Index == -1;
}
/// <summary> /// <summary>
/// Perform one pass of a given optimization on this block. /// Perform one pass of a given optimization on this block.
/// This block must consist of only basicblocks. /// This block must consist of only basicblocks.

80
ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

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

Loading…
Cancel
Save