Create generic instances cache (#3259)

* First attempt to create generic instances cache

* Change TypeScope equality check and add instance cache clearing

* Move instance cache clearing call to CodeCompletion Compile funciton

Шаблонные типы в instance_cache не должны пересекаться для различных модулей. Для улучшения производительности вызов очистки кэша расположен перед вызовом компиляции всех модулей.

* Squashed commit of the following:

commit 771ea7b445
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Sun Apr 6 14:32:17 2025 +0200

    #3230

commit 28a1a03e8d
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Sun Apr 6 11:35:09 2025 +0200

    #3251

commit af7abc770b
Author: samuraiGH <87191377+samuraiGH@users.noreply.github.com>
Date:   Sun Apr 6 08:33:34 2025 +0300

    synchronization of namespaces and folders for TeacherControlPlugin (#3262)

commit aae723b982
Author: AlexanderZemlyak <92867056+AlexanderZemlyak@users.noreply.github.com>
Date:   Thu Apr 3 12:00:04 2025 +0300

    Create default syntax tree converter class (#3216)

    Для удобства разработчиков простых языков, которым не требуются дополнительные обходы синтаксического дерева.

commit f9cc90e50f
Author: Sun Serega <sunserega2@gmail.com>
Date:   Thu Apr 3 11:59:46 2025 +0300

    fix errors (#3260)

commit f85bfad60f
Author: AlexanderZemlyak <92867056+AlexanderZemlyak@users.noreply.github.com>
Date:   Thu Apr 3 11:58:19 2025 +0300

    Intellisense memory leaks fix (#3257)

    * Fix memory leaks found for PABCSystem.pas

    Memory leaks of Interface and Implementation Unit Scopes fixed

    * Change open_files and recomp_files variables type to be Dictionary (not HashTable)

    * open_files Check simplification

    * Move TypeTable.Clear call to CodeCompletion Compile method

* Fix incorrect dictionary iteration

* Add one more dictionary keys copying
This commit is contained in:
AlexanderZemlyak 2025-04-10 13:14:04 +03:00 committed by GitHub
parent 69149f8c44
commit 2e27beef48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 92 additions and 20 deletions

View file

@ -120,6 +120,8 @@ namespace CodeCompletion
File.AppendAllText("log.txt", e.Message + Environment.NewLine + e.StackTrace + Environment.NewLine);
#endif
}
TypeScope.instance_cache.Clear();
// очистка кэша и данных от старых компиляций, чтобы при новой компиляции не появились ссылки на старые данные
TypeTable.Clear();

View file

@ -58,6 +58,7 @@ namespace CodeCompletion
public void Convert(compilation_unit cu)
{
method_call_cache.Clear();
try
{
cu.visit(this);

View file

@ -1,17 +1,14 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using PascalABCCompiler;
using PascalABCCompiler.Parsers;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.TreeRealization;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using SymbolTable;
using PascalABCCompiler.TreeRealization;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.Parsers;
using System.Linq;
using PascalABCCompiler;
using PascalABCCompiler.TreeConverter;
using System.Reflection;
namespace CodeCompletion
{
@ -3589,8 +3586,23 @@ namespace CodeCompletion
public override TypeScope GetInstance(List<TypeScope> gen_args, bool exact = false)
{
if ((elementType is UnknownScope || elementType is TemplateParameterScope) && gen_args.Count > 0)
return new ArrayScope(gen_args[gen_args.Count-1], Rank > 1?indexes:null);
{
InstanceCreationContext info = new InstanceCreationContext(this, gen_args, exact);
if (instance_cache.TryGetValue(info, out var instance))
{
return instance;
}
var arrayScope = new ArrayScope(gen_args[gen_args.Count - 1], Rank > 1 ? indexes : null);
instance_cache[info] = arrayScope;
return arrayScope;
}
return this;
}
@ -4102,6 +4114,41 @@ namespace CodeCompletion
}
}
internal struct InstanceCreationContext : IEquatable<InstanceCreationContext>
{
public TypeScope originalType;
public List<TypeScope> genericArguments;
public bool exact;
public InstanceCreationContext(TypeScope originalType, List<TypeScope> genericArguments, bool exact)
{
this.originalType = originalType;
this.genericArguments = genericArguments;
this.exact = exact;
}
private struct ScopeComparer : IEqualityComparer<TypeScope>
{
public bool Equals(TypeScope t1, TypeScope t2) => t1.IsEqual(t2);
public int GetHashCode(TypeScope t) => t.GetDescription().GetHashCode();
}
public bool Equals(InstanceCreationContext otherInfo)
{
return this.originalType.IsEqual(otherInfo.originalType) &&
this.genericArguments.SequenceEqual(otherInfo.genericArguments, new ScopeComparer()) &&
this.exact == otherInfo.exact;
}
public override int GetHashCode()
{
return string.Join("", genericArguments.Select(arg => arg.si != null ? arg.GetDescription() : "")
.Concat(new string[] { originalType.GetDescription(), exact.ToString() })).GetHashCode();
}
}
//opisanie tipa (klassa, zapisi) ot nego est nasledniki. sdelal ih dlja udobstva.
public class TypeScope : SymScope, ITypeScope
{
@ -4122,7 +4169,7 @@ namespace CodeCompletion
public bool is_final;
public bool aliased = false;
internal bool lazy_instance = false;
private static Dictionary<TypeScope, List<TypeScope>> instance_cache = new Dictionary<TypeScope, List<TypeScope>>();
internal static Dictionary<InstanceCreationContext, TypeScope> instance_cache = new Dictionary<InstanceCreationContext, TypeScope>();
public TypeScope() { }
public TypeScope(SymbolKind kind, SymScope topScope, SymScope baseScope)
@ -4475,7 +4522,16 @@ namespace CodeCompletion
public virtual TypeScope GetInstance(List<TypeScope> gen_args, bool exact = false)
{
InstanceCreationContext info = new InstanceCreationContext(this, gen_args, exact);
if (instance_cache.TryGetValue(info, out var instance))
{
return instance;
}
TypeScope ts = new TypeScope(this.kind, this.topScope, this.baseScope);
ts.original_type = this;
ts.loc = this.loc;
ts.other_partials = this.other_partials;
@ -4590,6 +4646,9 @@ namespace CodeCompletion
new_ps.nextProc = procs[ps.nextProc] as ProcScope;
}
}
instance_cache[info] = ts;
return ts;
}
@ -5784,9 +5843,17 @@ namespace CodeCompletion
public override TypeScope GetInstance(List<TypeScope> gen_args, bool exact = false)
{
Type t = this.ctn;
if (!ctn.IsGenericType)
return this;
InstanceCreationContext info = new InstanceCreationContext(this, gen_args, exact);
if (instance_cache.TryGetValue(info, out var instance))
{
return instance;
}
Type t = this.ctn;
if (!ctn.IsGenericTypeDefinition)
{
t = PascalABCCompiler.NetHelper.NetHelper.FindType(this.ctn.Namespace + "." + this.ctn.Name);
@ -5885,6 +5952,9 @@ namespace CodeCompletion
for (int i = 0; i < this.implemented_interfaces.Count; i++)
sc.implemented_interfaces.Add(this.implemented_interfaces[i].GetInstance(gen_args));
sc.si.description = sc.GetDescription();
instance_cache[info] = sc;
return sc;
}

View file

@ -1,9 +1,8 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using Languages.Integration;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace VisualPascalABC
{
@ -98,7 +97,7 @@ namespace VisualPascalABC
{
try
{
foreach (string s in open_files.Keys)
foreach (string s in open_files.Keys.ToArray())
{
if (ProjectFactory.Instance.CurrentProject.ContainsSourceFile(s))
open_files[s] = true;
@ -147,7 +146,7 @@ namespace VisualPascalABC
{
Dictionary<string, string> recomp_files = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
bool is_comp = false;
foreach (string FileName in open_files.Keys)
foreach (string FileName in open_files.Keys.ToArray()) // копирование ключей обязательно, иначе будет InvalidOperationException EVA
{
if (open_files[FileName])
@ -181,7 +180,7 @@ namespace VisualPascalABC
CodeCompletion.CodeCompletionController.comp_modules[FileName] = dc;
}
}
foreach (string FileName in open_files.Keys)
foreach (string FileName in open_files.Keys.ToArray()) // копирование ключей обязательно, иначе будет InvalidOperationException EVA
{
CodeCompletion.DomConverter dc = CodeCompletion.CodeCompletionController.comp_modules[FileName] as CodeCompletion.DomConverter;
CodeCompletion.SymScope ss = null;

View file

@ -1,8 +1,8 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace VisualPascalABC
{
@ -98,7 +98,7 @@ namespace VisualPascalABC
{
try
{
foreach (string s in open_files.Keys)
foreach (string s in open_files.Keys.ToArray())
{
if (ProjectFactory.Instance.CurrentProject.ContainsSourceFile(s))
open_files[s] = true;
@ -151,7 +151,7 @@ namespace VisualPascalABC
{
Dictionary<string, string> recomp_files = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
bool is_comp = false;
foreach (string FileName in open_files.Keys)
foreach (string FileName in open_files.Keys.ToArray()) // копирование ключей обязательно, иначе будет InvalidOperationException EVA
{
if (open_files[FileName])
@ -185,7 +185,7 @@ namespace VisualPascalABC
CodeCompletion.CodeCompletionController.comp_modules[FileName] = dc;
}
}
foreach (string FileName in open_files.Keys)
foreach (string FileName in open_files.Keys.ToArray()) // копирование ключей обязательно, иначе будет InvalidOperationException EVA
{
CodeCompletion.DomConverter dc = CodeCompletion.CodeCompletionController.comp_modules[FileName] as CodeCompletion.DomConverter;
CodeCompletion.SymScope ss = null;