From b701bed2ff8b50caf28d0f13dab2997f0fc55d8d Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 10 Aug 2018 12:20:20 +0200 Subject: [PATCH] SplitVariables: analyze address usage in virtual calls as well. Treat them the same as call instructions. --- .../IL/Transforms/SplitVariables.cs | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs b/ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs index 67cccc27f..8a67acc01 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs @@ -105,25 +105,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms // GetAwaiter() may write to the struct, but shouldn't store the address for later use return AddressUse.Immediate; case Call call: - // Address is passed to method. - // We'll assume the method only uses the address locally, - // unless we can see an address being returned from the method: - if (call.Method.ReturnType.IsByRefLike) { - return AddressUse.Unknown; - } - foreach (var p in call.Method.Parameters) { - // catch "out Span" and similar - if (p.Type.SkipModifiers() is ByReferenceType brt && brt.ElementType.IsByRefLike) - return AddressUse.Unknown; - } - // ensure there's no 'stloc target' in between the ldloca and the call consuming the address - for (int i = addressLoadingInstruction.ChildIndex + 1; i < call.Arguments.Count; i++) { - foreach (var inst in call.Arguments[i].Descendants) { - if (inst is StLoc store && store.Variable == targetVar) - return AddressUse.Unknown; - } - } - return AddressUse.Immediate; + return HandleCall(addressLoadingInstruction, targetVar, call); + case CallVirt call: + return HandleCall(addressLoadingInstruction, targetVar, call); case StLoc stloc when stloc.Variable.IsSingleDefinition: // Address stored in local variable: also check all uses of that variable. if (!(stloc.Variable.Kind == VariableKind.StackSlot || stloc.Variable.Kind == VariableKind.Local)) @@ -142,6 +126,29 @@ namespace ICSharpCode.Decompiler.IL.Transforms } } + static AddressUse HandleCall(ILInstruction addressLoadingInstruction, ILVariable targetVar, CallInstruction call) + { + // Address is passed to method. + // We'll assume the method only uses the address locally, + // unless we can see an address being returned from the method: + if (call.Method.ReturnType.IsByRefLike) { + return AddressUse.Unknown; + } + foreach (var p in call.Method.Parameters) { + // catch "out Span" and similar + if (p.Type.SkipModifiers() is ByReferenceType brt && brt.ElementType.IsByRefLike) + return AddressUse.Unknown; + } + // ensure there's no 'stloc target' in between the ldloca and the call consuming the address + for (int i = addressLoadingInstruction.ChildIndex + 1; i < call.Arguments.Count; i++) { + foreach (var inst in call.Arguments[i].Descendants) { + if (inst is StLoc store && store.Variable == targetVar) + return AddressUse.Unknown; + } + } + return AddressUse.Immediate; + } + /// /// Given 'ldloc ref_local' and 'ldloca target; stloc ref_local', returns the ldloca. /// This function must return a non-null LdLoca for every use of a SupportedRefLocal.