Browse Source

Performance: Cache ChainedConstructorCallILOffset in ILFunction to avoid having to scan the method body in every inlining step. Take a shortcut for static ctors, as there cannot be chained ctor calls in static ctors.

pull/1505/head
Siegfried Pammer 6 years ago
parent
commit
b03aa488aa
  1. 21
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  2. 30
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  3. 3
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

21
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -72,6 +72,27 @@ namespace ICSharpCode.Decompiler.IL @@ -72,6 +72,27 @@ namespace ICSharpCode.Decompiler.IL
internal DebugInfo.AsyncDebugInfo AsyncDebugInfo;
int ctorCallStart = int.MinValue;
/// <summary>
/// Returns the IL offset of the constructor call, -1 if this is not a constructor or no chained constructor call was found.
/// </summary>
internal int ChainedConstructorCallILOffset {
get {
if (ctorCallStart == int.MinValue) {
if (!this.Method.IsConstructor || this.Method.IsStatic)
ctorCallStart = -1;
else {
ctorCallStart = this.Descendants.FirstOrDefault(d => d is CallInstruction call && !(call is NewObj)
&& call.Method.IsConstructor
&& call.Method.DeclaringType.IsReferenceType == true
&& call.Parent is Block)?.StartILOffset ?? -1;
}
}
return ctorCallStart;
}
}
/// <summary>
/// If this is an expression tree or delegate, returns the expression tree type Expression{T} or T.
/// T is the delegate type that matches the signature of this method.

30
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -39,9 +39,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -39,9 +39,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
public void Run(ILFunction function, ILTransformContext context)
{
int? ctorCallStart = null;
foreach (var block in function.Descendants.OfType<Block>()) {
InlineAllInBlock(function, block, context, ref ctorCallStart);
InlineAllInBlock(function, block, context);
}
function.Variables.RemoveDead();
}
@ -64,27 +63,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -64,27 +63,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
else {
var function = block.Ancestors.OfType<ILFunction>().FirstOrDefault();
var inst = block.Instructions[pos];
int? ctorCallStart = null;
if (IsInConstructorInitializer(function, inst, ref ctorCallStart))
if (IsInConstructorInitializer(function, inst))
options |= InliningOptions.Aggressive;
}
return options;
}
public static bool InlineAllInBlock(ILFunction function, Block block, ILTransformContext context)
{
int? ctorCallStart = null;
return InlineAllInBlock(function, block, context, ref ctorCallStart);
}
static bool InlineAllInBlock(ILFunction function, Block block, ILTransformContext context, ref int? ctorCallStart)
{
bool modified = false;
var instructions = block.Instructions;
for (int i = instructions.Count - 1; i >= 0; i--) {
if (instructions[i] is StLoc inst) {
InliningOptions options = InliningOptions.None;
if (IsCatchWhenBlock(block) || IsInConstructorInitializer(function, inst, ref ctorCallStart))
if (IsCatchWhenBlock(block) || IsInConstructorInitializer(function, inst))
options = InliningOptions.Aggressive;
if (InlineOneIfPossible(block, i, options, context)) {
modified = true;
@ -95,23 +87,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -95,23 +87,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return modified;
}
internal static bool IsInConstructorInitializer(ILFunction function, ILInstruction inst, ref int? ctorCallStart)
internal static bool IsInConstructorInitializer(ILFunction function, ILInstruction inst)
{
if (ctorCallStart == null) {
if (function == null || !function.Method.IsConstructor)
ctorCallStart = -1;
else
ctorCallStart = function.Descendants.FirstOrDefault(d => d is CallInstruction call && !(call is NewObj)
&& call.Method.IsConstructor
&& call.Method.DeclaringType.IsReferenceType == true
&& call.Parent is Block)?.StartILOffset ?? -1;
}
if (inst.EndILOffset > ctorCallStart.GetValueOrDefault())
int ctorCallStart = function.ChainedConstructorCallILOffset;
if (inst.EndILOffset > ctorCallStart)
return false;
var topLevelInst = inst.Ancestors.LastOrDefault(instr => instr.Parent is Block);
if (topLevelInst == null)
return false;
return topLevelInst.EndILOffset <= ctorCallStart.GetValueOrDefault();
return topLevelInst.EndILOffset <= ctorCallStart;
}
internal static bool IsCatchWhenBlock(Block block)

3
ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

@ -439,8 +439,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -439,8 +439,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (elementCount >= length / 3 - 5)
return true;
int? unused = null;
if (ILInlining.IsCatchWhenBlock(block) || ILInlining.IsInConstructorInitializer(function, block.Instructions[startPos], ref unused))
if (ILInlining.IsCatchWhenBlock(block) || ILInlining.IsInConstructorInitializer(function, block.Instructions[startPos]))
return true;
return false;
}

Loading…
Cancel
Save