Browse Source

[async] Handle pre-roslyn stack saving during await.

pull/850/head
Daniel Grunwald 8 years ago
parent
commit
098d1152ff
  1. 65
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

65
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -648,9 +648,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -648,9 +648,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return;
if (awaitBlockData.awaiterVar != awaiterVar)
return;
if (!CheckAwaitBlock(awaitBlock, out var resumeBlock))
if (!CheckAwaitBlock(awaitBlock, out var resumeBlock, out var stackField))
return;
if (!CheckResumeBlock(resumeBlock, awaiterVar, awaitBlockData.awaiterField, completedBlock))
if (!CheckResumeBlock(resumeBlock, awaiterVar, awaitBlockData.awaiterField, completedBlock, stackField))
return;
// Check completedBlock:
ILInstruction getResultCall;
@ -685,25 +685,38 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -685,25 +685,38 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
}
}
}
bool CheckAwaitBlock(Block block, out Block resumeBlock)
bool CheckAwaitBlock(Block block, out Block resumeBlock, out IField stackField)
{
// awaitBlock:
// (pre-roslyn: save stack)
// await(ldloca V_2)
// br resumeBlock
resumeBlock = null;
if (block.Instructions.Count != 2)
return false;
if (block.Instructions[0].OpCode != OpCode.Await)
stackField = null;
if (block.Instructions.Count < 2)
return false;
if (!block.Instructions[1].MatchBranch(out resumeBlock))
int pos = 0;
if (block.Instructions[pos] is StLoc stloc && stloc.Variable.IsSingleDefinition) {
if (!block.Instructions[pos + 1].MatchStFld(out var target, out stackField, out var value))
return false;
if (!target.MatchLdThis())
return false;
pos += 2;
}
// await(ldloca awaiterVar)
if (block.Instructions[pos].OpCode != OpCode.Await)
return false;
return true;
// br resumeBlock
return block.Instructions[pos + 1].MatchBranch(out resumeBlock);
}
bool CheckResumeBlock(Block block, ILVariable awaiterVar, IField awaiterField, Block completedBlock)
bool CheckResumeBlock(Block block, ILVariable awaiterVar, IField awaiterField, Block completedBlock, IField stackField)
{
int pos = 0;
if (!RestoreStack(block, ref pos, stackField))
return false;
// stloc awaiterVar(ldfld awaiterField(ldloc this))
if (!block.Instructions[pos].MatchStLoc(awaiterVar, out var value))
return false;
@ -752,6 +765,38 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -752,6 +765,38 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return block.Instructions[pos].MatchBranch(completedBlock);
}
private bool RestoreStack(Block block, ref int pos, IField stackField)
{
if (stackField == null) {
return true; // nothing to restore
}
// stloc temp(unbox.any T(ldfld <>t__stack(ldloc this)))
if (!(block.Instructions[pos] is StLoc stloc))
return false;
if (!stloc.Variable.IsSingleDefinition)
return false;
if (!(stloc.Value is UnboxAny unbox))
return false;
if (!unbox.Argument.MatchLdFld(out var target, out var field))
return false;
if (!target.MatchLdThis())
return false;
if (!field.Equals(stackField))
return false;
pos++;
// restoring stack slots
while (block.Instructions[pos].MatchStLoc(out var v) && v.Kind == VariableKind.StackSlot) {
pos++;
}
// stfld <>t__stack(ldloc this, ldnull)
if (block.Instructions[pos].MatchStFld(out target, out field, out var value)) {
if (target.MatchLdThis() && field.Equals(stackField) && value.MatchLdNull()) {
pos++;
}
}
return true;
}
#endregion
void MarkGeneratedVariables(ILFunction function)

Loading…
Cancel
Save