|
|
|
@ -589,6 +589,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -589,6 +589,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
} else if (expr is Block block) { |
|
|
|
|
// Inlining into inline-blocks?
|
|
|
|
|
switch (block.Kind) { |
|
|
|
|
case BlockKind.ControlFlow when block.Parent is BlockContainer: |
|
|
|
|
case BlockKind.ArrayInitializer: |
|
|
|
|
case BlockKind.CollectionInitializer: |
|
|
|
|
case BlockKind.ObjectInitializer: |
|
|
|
@ -604,19 +605,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -604,19 +605,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
default: |
|
|
|
|
return FindResult.Stop; |
|
|
|
|
} |
|
|
|
|
} else if (expr is BlockContainer container && container.EntryPoint.IncomingEdgeCount == 1) { |
|
|
|
|
// Possibly a switch-container, allow inlining into the switch instruction:
|
|
|
|
|
return NoContinue(FindLoadInNext(container.EntryPoint.Instructions[0], v, expressionBeingMoved, options)); |
|
|
|
|
// If FindLoadInNext() returns null, we still can't continue searching
|
|
|
|
|
// because we can't inline over the remainder of the blockcontainer.
|
|
|
|
|
} else if (expr is NullableRewrap) { |
|
|
|
|
// Inlining into nullable.rewrap is OK unless the expression being inlined
|
|
|
|
|
// contains a nullable.wrap that isn't being re-wrapped within the expression being inlined.
|
|
|
|
|
if (expressionBeingMoved.HasFlag(InstructionFlags.MayUnwrapNull)) |
|
|
|
|
return FindResult.Stop; |
|
|
|
|
} |
|
|
|
|
foreach (var child in expr.Children) { |
|
|
|
|
if (!child.SlotInfo.CanInlineInto) |
|
|
|
|
if (!expr.CanInlineIntoSlot(child.ChildIndex, expressionBeingMoved)) |
|
|
|
|
return FindResult.Stop; |
|
|
|
|
|
|
|
|
|
// Recursively try to find the load instruction
|
|
|
|
@ -666,24 +657,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -666,24 +657,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets whether arg can be un-inlined out of stmt.
|
|
|
|
|
/// Gets whether 'expressionBeingMoved' can be moved from somewhere before 'stmt' to become the replacement of 'targetLoad'.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <seealso cref="ILInstruction.Extract"/>
|
|
|
|
|
internal static bool CanUninline(ILInstruction arg, ILInstruction stmt) |
|
|
|
|
public static bool CanMoveInto(ILInstruction expressionBeingMoved, ILInstruction stmt, ILInstruction targetLoad) |
|
|
|
|
{ |
|
|
|
|
Debug.Assert(arg.IsDescendantOf(stmt)); |
|
|
|
|
for (ILInstruction inst = arg; inst != stmt; inst = inst.Parent) { |
|
|
|
|
if (!inst.SlotInfo.CanInlineInto) |
|
|
|
|
Debug.Assert(targetLoad.IsDescendantOf(stmt)); |
|
|
|
|
for (ILInstruction inst = targetLoad; inst != stmt; inst = inst.Parent) { |
|
|
|
|
if (!inst.Parent.CanInlineIntoSlot(inst.ChildIndex, expressionBeingMoved)) |
|
|
|
|
return false; |
|
|
|
|
// Check whether re-ordering with predecessors is valid:
|
|
|
|
|
int childIndex = inst.ChildIndex; |
|
|
|
|
for (int i = 0; i < childIndex; ++i) { |
|
|
|
|
ILInstruction predecessor = inst.Parent.Children[i]; |
|
|
|
|
if (!SemanticHelper.MayReorder(arg, predecessor)) |
|
|
|
|
if (!IsSafeForInlineOver(predecessor, expressionBeingMoved)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets whether arg can be un-inlined out of stmt.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <seealso cref="ILInstruction.Extract"/>
|
|
|
|
|
internal static bool CanUninline(ILInstruction arg, ILInstruction stmt) |
|
|
|
|
{ |
|
|
|
|
// moving into and moving out-of are equivalent
|
|
|
|
|
return CanMoveInto(arg, stmt, arg); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|