Browse Source

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

pull/1953/head
Siegfried Pammer 6 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
oldParentChildren[oldChildIndex] = replacement; oldParentChildren[oldChildIndex] = replacement;
} }
// stloc valueTemporary(valueExpression) // stloc target(targetInst)
// stloc defaultTemporary(default.value type) // stloc defaultTemporary(default.value type)
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock { // if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc valueTemporary)) // stloc defaultTemporary(ldobj type(ldloc target))
// stloc valueTemporary(ldloca defaultTemporary) // stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock2 { // if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock2 {
// stloc resultTemporary(nullInst) // stloc resultTemporary(nullInst)
// br endBlock // br endBlock
// } // }
// } // }
// stloc resultTemporary(constrained[type].call_instruction(ldloc valueTemporary, ...)) // stloc resultTemporary(constrained[type].call_instruction(ldloc target, ...))
// br endBlock // 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- // -or-
// //
// stloc valueTemporary(valueExpression) // stloc target(targetInst)
// stloc defaultTemporary(default.value type) // stloc defaultTemporary(default.value type)
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock { // if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc valueTemporary)) // stloc defaultTemporary(ldobj type(ldloc target))
// stloc valueTemporary(ldloca defaultTemporary) // stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock2 { // if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock2 {
// leave(nullInst) // 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, 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; nonNullInst = null;
nullInst = null; nullInst = null;
endBlock = null; endBlock = null;
if (pos + 3 >= block.Instructions.Count) if (pos + 3 >= block.Instructions.Count)
return false; return false;
// stloc valueTemporary(valueExpression) // stloc target(...)
if (!block.Instructions[pos].MatchStLoc(out valueTemporary, out var value)) if (!block.Instructions[pos].MatchStLoc(out target, out _))
return false; 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; return false;
// stloc defaultTemporary(default.value type) // stloc defaultTemporary(default.value type)
if (!(block.Instructions[pos + 1].MatchStLoc(out var defaultTemporary, out var defaultExpression) && defaultExpression.MatchDefaultValue(out var 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
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock // 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))) if (!(block.Instructions[pos + 2].MatchIfInstruction(out var condition, out var fallbackBlock1) && condition.MatchCompEqualsNull(out var arg) && arg.MatchLdLoc(defaultTemporary)))
return false; return false;
if (!MatchStLocResultTemporary(block, pos, type, valueTemporary, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst, out endBlock) if (!MatchStLocResultTemporary(block, pos, type, target, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst, out endBlock)
&& !MatchLeaveResult(block, pos, type, valueTemporary, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst)) && !MatchLeaveResult(block, pos, type, target, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst))
return false; return false;
return true; return true;
} }
// stloc resultTemporary(constrained[type].call_instruction(ldloc valueTemporary, ...)) // stloc resultTemporary(constrained[type].call_instruction(ldloc target, ...))
// br endBlock // 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; endBlock = null;
nonNullInst = null; nonNullInst = null;
@ -415,54 +415,54 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (pos + 4 >= block.Instructions.Count) if (pos + 4 >= block.Instructions.Count)
return false; 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))) if (!(block.Instructions[pos + 3].MatchStLoc(out var resultTemporary, out nonNullInst)))
return false; return false;
// br endBlock // br endBlock
if (!(block.Instructions[pos + 4].MatchBranch(out endBlock))) if (!(block.Instructions[pos + 4].MatchBranch(out endBlock)))
return false; return false;
// Analyze Block fallbackBlock // 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 false;
return true; 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; nonNullInst = null;
nullInst = 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)) if (!(block.Instructions[pos + 3] is Leave leave && leave.IsLeavingFunction))
return false; return false;
nonNullInst = leave.Value; nonNullInst = leave.Value;
// Analyze Block fallbackBlock // 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 false;
return true; return true;
} }
// Block fallbackBlock { // Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc valueTemporary)) // stloc defaultTemporary(ldobj type(ldloc target))
// stloc valueTemporary(ldloca defaultTemporary) // stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock { // if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock {
// stloc resultTemporary(ldnull) // stloc resultTemporary(ldnull)
// br endBlock // 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; nullInst = null;
if (!(block.Instructions.Count == 3)) if (!(block.Instructions.Count == 3))
return false; return false;
// stloc defaultTemporary(ldobj type(ldloc valueTemporary)) // stloc defaultTemporary(ldobj type(ldloc target))
if (!(block.Instructions[0].MatchStLoc(defaultTemporary, out var valueExpression))) if (!(block.Instructions[0].MatchStLoc(defaultTemporary, out var value)))
return false; 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; return false;
// stloc valueTemporary(ldloca defaultTemporary) // stloc target(ldloca defaultTemporary)
if (!(block.Instructions[1].MatchStLoc(valueTemporary, out var defaultAddress) && defaultAddress.MatchLdLoca(defaultTemporary))) if (!(block.Instructions[1].MatchStLoc(target, out var defaultAddress) && defaultAddress.MatchLdLoca(defaultTemporary)))
return false; return false;
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock // 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))) if (!(block.Instructions[2].MatchIfInstruction(out var condition, out var tmp) && condition.MatchCompEqualsNull(out var arg) && arg.MatchLdLoc(defaultTemporary)))

Loading…
Cancel
Save