From b7d2eec41d341b2f33438f661fed2b9e357f9eba Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 25 Oct 2020 19:47:18 +0100 Subject: [PATCH] #2199: Add support for VB cached delegate initialization --- .../CSharp/StatementBuilder.cs | 1 - .../CachedDelegateInitialization.cs | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 6c9419110..9b450abfd 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -1315,7 +1315,6 @@ namespace ICSharpCode.Decompiler.CSharp { method.Modifiers |= Modifiers.Extern; } - CSharpDecompiler.CleanUpMethodDeclaration(method, method.Body, function, function.Method.HasBody); CSharpDecompiler.RemoveAttribute(method, KnownAttribute.CompilerGenerated); diff --git a/ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs b/ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs index 08148b64b..b16254a91 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/CachedDelegateInitialization.cs @@ -51,6 +51,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms block.Instructions.RemoveAt(i); continue; } + if (CachedDelegateInitializationVB(inst)) + { + continue; + } } } } @@ -189,5 +193,48 @@ namespace ICSharpCode.Decompiler.IL.Transforms storeBeforeIf.Value = stobj.Value; return true; } + + /// + /// if (comp.i4(comp.o(ldobj delegateType(ldsflda CachedAnonMethodDelegate) != ldnull) == ldc.i4 0)) Block { + /// stloc s(stobj(ldflda(CachedAnonMethodDelegate), DelegateConstruction)) + /// } else Block { + /// stloc s(ldobj System.Action(ldsflda $I4-1)) + /// } + /// => + /// stloc s(DelegateConstruction) + /// + bool CachedDelegateInitializationVB(IfInstruction inst) + { + if (!(inst.TrueInst is Block trueInst && inst.FalseInst is Block falseInst)) + return false; + if (trueInst.Instructions.Count != 1 || falseInst.Instructions.Count != 1) + return false; + if (!(trueInst.Instructions[0].MatchStLoc(out var s, out var trueInitValue) + && falseInst.Instructions[0].MatchStLoc(s, out var falseInitValue))) + { + return false; + } + if (s.Kind != VariableKind.StackSlot || s.StoreCount != 2 || s.LoadCount != 1) + return false; + if (!(trueInitValue is StObj stobj) || !(falseInitValue is LdObj ldobj)) + return false; + if (!(stobj.Value is NewObj delegateConstruction)) + return false; + if (!stobj.Target.MatchLdsFlda(out var field1) + || !ldobj.Target.MatchLdsFlda(out var field2) + || !field1.Equals(field2)) + { + return false; + } + if (!inst.Condition.MatchCompEquals(out ILInstruction left, out ILInstruction right) || !right.MatchLdNull()) + return false; + if (!ldobj.Match(left).Success) + return false; + if (!DelegateConstruction.MatchDelegateConstruction(delegateConstruction, out _, out _, out _, true)) + return false; + context.Step("CachedDelegateInitializationVB", inst); + inst.ReplaceWith(new StLoc(s, delegateConstruction)); + return true; + } } }