Browse Source

#3075: Improve performance of CSharpResolver.LookupSimpleNameOrTypeName in cases with a large number of local variables.

pull/3111/head
Siegfried Pammer 2 years ago
parent
commit
ee160b4e2a
  1. 22
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
  2. 6
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

22
ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
currentTypeDefinitionCache = new TypeDefinitionCache(context.CurrentTypeDefinition);
}
private CSharpResolver(ICompilation compilation, CSharpConversions conversions, CSharpTypeResolveContext context, bool checkForOverflow, bool isWithinLambdaExpression, TypeDefinitionCache currentTypeDefinitionCache, ImmutableStack<IVariable> localVariableStack, ObjectInitializerContext objectInitializerStack)
private CSharpResolver(ICompilation compilation, CSharpConversions conversions, CSharpTypeResolveContext context, bool checkForOverflow, bool isWithinLambdaExpression, TypeDefinitionCache currentTypeDefinitionCache, ImmutableStack<Dictionary<string, IVariable>> localVariableStack, ObjectInitializerContext objectInitializerStack)
{
this.compilation = compilation;
this.conversions = conversions;
@ -228,21 +228,21 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -228,21 +228,21 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// The beginning of a block is marked by a null entry.
// This data structure is used to allow efficient cloning of the resolver with its local variable context.
readonly ImmutableStack<IVariable> localVariableStack = ImmutableStack<IVariable>.Empty;
readonly ImmutableStack<Dictionary<string, IVariable>> localVariableStack = ImmutableStack<Dictionary<string, IVariable>>.Empty;
CSharpResolver WithLocalVariableStack(ImmutableStack<IVariable> stack)
CSharpResolver WithLocalVariableStack(ImmutableStack<Dictionary<string, IVariable>> stack)
{
return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, stack, objectInitializerStack);
}
/// <summary>
/// Adds a new variable or lambda parameter to the current block.
/// Adds new variableŝ or lambda parameters to the current block.
/// </summary>
public CSharpResolver AddVariable(IVariable variable)
public CSharpResolver AddVariables(Dictionary<string, IVariable> variables)
{
if (variable == null)
throw new ArgumentNullException(nameof(variable));
return WithLocalVariableStack(localVariableStack.Push(variable));
if (variables == null)
throw new ArgumentNullException(nameof(variables));
return WithLocalVariableStack(localVariableStack.Push(variables));
}
/// <summary>
@ -251,7 +251,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -251,7 +251,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary>
public IEnumerable<IVariable> LocalVariables {
get {
return localVariableStack.Where(v => v != null);
return localVariableStack.SelectMany(s => s.Values);
}
}
#endregion
@ -1482,9 +1482,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1482,9 +1482,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (lookupMode == NameLookupMode.Expression || lookupMode == NameLookupMode.InvocationTarget)
{
// Look in local variables
foreach (IVariable v in this.LocalVariables)
foreach (Dictionary<string, IVariable> variables in localVariableStack)
{
if (v.Name == identifier)
if (variables.TryGetValue(identifier, out var v))
{
return new LocalResolveResult(v);
}

6
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

@ -161,11 +161,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -161,11 +161,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
CSharpResolver resolver = new CSharpResolver(context);
if (function != null)
{
var variables = new Dictionary<string, IVariable>();
foreach (var v in function.Variables)
{
if (v.Kind != IL.VariableKind.Parameter && v.Name != null)
resolver = resolver.AddVariable(new DefaultVariable(v.Type, v.Name));
if (v.Kind != IL.VariableKind.Parameter && v.Name != null && !variables.ContainsKey(v.Name))
variables.Add(v.Name, new DefaultVariable(v.Type, v.Name));
}
resolver = resolver.AddVariables(variables);
}
return new TypeSystemAstBuilder(resolver) {

Loading…
Cancel
Save