Skip to content

Commit

Permalink
#3075: Improve performance of CSharpResolver.LookupSimpleNameOrTypeNa…
Browse files Browse the repository at this point in the history
…me in cases with a large number of local variables.
  • Loading branch information
siegfriedpammer committed Oct 14, 2023
1 parent 5a3c6e0 commit ee160b4
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 13 deletions.
22 changes: 11 additions & 11 deletions ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public CSharpResolver(CSharpTypeResolveContext context)
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;
Expand Down Expand Up @@ -228,21 +228,21 @@ public TypeDefinitionCache(ITypeDefinition typeDefinition)
// 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>
Expand All @@ -251,7 +251,7 @@ public CSharpResolver AddVariable(IVariable variable)
/// </summary>
public IEnumerable<IVariable> LocalVariables {
get {
return localVariableStack.Where(v => v != null);
return localVariableStack.SelectMany(s => s.Values);
}
}
#endregion
Expand Down Expand Up @@ -1482,9 +1482,9 @@ public ResolveResult LookupSimpleNameOrTypeName(string identifier, IReadOnlyList
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,13 @@ TypeSystemAstBuilder CreateAstBuilder(CSharpTypeResolveContext context, IL.ILFun
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) {
Expand Down

0 comments on commit ee160b4

Please sign in to comment.