|
|
|
@ -42,41 +42,44 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -42,41 +42,44 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
// This is necessary to remove useless stores generated by some compilers, e.g., the F# compiler.
|
|
|
|
|
// In yield return + async, the C# compiler tends to store null/default(T) to variables
|
|
|
|
|
// when the variable goes out of scope.
|
|
|
|
|
if (function.IsAsync || function.IsIterator || context.Settings.RemoveDeadStores) |
|
|
|
|
bool removeDeadStores = function.IsAsync || function.IsIterator || context.Settings.RemoveDeadStores; |
|
|
|
|
|
|
|
|
|
var variableQueue = new Queue<ILVariable>(function.Variables); |
|
|
|
|
while (variableQueue.Count > 0) |
|
|
|
|
{ |
|
|
|
|
var variableQueue = new Queue<ILVariable>(function.Variables); |
|
|
|
|
while (variableQueue.Count > 0) |
|
|
|
|
var v = variableQueue.Dequeue(); |
|
|
|
|
if (v.Kind != VariableKind.Local && v.Kind != VariableKind.StackSlot) |
|
|
|
|
continue; |
|
|
|
|
if (!(v.RemoveIfRedundant || removeDeadStores)) |
|
|
|
|
continue; |
|
|
|
|
// Skip variables that are captured in a mcs yield state-machine
|
|
|
|
|
// loads of these will only be visible after DelegateConstruction step.
|
|
|
|
|
if (function.StateMachineCompiledWithMono && v.StateMachineField != null) |
|
|
|
|
continue; |
|
|
|
|
if (v.LoadCount != 0 || v.AddressCount != 0) |
|
|
|
|
continue; |
|
|
|
|
foreach (var stloc in v.StoreInstructions.OfType<StLoc>().ToArray()) |
|
|
|
|
{ |
|
|
|
|
var v = variableQueue.Dequeue(); |
|
|
|
|
if (v.Kind != VariableKind.Local && v.Kind != VariableKind.StackSlot) |
|
|
|
|
continue; |
|
|
|
|
// Skip variables that are captured in a mcs yield state-machine
|
|
|
|
|
// loads of these will only be visible after DelegateConstruction step.
|
|
|
|
|
if (function.StateMachineCompiledWithMono && v.StateMachineField != null) |
|
|
|
|
continue; |
|
|
|
|
if (v.LoadCount != 0 || v.AddressCount != 0) |
|
|
|
|
continue; |
|
|
|
|
foreach (var stloc in v.StoreInstructions.OfType<StLoc>().ToArray()) |
|
|
|
|
if (stloc.Parent is Block block) |
|
|
|
|
{ |
|
|
|
|
if (stloc.Parent is Block block) |
|
|
|
|
context.Step($"Dead store to {v.Name}", stloc); |
|
|
|
|
if (SemanticHelper.IsPure(stloc.Value.Flags)) |
|
|
|
|
{ |
|
|
|
|
block.Instructions.Remove(stloc); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if (SemanticHelper.IsPure(stloc.Value.Flags)) |
|
|
|
|
{ |
|
|
|
|
block.Instructions.Remove(stloc); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
stloc.ReplaceWith(stloc.Value); |
|
|
|
|
} |
|
|
|
|
if (stloc.Value is LdLoc ldloc) |
|
|
|
|
{ |
|
|
|
|
variableQueue.Enqueue(ldloc.Variable); |
|
|
|
|
} |
|
|
|
|
stloc.ReplaceWith(stloc.Value); |
|
|
|
|
} |
|
|
|
|
if (stloc.Value is LdLoc ldloc) |
|
|
|
|
{ |
|
|
|
|
variableQueue.Enqueue(ldloc.Variable); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try to infer IType of stack slots that are of StackType.Ref:
|
|
|
|
|
foreach (var v in function.Variables) |
|
|
|
|
{ |
|
|
|
|