From 88f2b8aa74a5f664e63f0b40811876ffe2629f3a Mon Sep 17 00:00:00 2001 From: Heejae Chang Date: Mon, 14 Sep 2015 17:11:40 -0700 Subject: [PATCH] fixed #5203 by caching boxed object only once and re-use them --- .../TableDataSource/ValueTypeCache.cs | 37 +++++++++++++++++++ ...DiagnosticListTable.LiveTableDataSource.cs | 8 ++-- .../VisualStudioBaseTodoListTable.cs | 6 +-- ...iagnosticListTable.BuildTableDataSource.cs | 9 +++-- .../Core/Def/ServicesVisualStudio.csproj | 1 + 5 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 src/VisualStudio/Core/Def/Implementation/TableDataSource/ValueTypeCache.cs diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/ValueTypeCache.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/ValueTypeCache.cs new file mode 100644 index 00000000000..8a9b4de9364 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/ValueTypeCache.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Concurrent; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource +{ + internal static class ValueTypeCache + { + /// + /// Re-use already boxed object for value type. + /// this cache never release cached object. must be used only with fixed set of valut types. or + /// something that grows very slowly like Guid for projects. + /// + public static object GetOrCreate(T value) where T : struct + { + // let compiler creates a cache for each value type. + return Cache.Instance.GetOrCreate(value); + } + + private class Cache where T : struct + { + public static readonly Cache Instance = new Cache(); + + private static readonly Func _boxer = v => (object)v; + + // this will be never released, must be used only for fixed size set + private readonly ConcurrentDictionary _map = + new ConcurrentDictionary(concurrencyLevel: 2, capacity: 5); + + public object GetOrCreate(T value) + { + return _map.GetOrAdd(value, _boxer); + } + } + } +} \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.LiveTableDataSource.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.LiveTableDataSource.cs index ecc9465a2a9..33f1f9b4ed6 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.LiveTableDataSource.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.LiveTableDataSource.cs @@ -257,10 +257,10 @@ public override bool TryGetValue(int index, string columnName, out object conten switch (columnName) { case StandardTableKeyNames.ErrorRank: - content = GetErrorRank(data); + content = ValueTypeCache.GetOrCreate(GetErrorRank(data)); return true; case StandardTableKeyNames.ErrorSeverity: - content = GetErrorCategory(data.Severity); + content = ValueTypeCache.GetOrCreate(GetErrorCategory(data.Severity)); return true; case StandardTableKeyNames.ErrorCode: content = data.Id; @@ -275,7 +275,7 @@ public override bool TryGetValue(int index, string columnName, out object conten content = data.Category; return true; case StandardTableKeyNames.ErrorSource: - content = GetErrorSource(_source.BuildTool); + content = ValueTypeCache.GetOrCreate(GetErrorSource(_source.BuildTool)); return true; case StandardTableKeyNames.BuildTool: content = GetBuildTool(_source.BuildTool); @@ -299,7 +299,7 @@ public override bool TryGetValue(int index, string columnName, out object conten content = item.ProjectNames; return ((string[])content).Length > 0; case StandardTableKeyNames.ProjectGuid: - content = item.ProjectGuid; + content = ValueTypeCache.GetOrCreate(item.ProjectGuid); return (Guid)content != Guid.Empty; case ProjectGuids: content = item.ProjectGuids; diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs index b6bcca71e15..0ca76d5dcc4 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs @@ -235,7 +235,7 @@ public override bool TryGetValue(int index, string columnName, out object conten switch (columnName) { case StandardTableKeyNames.Priority: - content = (VSTASKPRIORITY)data.Priority; + content = ValueTypeCache.GetOrCreate((VSTASKPRIORITY)data.Priority); return true; case StandardTableKeyNames.Text: content = data.Message; @@ -250,7 +250,7 @@ public override bool TryGetValue(int index, string columnName, out object conten content = GetLineColumn(data).Character; return true; case StandardTableKeyNames.TaskCategory: - content = VSTASKCATEGORY.CAT_COMMENTS; + content = ValueTypeCache.GetOrCreate(VSTASKCATEGORY.CAT_COMMENTS); return true; case StandardTableKeyNames.ProjectName: content = item.ProjectName; @@ -259,7 +259,7 @@ public override bool TryGetValue(int index, string columnName, out object conten content = item.ProjectNames; return ((string[])content).Length > 0; case StandardTableKeyNames.ProjectGuid: - content = item.ProjectGuid; + content = ValueTypeCache.GetOrCreate(item.ProjectGuid); return (Guid)content != Guid.Empty; case ProjectGuids: content = item.ProjectGuids; diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioDiagnosticListTable.BuildTableDataSource.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioDiagnosticListTable.BuildTableDataSource.cs index 46e7a3d8e16..f40e9e90511 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioDiagnosticListTable.BuildTableDataSource.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioDiagnosticListTable.BuildTableDataSource.cs @@ -180,10 +180,11 @@ public override bool TryGetValue(int index, string columnName, out object conten switch (columnName) { case StandardTableKeyNames.ErrorRank: - content = WellKnownDiagnosticTags.Build; + // build error gets highest rank + content = ValueTypeCache.GetOrCreate(ErrorRank.Lexical); return true; case StandardTableKeyNames.ErrorSeverity: - content = GetErrorCategory(data.Severity); + content = ValueTypeCache.GetOrCreate(GetErrorCategory(data.Severity)); return true; case StandardTableKeyNames.ErrorCode: content = data.Id; @@ -198,7 +199,7 @@ public override bool TryGetValue(int index, string columnName, out object conten content = data.Category; return true; case StandardTableKeyNames.ErrorSource: - content = ErrorSource.Build; + content = ValueTypeCache.GetOrCreate(ErrorSource.Build); return true; case StandardTableKeyNames.BuildTool: content = _source.BuildTool; @@ -222,7 +223,7 @@ public override bool TryGetValue(int index, string columnName, out object conten content = item.ProjectNames; return ((string[])content).Length > 0; case StandardTableKeyNames.ProjectGuid: - content = item.ProjectGuid; + content = ValueTypeCache.GetOrCreate(item.ProjectGuid); return (Guid)content != Guid.Empty; case ProjectGuids: content = item.ProjectGuids; diff --git a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj index 8a8fcbf2409..2110fdf6a94 100644 --- a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj +++ b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj @@ -78,6 +78,7 @@ + -- GitLab