Browse Source

Merge pull request #1108 from pentp/perf2

Reduced allocations in ILInlining
pull/1121/head
Siegfried Pammer 8 years ago committed by GitHub
parent
commit
b504ca349b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  2. 46
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

2
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -151,7 +151,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
new RemoveDeadVariableInit().Run(function, context); new RemoveDeadVariableInit().Run(function, context);
// Run inlining, but don't remove dead variables (they might get revived by TranslateFieldsToLocalAccess) // Run inlining, but don't remove dead variables (they might get revived by TranslateFieldsToLocalAccess)
foreach (var block in function.Descendants.OfType<Block>()) { foreach (var block in function.Descendants.OfType<Block>()) {
ILInlining.InlineAllInBlock(block, context); ILInlining.InlineAllInBlock(function, block, context);
} }
context.StepEndGroup(); context.StepEndGroup();
} }

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

@ -30,15 +30,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
public void Run(ILFunction function, ILTransformContext context) public void Run(ILFunction function, ILTransformContext context)
{ {
int? ctorCallStart = null;
foreach (var block in function.Descendants.OfType<Block>()) { foreach (var block in function.Descendants.OfType<Block>()) {
InlineAllInBlock(block, context); InlineAllInBlock(function, block, context, ref ctorCallStart);
} }
function.Variables.RemoveDead(); function.Variables.RemoveDead();
} }
public void Run(Block block, BlockTransformContext context) public void Run(Block block, BlockTransformContext context)
{ {
InlineAllInBlock(block, context); InlineAllInBlock(context.Function, block, context);
} }
public void Run(Block block, int pos, StatementTransformContext context) public void Run(Block block, int pos, StatementTransformContext context)
@ -46,12 +47,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
InlineOneIfPossible(block, pos, aggressive: IsCatchWhenBlock(block), context: context); InlineOneIfPossible(block, pos, aggressive: IsCatchWhenBlock(block), context: context);
} }
public static bool InlineAllInBlock(Block block, ILTransformContext context) 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; bool modified = false;
int i = 0; var instructions = block.Instructions;
while (i < block.Instructions.Count) { for (int i = 0; i < instructions.Count;) {
if (InlineOneIfPossible(block, i, aggressive: IsCatchWhenBlock(block) || IsInConstructorInitializer(i, block), context: context)) { if (instructions[i] is StLoc inst
&& InlineOneIfPossible(block, i, aggressive: IsCatchWhenBlock(block) || IsInConstructorInitializer(function, inst, ref ctorCallStart), context: context)) {
modified = true; modified = true;
i = Math.Max(0, i - 1); i = Math.Max(0, i - 1);
// Go back one step // Go back one step
@ -62,21 +70,23 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return modified; return modified;
} }
static bool IsInConstructorInitializer(int i, Block block) static bool IsInConstructorInitializer(ILFunction function, ILInstruction inst, ref int? ctorCallStart)
{ {
var inst = block.Instructions[i]; if (ctorCallStart == null) {
var topLevelBlock = inst.Ancestors.OfType<Block>().LastOrDefault(); if (function == null || !function.Method.IsConstructor)
var function = topLevelBlock.Ancestors.OfType<ILFunction>().FirstOrDefault(f => f.Parent == null); ctorCallStart = -1;
if (topLevelBlock == null || function == null || !function.Method.IsConstructor) 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)?.ILRange.Start ?? -1;
}
if (inst.ILRange.InclusiveEnd >= ctorCallStart.GetValueOrDefault())
return false; return false;
var topLevelInst = inst.Ancestors.FirstOrDefault(instr => instr.Parent == topLevelBlock); var topLevelInst = inst.Ancestors.LastOrDefault(instr => instr.Parent is Block);
var ctorCall = function.Descendants.OfType<CallInstruction>().FirstOrDefault(call => !(call is NewObj) if (topLevelInst == null)
&& call.Method.IsConstructor
&& call.Method.DeclaringType.IsReferenceType == true
&& call.Parent is Block);
if (topLevelInst == null || ctorCall == null)
return false; return false;
return topLevelInst.ILRange.InclusiveEnd < ctorCall.ILRange.Start; return topLevelInst.ILRange.InclusiveEnd < ctorCallStart.GetValueOrDefault();
} }
static bool IsCatchWhenBlock(Block block) static bool IsCatchWhenBlock(Block block)

Loading…
Cancel
Save