Browse Source

SplitVariables: analyze address usage in virtual calls as well. Treat them the same as call instructions.

pull/1253/head
Siegfried Pammer 7 years ago
parent
commit
b701bed2ff
  1. 45
      ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs

45
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<int>" 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<int>" 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;
}
/// <summary>
/// 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.

Loading…
Cancel
Save