From 2e27beef48a34702ba4ce6457af985de6fd78baf Mon Sep 17 00:00:00 2001 From: AlexanderZemlyak <92867056+AlexanderZemlyak@users.noreply.github.com> Date: Thu, 10 Apr 2025 13:14:04 +0300 Subject: [PATCH] Create generic instances cache (#3259) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 771ea7b445ec9086a0ac172e24299fa6c8bea0f3 Author: Ivan Bondarev Date: Sun Apr 6 14:32:17 2025 +0200 #3230 commit 28a1a03e8dbccdff404c133145b5bffc63920cad Author: Ivan Bondarev Date: Sun Apr 6 11:35:09 2025 +0200 #3251 commit af7abc770b958fe85cf37d4f29f79eb97f3f25ba 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 aae723b982e09e5476f89805ee6cfe2b88029dfc 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 f9cc90e50fe4d765ec03b4c685c9ce9b62d66caf Author: Sun Serega Date: Thu Apr 3 11:59:46 2025 +0300 fix errors (#3260) commit f85bfad60ffee7a9f01f9a95e630388db4cd732b 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 --- CodeCompletion/CodeCompletion.cs | 2 + CodeCompletion/DomSyntaxTreeVisitor.cs | 1 + CodeCompletion/SymTable.cs | 92 ++++++++++++++++--- .../CodeCompletionParserController.cs | 9 +- .../CodeCompletionParserController.cs | 8 +- 5 files changed, 92 insertions(+), 20 deletions(-) diff --git a/CodeCompletion/CodeCompletion.cs b/CodeCompletion/CodeCompletion.cs index 47c0a937d..b0611ca0c 100644 --- a/CodeCompletion/CodeCompletion.cs +++ b/CodeCompletion/CodeCompletion.cs @@ -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(); diff --git a/CodeCompletion/DomSyntaxTreeVisitor.cs b/CodeCompletion/DomSyntaxTreeVisitor.cs index 84db7e59e..b4c705c11 100644 --- a/CodeCompletion/DomSyntaxTreeVisitor.cs +++ b/CodeCompletion/DomSyntaxTreeVisitor.cs @@ -58,6 +58,7 @@ namespace CodeCompletion public void Convert(compilation_unit cu) { method_call_cache.Clear(); + try { cu.visit(this); diff --git a/CodeCompletion/SymTable.cs b/CodeCompletion/SymTable.cs index 2b291f484..58b6b6a95 100644 --- a/CodeCompletion/SymTable.cs +++ b/CodeCompletion/SymTable.cs @@ -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 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 + { + public TypeScope originalType; + public List genericArguments; + public bool exact; + + public InstanceCreationContext(TypeScope originalType, List genericArguments, bool exact) + { + this.originalType = originalType; + this.genericArguments = genericArguments; + this.exact = exact; + } + + private struct ScopeComparer : IEqualityComparer + { + 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> instance_cache = new Dictionary>(); + internal static Dictionary instance_cache = new Dictionary(); public TypeScope() { } public TypeScope(SymbolKind kind, SymScope topScope, SymScope baseScope) @@ -4475,7 +4522,16 @@ namespace CodeCompletion public virtual TypeScope GetInstance(List 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 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; } diff --git a/VisualPascalABCNET/IB/CodeCompletion/CodeCompletionParserController.cs b/VisualPascalABCNET/IB/CodeCompletion/CodeCompletionParserController.cs index d8e4f04ea..cee96c19a 100644 --- a/VisualPascalABCNET/IB/CodeCompletion/CodeCompletionParserController.cs +++ b/VisualPascalABCNET/IB/CodeCompletion/CodeCompletionParserController.cs @@ -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 recomp_files = new Dictionary(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; diff --git a/VisualPascalABCNETLinux/IB/CodeCompletion/CodeCompletionParserController.cs b/VisualPascalABCNETLinux/IB/CodeCompletion/CodeCompletionParserController.cs index 5caba22d5..1caf262f8 100644 --- a/VisualPascalABCNETLinux/IB/CodeCompletion/CodeCompletionParserController.cs +++ b/VisualPascalABCNETLinux/IB/CodeCompletion/CodeCompletionParserController.cs @@ -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 recomp_files = new Dictionary(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;