|
|
|
@ -16,6 +16,8 @@
@@ -16,6 +16,8 @@
|
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
using System.Linq; |
|
|
|
|
using ICSharpCode.Decompiler.FlowAnalysis; |
|
|
|
|
|
|
|
|
|
namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
@ -37,13 +39,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -37,13 +39,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
v.HasInitialValue = false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (function.IsIterator || function.IsAsync) { |
|
|
|
|
// In yield return + async, the C# compiler tends to store null/default(T) to variables
|
|
|
|
|
// when the variable goes out of scope. Remove such useless stores.
|
|
|
|
|
foreach (var v in function.Variables) { |
|
|
|
|
if (v.Kind == VariableKind.Local && v.StoreCount == 1 && v.LoadCount == 0 && v.AddressCount == 0) { |
|
|
|
|
if (v.StoreInstructions[0] is StLoc stloc && (stloc.Value.MatchLdNull() || stloc.Value is DefaultValue) && stloc.Parent is Block block) { |
|
|
|
|
// Remove dead stores to variables that are never read from.
|
|
|
|
|
// If the stored value has some side-effect, the value is unwrapped.
|
|
|
|
|
// 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.
|
|
|
|
|
var variableQueue = new Queue<ILVariable>(function.Variables.Where(v => v.Kind == VariableKind.Local || v.Kind == VariableKind.StackSlot)); |
|
|
|
|
while (variableQueue.Count > 0) { |
|
|
|
|
var v = variableQueue.Dequeue(); |
|
|
|
|
if (v.Kind != VariableKind.Local && v.Kind != VariableKind.StackSlot) |
|
|
|
|
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 (SemanticHelper.IsPure(stloc.Value.Flags)) { |
|
|
|
|
block.Instructions.Remove(stloc); |
|
|
|
|
} else { |
|
|
|
|
stloc.ReplaceWith(stloc.Value); |
|
|
|
|
} |
|
|
|
|
if (stloc.Value is LdLoc ldloc && (ldloc.Variable.Kind == VariableKind.Local || ldloc.Variable.Kind == VariableKind.StackSlot)) { |
|
|
|
|
variableQueue.Enqueue(ldloc.Variable); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|