/* * Add current code to the cache */ private CachedCodeEntry CacheCode(CachedCodeEntryKey key) { CachedCodeEntry newcached = null; lock (s_livecode) { // first look for it in the cache and move it to the head for (LinkedListNode <CachedCodeEntry> current = s_livecode.First; current != null; current = current.Next) { if (current.Value._key == key) { s_livecode.Remove(current); s_livecode.AddFirst(current); return(current.Value); } } // it wasn't in the cache, so we'll add a new one. Shortcut out for the case where cacheSize is zero. if (s_cacheSize != 0) { newcached = new CachedCodeEntry(key, _capnames, capslist, _code, _caps, capsize, _runnerref, _replref); s_livecode.AddFirst(newcached); if (s_livecode.Count > s_cacheSize) { s_livecode.RemoveLast(); } } } return(newcached); }
private CachedCodeEntry GetCachedCodeEntryInternal(CachedCodeEntryKey key, bool isToAdd) { lock (s_cache) { // first look for it in the cache and move it to the head CachedCodeEntry entry = LookupCachedAndPromote(key); // it wasn't in the cache, so we'll add a new one if (entry == null && isToAdd && s_cacheSize != 0) // check cache size again in case it changed { entry = new CachedCodeEntry(key, capnames, capslist, _code, caps, capsize, _runnerref, _replref); // put first in linked list: if (s_cacheFirst != null) { SysDebug.Assert(s_cacheFirst.Next == null); s_cacheFirst.Next = entry; entry.Previous = s_cacheFirst; } s_cacheFirst = entry; s_cacheCount++; if (s_cacheCount >= CacheDictionarySwitchLimit) { if (s_cacheCount == CacheDictionarySwitchLimit) { FillCacheDictionary(); } else { s_cache.Add(key, entry); } SysDebug.Assert(s_cacheCount == s_cache.Count); } // update last in linked list: if (s_cacheLast == null) { s_cacheLast = entry; } else if (s_cacheCount > s_cacheSize) // remove last { CachedCodeEntry last = s_cacheLast; if (s_cacheCount >= CacheDictionarySwitchLimit) { SysDebug.Assert(s_cache[last.Key] == s_cacheLast); s_cache.Remove(last.Key); } SysDebug.Assert(last.Previous == null); SysDebug.Assert(last.Next != null); SysDebug.Assert(last.Next.Previous == last); last.Next.Previous = null; s_cacheLast = last.Next; s_cacheCount--; } } return(entry); } }
public CachedCodeEntry(CachedCodeEntryKey key, Hashtable capnames, string[] capslist, RegexCode code, Hashtable caps, int capsize, ExclusiveReference runner, WeakReference <RegexReplacement> replref) { Key = key; Capnames = capnames; Capslist = capslist; Code = code; Caps = caps; Capsize = capsize; Runnerref = runner; ReplRef = replref; }
[MethodImpl(MethodImplOptions.AggressiveInlining)] // Unprofitable inline - JIT overly pessimistic private static bool TryGetCacheValue(CachedCodeEntryKey key, out CachedCodeEntry entry) { if (s_cacheCount >= CacheDictionarySwitchLimit) { SysDebug.Assert((s_cacheFirst != null && s_cacheLast != null && s_cache.Count > 0) || (s_cacheFirst == null && s_cacheLast == null && s_cache.Count == 0), "Linked list and Dict should be synchronized"); return(s_cache.TryGetValue(key, out entry)); } return(TryGetCacheValueSmall(key, out entry)); }
internal CachedCodeEntry(CachedCodeEntryKey key, Dictionary <string, int> capnames, String[] capslist, RegexCode code, Dictionary <Int32, Int32> caps, int capsize, ExclusiveReference runner, SharedReference repl) { _key = key; _capnames = capnames; _capslist = capslist; _code = code; _caps = caps; _capsize = capsize; _runnerref = runner; _replref = repl; }
internal CachedCodeEntry(CachedCodeEntryKey key, Hashtable capnames, string[] capslist, RegexCode code, Hashtable caps, int capsize, ExclusiveReference runner, SharedReference repl) { _key = key; _capnames = capnames; _capslist = capslist; _code = code; _caps = caps; _capsize = capsize; _runnerref = runner; _replref = repl; }
private static bool TryGetCacheValueSmall(CachedCodeEntryKey key, out CachedCodeEntry entry) { entry = s_cacheFirst?.Previous; // first already checked while (entry != null) { if (entry.Key == key) { return(true); } entry = entry.Previous; } return(false); }
private CachedCodeEntry GetCachedCode(CachedCodeEntryKey key, bool isToAdd) { // to avoid lock: CachedCodeEntry first = s_cacheFirst; if (first?.Key == key) { return(first); } if (s_cacheSize == 0) { return(null); } return(GetCachedCodeEntryInternal(key, isToAdd)); }
/* * Find code cache based on options+pattern */ private static CachedCodeEntry LookupCachedAndUpdate(CachedCodeEntryKey key) { lock (s_livecode) { for (LinkedListNode <CachedCodeEntry> current = s_livecode.First; current != null; current = current.Next) { if (current.Value._key == key) { // If we find an entry in the cache, move it to the head at the same time. s_livecode.Remove(current); s_livecode.AddFirst(current); return(current.Value); } } } return(null); }
private static CachedCodeEntry LookupCachedAndPromote(CachedCodeEntryKey key) { SysDebug.Assert(Monitor.IsEntered(s_cache)); if (s_cacheFirst?.Key == key) // again check this as could have been promoted by other thread { return(s_cacheFirst); } if (TryGetCacheValue(key, out CachedCodeEntry entry)) { // promote: SysDebug.Assert(s_cacheFirst != entry, "key should not get s_livecode_first"); SysDebug.Assert(s_cacheFirst != null, "as Dict has at least one"); SysDebug.Assert(s_cacheFirst.Next == null); SysDebug.Assert(s_cacheFirst.Previous != null); SysDebug.Assert(entry.Next != null, "not first so Next should exist"); SysDebug.Assert(entry.Next.Previous == entry); if (s_cacheLast == entry) { SysDebug.Assert(entry.Previous == null, "last"); s_cacheLast = entry.Next; } else { SysDebug.Assert(entry.Previous != null, "in middle"); SysDebug.Assert(entry.Previous.Next == entry); entry.Previous.Next = entry.Next; } entry.Next.Previous = entry.Previous; s_cacheFirst.Next = entry; entry.Previous = s_cacheFirst; entry.Next = null; s_cacheFirst = entry; } return(entry); }
private Regex(string pattern, RegexOptions options, TimeSpan matchTimeout, bool addToCache) { if (pattern == null) { throw new ArgumentNullException(nameof(pattern)); } if (options < RegexOptions.None || (((int)options) >> MaxOptionShift) != 0) { throw new ArgumentOutOfRangeException(nameof(options)); } if ((options & RegexOptions.ECMAScript) != 0 && (options & ~(RegexOptions.ECMAScript | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.CultureInvariant #if DEBUG | RegexOptions.Debug #endif )) != 0) { throw new ArgumentOutOfRangeException(nameof(options)); } ValidateMatchTimeout(matchTimeout); // After parameter validation assign this.pattern = pattern; roptions = options; internalMatchTimeout = matchTimeout; // Cache handling. Try to look up this regex in the cache. CultureInfo culture = (options & RegexOptions.CultureInvariant) != 0 ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture; var key = new CachedCodeEntryKey(options, culture.ToString(), pattern); CachedCodeEntry cached = GetCachedCode(key, false); if (cached == null) { // Parse the input RegexTree tree = RegexParser.Parse(pattern, roptions, culture); // Extract the relevant information capnames = tree.CapNames; capslist = tree.CapsList; _code = RegexWriter.Write(tree); caps = _code.Caps; capsize = _code.CapSize; InitializeReferences(); tree = null; if (addToCache) { cached = GetCachedCode(key, true); } } else { caps = cached.Caps; capnames = cached.Capnames; capslist = cached.Capslist; capsize = cached.Capsize; _code = cached.Code; #if FEATURE_COMPILED factory = cached.Factory; #endif // Cache runner and replacement _runnerref = cached.Runnerref; _replref = cached.ReplRef; _refsInitialized = true; } #if FEATURE_COMPILED // if the compile option is set, then compile the code if it's not already if (UseOptionC() && factory == null) { factory = Compile(_code, roptions); if (addToCache && cached != null) { cached.AddCompiled(factory); } _code = null; } #endif }
private Regex(String pattern, RegexOptions options, TimeSpan matchTimeout, bool useCache) { RegexTree tree; CachedCodeEntry cached = null; string cultureKey = null; if (pattern == null) { throw new ArgumentNullException(nameof(pattern)); } if (options < RegexOptions.None || (((int)options) >> MaxOptionShift) != 0) { throw new ArgumentOutOfRangeException(nameof(options)); } if ((options & RegexOptions.ECMAScript) != 0 && (options & ~(RegexOptions.ECMAScript | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant #if DEBUG | RegexOptions.Debug #endif )) != 0) { throw new ArgumentOutOfRangeException(nameof(options)); } ValidateMatchTimeout(matchTimeout); // Try to look up this regex in the cache. We do this regardless of whether useCache is true since there's // really no reason not to. if ((options & RegexOptions.CultureInvariant) != 0) { cultureKey = CultureInfo.InvariantCulture.ToString(); // "English (United States)" } else { cultureKey = CultureInfo.CurrentCulture.ToString(); } var key = new CachedCodeEntryKey(options, cultureKey, pattern); cached = LookupCachedAndUpdate(key); this.pattern = pattern; roptions = options; internalMatchTimeout = matchTimeout; if (cached == null) { // Parse the input tree = RegexParser.Parse(pattern, roptions); // Extract the relevant information _capnames = tree._capnames; capslist = tree._capslist; _code = RegexWriter.Write(tree); _caps = _code._caps; capsize = _code._capsize; InitializeReferences(); tree = null; if (useCache) { cached = CacheCode(key); } } else { _caps = cached._caps; _capnames = cached._capnames; capslist = cached._capslist; capsize = cached._capsize; _code = cached._code; _runnerref = cached._runnerref; _replref = cached._replref; _refsInitialized = true; } }