Browse Source

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

pull/3111/head
Siegfried Pammer 3 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
currentTypeDefinitionCache = new TypeDefinitionCache(context.CurrentTypeDefinition); 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.compilation = compilation;
this.conversions = conversions; this.conversions = conversions;
@ -228,21 +228,21 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// The beginning of a block is marked by a null entry. // 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. // 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); return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, stack, objectInitializerStack);
} }
/// <summary> /// <summary>
/// Adds a new variable or lambda parameter to the current block. /// Adds new variableŝ or lambda parameters to the current block.
/// </summary> /// </summary>
public CSharpResolver AddVariable(IVariable variable) public CSharpResolver AddVariables(Dictionary<string, IVariable> variables)
{ {
if (variable == null) if (variables == null)
throw new ArgumentNullException(nameof(variable)); throw new ArgumentNullException(nameof(variables));
return WithLocalVariableStack(localVariableStack.Push(variable)); return WithLocalVariableStack(localVariableStack.Push(variables));
} }
/// <summary> /// <summary>
@ -251,7 +251,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary> /// </summary>
public IEnumerable<IVariable> LocalVariables { public IEnumerable<IVariable> LocalVariables {
get { get {
return localVariableStack.Where(v => v != null); return localVariableStack.SelectMany(s => s.Values);
} }
} }
#endregion #endregion
@ -1482,9 +1482,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (lookupMode == NameLookupMode.Expression || lookupMode == NameLookupMode.InvocationTarget) if (lookupMode == NameLookupMode.Expression || lookupMode == NameLookupMode.InvocationTarget)
{ {
// Look in local variables // 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); return new LocalResolveResult(v);
} }

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

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

Loading…
Cancel
Save