提交 906dcdd0 编写于 作者: V vsadov

use refs in TextKeyedCache

上级 5529bed3
......@@ -15,26 +15,6 @@ namespace Roslyn.Utilities
{
internal class TextKeyedCache<T> where T : class
{
// entry in the local cache
private struct LocalEntry
{
// full text of the item
public string Text;
// hash code of the entry
public int HashCode;
// item
public T Item;
}
// entry in the shared cache
private struct SharedEntry
{
public int HashCode;
public SharedEntryValue Entry;
}
// immutable tuple - text and corresponding item
// reference type because we want atomic assignments
private class SharedEntryValue
......@@ -71,17 +51,17 @@ public SharedEntryValue(string Text, T item)
// local cache
// simple fast and not threadsafe cache
// with limited size and "last add wins" expiration policy
private readonly LocalEntry[] _localTable = new LocalEntry[LocalSize];
private readonly (string Text, int HashCode, T Item)[] _localTable = new(string Text, int HashCode, T Item)[LocalSize];
// shared threadsafe cache
// slightly slower than local cache
// we read this cache when having a miss in local cache
// writes to local cache will update shared cache as well.
private static readonly SharedEntry[] s_sharedTable = new SharedEntry[SharedSize];
private static readonly (int HashCode, SharedEntryValue Entry)[] s_sharedTable = new(int HashCode, SharedEntryValue Entry)[SharedSize];
// store a reference to shared cache locally
// accessing a static field of a generic type could be nontrivial
private readonly SharedEntry[] _sharedTableInst = s_sharedTable;
private readonly (int HashCode, SharedEntryValue Entry)[] _sharedTableInst = s_sharedTable;
private readonly StringTable _strings;
......@@ -131,31 +111,27 @@ public void Free()
internal T FindItem(char[] chars, int start, int len, int hashCode)
{
// capture array to avoid extra range checks
var arr = _localTable;
var idx = LocalIdxFromHash(hashCode);
// get direct element reference to avoid extra range checks
ref var localSlot = ref _localTable[LocalIdxFromHash(hashCode)];
var text = arr[idx].Text;
var text = localSlot.Text;
if (text != null && arr[idx].HashCode == hashCode)
if (text != null && localSlot.HashCode == hashCode)
{
if (StringTable.TextEquals(text, chars, start, len))
{
return arr[idx].Item;
return localSlot.Item;
}
}
SharedEntryValue e = FindSharedEntry(chars, start, len, hashCode);
if (e != null)
{
// PERF: the following code does element-wise assignment of a struct
// because current JIT produces better code compared to
// arr[idx] = new LocalEntry(...)
arr[idx].HashCode = hashCode;
arr[idx].Text = e.Text;
localSlot.HashCode = hashCode;
localSlot.Text = e.Text;
var tk = e.Item;
arr[idx].Item = tk;
localSlot.Item = tk;
return tk;
}
......@@ -169,12 +145,13 @@ private SharedEntryValue FindSharedEntry(char[] chars, int start, int len, int h
int idx = SharedIdxFromHash(hashCode);
SharedEntryValue e = null;
int hash;
// we use quadratic probing here
// bucket positions are (n^2 + n)/2 relative to the masked hashcode
for (int i = 1; i < SharedBucketSize + 1; i++)
{
e = arr[idx].Entry;
int hash = arr[idx].HashCode;
(hash, e) = arr[idx];
if (e != null)
{
......@@ -207,11 +184,10 @@ internal void AddItem(char[] chars, int start, int len, int hashCode, T item)
AddSharedEntry(hashCode, e);
// add to the local table too
var arr = _localTable;
var idx = LocalIdxFromHash(hashCode);
arr[idx].HashCode = hashCode;
arr[idx].Text = text;
arr[idx].Item = item;
ref var localSlot = ref _localTable[LocalIdxFromHash(hashCode)];
localSlot.HashCode = hashCode;
localSlot.Text = text;
localSlot.Item = item;
}
private void AddSharedEntry(int hashCode, SharedEntryValue e)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册