diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs
index 60d4711da3..e629a427b7 100644
--- a/src/System.Management.Automation/engine/lang/parserutils.cs
+++ b/src/System.Management.Automation/engine/lang/parserutils.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.Collections;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
@@ -9,10 +10,8 @@ using System.Management.Automation.Internal;
using System.Management.Automation.Internal.Host;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
-using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
-using System.Text;
using System.Text.RegularExpressions;
using Dbg = System.Management.Automation.Diagnostics;
@@ -1347,35 +1346,37 @@ namespace System.Management.Automation
}
///
- /// Cache regular expressions...
+ /// Cache regular expressions.
///
/// The string to find the pattern for.
- /// The options used to create the regex...
- /// A case-insensitive Regex...
+ /// The options used to create the regex.
+ /// New or cached Regex.
internal static Regex NewRegex(string patternString, RegexOptions options)
{
- if (options != RegexOptions.IgnoreCase)
- return new Regex(patternString, options);
-
- lock (s_regexCache)
+ var subordinateRegexCache = s_regexCache.GetOrAdd(options, s_subordinateRegexCacheCreationDelegate);
+ if (subordinateRegexCache.TryGetValue(patternString, out Regex result))
{
- Regex result;
- if (s_regexCache.TryGetValue(patternString, out result))
+ return result;
+ }
+ else
+ {
+ if (subordinateRegexCache.Count > MaxRegexCache)
{
- return result;
- }
- else
- {
- if (s_regexCache.Count > MaxRegexCache)
- s_regexCache.Clear();
- Regex re = new Regex(patternString, RegexOptions.IgnoreCase);
- s_regexCache.Add(patternString, re);
- return re;
+ // TODO: it would be useful to get a notice (in telemetry?) if the cache is full.
+ subordinateRegexCache.Clear();
}
+
+ var regex = new Regex(patternString, options);
+ return subordinateRegexCache.GetOrAdd(patternString, regex);
}
}
- private static Dictionary s_regexCache = new Dictionary();
+ private static readonly ConcurrentDictionary> s_regexCache =
+ new ConcurrentDictionary>();
+
+ private static readonly Func> s_subordinateRegexCacheCreationDelegate =
+ key => new ConcurrentDictionary(StringComparer.Ordinal);
+
private const int MaxRegexCache = 1000;
///
diff --git a/src/System.Management.Automation/engine/regex.cs b/src/System.Management.Automation/engine/regex.cs
index 71c6c8bac8..2c4ade7cb5 100644
--- a/src/System.Management.Automation/engine/regex.cs
+++ b/src/System.Management.Automation/engine/regex.cs
@@ -909,7 +909,7 @@ namespace System.Management.Automation
WildcardPatternParser.Parse(wildcardPattern, parser);
try
{
- return new Regex(parser._regexPattern.ToString(), parser._regexOptions);
+ return ParserOps.NewRegex(parser._regexPattern.ToString(), parser._regexOptions);
}
catch (ArgumentException)
{
@@ -1258,7 +1258,7 @@ namespace System.Management.Automation
protected override void EndBracketExpression()
{
_bracketExpressionBuilder.Append(']');
- Regex regex = new Regex(_bracketExpressionBuilder.ToString(), _regexOptions);
+ Regex regex = ParserOps.NewRegex(_bracketExpressionBuilder.ToString(), _regexOptions);
_patternElements.Add(new BracketExpressionElement(regex));
}
}