Browse Source

Make sure that the code and the pattern described in the comment above are in sync.

pull/1953/head
Siegfried Pammer 5 years ago
parent
commit
5711185832
  1. 64
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

64
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -347,48 +347,48 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -347,48 +347,48 @@ namespace ICSharpCode.Decompiler.IL.Transforms
oldParentChildren[oldChildIndex] = replacement;
}
// stloc valueTemporary(valueExpression)
// stloc target(targetInst)
// stloc defaultTemporary(default.value type)
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc valueTemporary))
// stloc valueTemporary(ldloca defaultTemporary)
// stloc defaultTemporary(ldobj type(ldloc target))
// stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock2 {
// stloc resultTemporary(nullInst)
// br endBlock
// }
// }
// stloc resultTemporary(constrained[type].call_instruction(ldloc valueTemporary, ...))
// stloc resultTemporary(constrained[type].call_instruction(ldloc target, ...))
// br endBlock
// =>
// stloc resultTemporary(nullable.rewrap(constrained[type].call_instruction(nullable.unwrap(valueExpression), ...)))
// stloc resultTemporary(nullable.rewrap(constrained[type].call_instruction(nullable.unwrap(targetInst), ...)))
//
// -or-
//
// stloc valueTemporary(valueExpression)
// stloc target(targetInst)
// stloc defaultTemporary(default.value type)
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc valueTemporary))
// stloc valueTemporary(ldloca defaultTemporary)
// stloc defaultTemporary(ldobj type(ldloc target))
// stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock2 {
// leave(nullInst)
// }
// }
// leave (constrained[type].call_instruction(ldloc valueTemporary, ...))
// leave (constrained[type].call_instruction(ldloc target, ...))
// =>
// leave (nullable.rewrap(constrained[type].call_instruction(nullable.unwrap(valueExpression), ...)))
// leave (nullable.rewrap(constrained[type].call_instruction(nullable.unwrap(targetInst), ...)))
private bool TransformNullPropagationOnUnconstrainedGenericExpression(Block block, int pos,
out ILVariable valueTemporary, out ILInstruction nonNullInst, out ILInstruction nullInst, out Block endBlock)
out ILVariable target, out ILInstruction nonNullInst, out ILInstruction nullInst, out Block endBlock)
{
valueTemporary = null;
target = null;
nonNullInst = null;
nullInst = null;
endBlock = null;
if (pos + 3 >= block.Instructions.Count)
return false;
// stloc valueTemporary(valueExpression)
if (!block.Instructions[pos].MatchStLoc(out valueTemporary, out var value))
// stloc target(...)
if (!block.Instructions[pos].MatchStLoc(out target, out _))
return false;
if (!(valueTemporary.Kind == VariableKind.StackSlot && valueTemporary.LoadCount == 2 && valueTemporary.StoreCount == 2))
if (!(target.Kind == VariableKind.StackSlot && target.LoadCount == 2 && target.StoreCount == 2))
return false;
// stloc defaultTemporary(default.value type)
if (!(block.Instructions[pos + 1].MatchStLoc(out var defaultTemporary, out var defaultExpression) && defaultExpression.MatchDefaultValue(out var type)))
@ -399,15 +399,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -399,15 +399,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock
if (!(block.Instructions[pos + 2].MatchIfInstruction(out var condition, out var fallbackBlock1) && condition.MatchCompEqualsNull(out var arg) && arg.MatchLdLoc(defaultTemporary)))
return false;
if (!MatchStLocResultTemporary(block, pos, type, valueTemporary, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst, out endBlock)
&& !MatchLeaveResult(block, pos, type, valueTemporary, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst))
if (!MatchStLocResultTemporary(block, pos, type, target, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst, out endBlock)
&& !MatchLeaveResult(block, pos, type, target, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst))
return false;
return true;
}
// stloc resultTemporary(constrained[type].call_instruction(ldloc valueTemporary, ...))
// stloc resultTemporary(constrained[type].call_instruction(ldloc target, ...))
// br endBlock
private bool MatchStLocResultTemporary(Block block, int pos, IType type, ILVariable valueTemporary, ILVariable defaultTemporary, ILInstruction fallbackBlock, out ILInstruction nonNullInst, out ILInstruction nullInst, out Block endBlock)
private bool MatchStLocResultTemporary(Block block, int pos, IType type, ILVariable target, ILVariable defaultTemporary, ILInstruction fallbackBlock, out ILInstruction nonNullInst, out ILInstruction nullInst, out Block endBlock)
{
endBlock = null;
nonNullInst = null;
@ -415,54 +415,54 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -415,54 +415,54 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (pos + 4 >= block.Instructions.Count)
return false;
// stloc resultTemporary(constrained[type].call_instruction(ldloc valueTemporary, ...))
// stloc resultTemporary(constrained[type].call_instruction(ldloc target, ...))
if (!(block.Instructions[pos + 3].MatchStLoc(out var resultTemporary, out nonNullInst)))
return false;
// br endBlock
if (!(block.Instructions[pos + 4].MatchBranch(out endBlock)))
return false;
// Analyze Block fallbackBlock
if (!(fallbackBlock is Block b && IsFallbackBlock(b, type, valueTemporary, defaultTemporary, resultTemporary, endBlock, out nullInst)))
if (!(fallbackBlock is Block b && IsFallbackBlock(b, type, target, defaultTemporary, resultTemporary, endBlock, out nullInst)))
return false;
return true;
}
private bool MatchLeaveResult(Block block, int pos, IType type, ILVariable valueTemporary, ILVariable defaultTemporary, ILInstruction fallbackBlock, out ILInstruction nonNullInst, out ILInstruction nullInst)
private bool MatchLeaveResult(Block block, int pos, IType type, ILVariable target, ILVariable defaultTemporary, ILInstruction fallbackBlock, out ILInstruction nonNullInst, out ILInstruction nullInst)
{
nonNullInst = null;
nullInst = null;
// leave (constrained[type].call_instruction(ldloc valueTemporary, ...))
// leave (constrained[type].call_instruction(ldloc target, ...))
if (!(block.Instructions[pos + 3] is Leave leave && leave.IsLeavingFunction))
return false;
nonNullInst = leave.Value;
// Analyze Block fallbackBlock
if (!(fallbackBlock is Block b && IsFallbackBlock(b, type, valueTemporary, defaultTemporary, null, leave.TargetContainer, out nullInst)))
if (!(fallbackBlock is Block b && IsFallbackBlock(b, type, target, defaultTemporary, null, leave.TargetContainer, out nullInst)))
return false;
return true;
}
// Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc valueTemporary))
// stloc valueTemporary(ldloca defaultTemporary)
// stloc defaultTemporary(ldobj type(ldloc target))
// stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock {
// stloc resultTemporary(ldnull)
// br endBlock
// }
// }
private bool IsFallbackBlock(Block block, IType type, ILVariable valueTemporary, ILVariable defaultTemporary, ILVariable resultTemporary, ILInstruction endBlockOrLeaveContainer, out ILInstruction nullInst)
private bool IsFallbackBlock(Block block, IType type, ILVariable target, ILVariable defaultTemporary, ILVariable resultTemporary, ILInstruction endBlockOrLeaveContainer, out ILInstruction nullInst)
{
nullInst = null;
if (!(block.Instructions.Count == 3))
return false;
// stloc defaultTemporary(ldobj type(ldloc valueTemporary))
if (!(block.Instructions[0].MatchStLoc(defaultTemporary, out var valueExpression)))
// stloc defaultTemporary(ldobj type(ldloc target))
if (!(block.Instructions[0].MatchStLoc(defaultTemporary, out var value)))
return false;
if (!(valueExpression.MatchLdObj(out var target, out var t) && type.Equals(t) && target.MatchLdLoc(valueTemporary)))
if (!(value.MatchLdObj(out var inst, out var t) && type.Equals(t) && inst.MatchLdLoc(target)))
return false;
// stloc valueTemporary(ldloca defaultTemporary)
if (!(block.Instructions[1].MatchStLoc(valueTemporary, out var defaultAddress) && defaultAddress.MatchLdLoca(defaultTemporary)))
// stloc target(ldloca defaultTemporary)
if (!(block.Instructions[1].MatchStLoc(target, out var defaultAddress) && defaultAddress.MatchLdLoca(defaultTemporary)))
return false;
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock
if (!(block.Instructions[2].MatchIfInstruction(out var condition, out var tmp) && condition.MatchCompEqualsNull(out var arg) && arg.MatchLdLoc(defaultTemporary)))

Loading…
Cancel
Save