未验证 提交 b79c5a5c 编写于 作者: V Vladimir Sadov 提交者: GitHub

Merge pull request #26156 from VSadov/isReusable15_7

In Object serialization, do not keep track of non-reusable green nodes.
......@@ -22,6 +22,8 @@ private MessageProvider()
{
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
// write nothing, always read/deserialized as global Instance
......
......@@ -15,7 +15,7 @@ internal partial class Lexer
// From what I see in our own codebase, tokens longer then 40-50 chars are
// not very common.
// So it seems reasonable to limit the sizes to some round number like 42.
private const int MaxCachedTokenSize = 42;
internal const int MaxCachedTokenSize = 42;
private enum QuickScanState : byte
{
......
......@@ -66,6 +66,9 @@ internal SyntaxToken(ObjectReader reader)
this.flags |= NodeFlags.IsNotMissing; //note: cleared by subclasses representing missing tokens
}
internal override bool ShouldReuseInSerialization => base.ShouldReuseInSerialization &&
FullWidth < Lexer.MaxCachedTokenSize;
//====================
public override bool IsToken => true;
......
......@@ -34,6 +34,9 @@ static SyntaxTrivia()
public override bool IsTrivia => true;
internal override bool ShouldReuseInSerialization => this.Kind == SyntaxKind.WhitespaceTrivia &&
FullWidth < Lexer.MaxCachedTokenSize;
internal override void WriteTo(ObjectWriter writer)
{
base.WriteTo(writer);
......
......@@ -161,6 +161,8 @@ private TypeWithOneMember(ObjectReader reader)
: (T)reader.ReadValue();
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
if (typeof(T).IsEnum)
......@@ -218,6 +220,8 @@ private TypeWithTwoMembers(ObjectReader reader)
_member2 = (S)reader.ReadValue();
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
writer.WriteValue(_member1);
......@@ -276,6 +280,8 @@ private TypeWithManyMembers(ObjectReader reader)
}
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
writer.WriteInt32(_members.Length);
......@@ -511,6 +517,8 @@ private PrimitiveArrayMemberTest(ObjectReader reader)
TestReadingPrimitiveArrays(reader);
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
TestWritingPrimitiveArrays(writer);
......@@ -804,6 +812,8 @@ private PrimitiveMemberTest(ObjectReader reader)
TestReadingPrimitiveAPIs(reader);
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
TestWritingPrimitiveAPIs(writer);
......@@ -886,6 +896,8 @@ private PrimitiveValueTest(ObjectReader reader)
TestReadingPrimitiveValues(reader);
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
TestWritingPrimitiveValues(writer);
......@@ -1146,6 +1158,30 @@ public void TestObjectGraph()
TestRoundTripValue(new Node("x", oneNode, oneNode, oneNode, oneNode));
}
[Fact]
public void TestReuse()
{
var oneNode = new Node("one");
var n1 = new Node("x", oneNode, oneNode, oneNode, oneNode);
var n2 = RoundTripValue(n1, recursive: true);
Assert.Same(n2.Children[0], n2.Children[1]);
Assert.Same(n2.Children[1], n2.Children[2]);
Assert.Same(n2.Children[2], n2.Children[3]);
}
[Fact]
public void TestReuseNegative()
{
var oneNode = new Node("one", isReusable: false);
var n1 = new Node("x", oneNode, oneNode, oneNode, oneNode);
var n2 = RoundTripValue(n1, recursive: true);
Assert.NotSame(n2.Children[0], n2.Children[1]);
Assert.NotSame(n2.Children[1], n2.Children[2]);
Assert.NotSame(n2.Children[2], n2.Children[3]);
}
[Fact]
public void TestWideObjectGraph()
{
......@@ -1197,6 +1233,7 @@ private class Node : IObjectWritable, IEquatable<Node>
{
internal readonly string Name;
internal readonly Node[] Children;
private readonly bool _isReusable = true;
public Node(string name, params Node[] children)
{
......@@ -1204,6 +1241,12 @@ public Node(string name, params Node[] children)
this.Children = children;
}
public Node(string name, bool isReusable)
: this(name)
{
this._isReusable = isReusable;
}
private Node(ObjectReader reader)
{
this.Name = reader.ReadString();
......@@ -1212,6 +1255,8 @@ private Node(ObjectReader reader)
private static readonly Func<ObjectReader, object> s_createInstance = r => new Node(r);
bool IObjectWritable.ShouldReuseInSerialization => _isReusable;
public void WriteTo(ObjectWriter writer)
{
writer.WriteString(this.Name);
......
......@@ -138,6 +138,8 @@ internal DiagnosticInfo GetInstanceWithSeverity(DiagnosticSeverity severity)
#region Serialization
bool IObjectWritable.ShouldReuseInSerialization => false;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
this.WriteTo(writer);
......
......@@ -93,6 +93,8 @@ private LocalizableResourceString(ObjectReader reader)
}
}
bool IObjectWritable.ShouldReuseInSerialization => false;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
writer.WriteType(_resourceSource);
......
......@@ -9,5 +9,12 @@ namespace Roslyn.Utilities
internal interface IObjectWritable
{
void WriteTo(ObjectWriter writer);
/// <summary>
/// Returns 'true' when the same instance could be used more than once.
/// Instances that return 'false' should not be tracked for the purpose
/// of de-duplication while serializing/deserializing.
/// </summary>
bool ShouldReuseInSerialization { get; }
}
}
......@@ -32,7 +32,7 @@ internal static class ObjectBinder
/// </summary>
private static readonly Dictionary<Type, int> s_typeToIndex = new Dictionary<Type, int>();
private static readonly List<Type> s_types = new List<Type>();
private static readonly List<Func<ObjectReader, object>> s_typeReaders = new List<Func<ObjectReader, object>>();
private static readonly List<Func<ObjectReader, IObjectWritable>> s_typeReaders = new List<Func<ObjectReader, IObjectWritable>>();
/// <summary>
/// Gets an immutable copy of the state of this binder. This copy does not need to be
......@@ -51,7 +51,7 @@ public static ObjectBinderSnapshot GetSnapshot()
}
}
public static void RegisterTypeReader(Type type, Func<ObjectReader, object> typeReader)
public static void RegisterTypeReader(Type type, Func<ObjectReader, IObjectWritable> typeReader)
{
lock (s_gate)
{
......
......@@ -6,16 +6,16 @@
namespace Roslyn.Utilities
{
internal struct ObjectBinderSnapshot
internal readonly struct ObjectBinderSnapshot
{
private readonly Dictionary<Type, int> _typeToIndex;
private readonly ImmutableArray<Type> _types;
private readonly ImmutableArray<Func<ObjectReader, object>> _typeReaders;
private readonly ImmutableArray<Func<ObjectReader, IObjectWritable>> _typeReaders;
public ObjectBinderSnapshot(
Dictionary<Type, int> typeToIndex,
List<Type> types,
List<Func<ObjectReader, object>> typeReaders)
List<Func<ObjectReader, IObjectWritable>> typeReaders)
{
_typeToIndex = new Dictionary<Type, int>(typeToIndex);
_types = types.ToImmutableArray();
......@@ -28,7 +28,7 @@ public int GetTypeId(Type type)
public Type GetTypeFromId(int typeId)
=> _types[typeId];
public Func<ObjectReader, object> GetTypeReaderFromId(int typeId)
public Func<ObjectReader, IObjectWritable> GetTypeReaderFromId(int typeId)
=> _typeReaders[typeId];
}
}
......@@ -607,7 +607,12 @@ private object ReadObject()
// recursive: read and construct instance immediately from member elements encoding next in the stream
var instance = typeReader(this);
_objectReferenceMap.AddValue(objectId, instance);
if (instance.ShouldReuseInSerialization)
{
_objectReferenceMap.AddValue(objectId, instance);
}
return instance;
}
......
......@@ -361,10 +361,14 @@ public void Dispose()
public bool TryGetReferenceId(object value, out int referenceId)
=> _valueToIdMap.TryGetValue(value, out referenceId);
public void Add(object value)
public void Add(object value, bool isReusable)
{
var id = _nextId++;
_valueToIdMap.Add(value, id);
if (isReusable)
{
_valueToIdMap.Add(value, id);
}
}
}
......@@ -432,7 +436,7 @@ private unsafe void WriteStringValue(string value)
}
else
{
_stringReferenceMap.Add(value);
_stringReferenceMap.Add(value, isReusable: true);
if (value.IsValidUnicodeString())
{
......@@ -801,9 +805,9 @@ private void WriteObject(object instance, IObjectWritable instanceAsWritableOpt)
private void WriteObjectWorker(IObjectWritable writable)
{
// emit object header up front
_objectReferenceMap.Add(writable);
_objectReferenceMap.Add(writable, writable.ShouldReuseInSerialization);
// emit object header up front
_writer.Write((byte)EncodingKind.Object);
// Directly write out the type-id for this object. i.e. no need to write out the 'Type'
......
......@@ -437,6 +437,10 @@ internal GreenNode(ObjectReader reader)
}
}
bool IObjectWritable.ShouldReuseInSerialization => ShouldReuseInSerialization;
internal virtual bool ShouldReuseInSerialization => this.IsCacheable;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
this.WriteTo(writer);
......
......@@ -57,6 +57,8 @@ private SyntaxAnnotation(ObjectReader reader)
this.Data = reader.ReadString();
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
writer.WriteInt64(_id);
......
......@@ -18,6 +18,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private Sub New()
End Sub
Private ReadOnly Property IObjectWritable_ShouldReuseInSerialization As Boolean Implements IObjectWritable.ShouldReuseInSerialization
Get
Return True
End Get
End Property
Private Sub WriteTo(writer As ObjectWriter) Implements IObjectWritable.WriteTo
' don't write anything since we always return the shared 'Instance' when read.
End Sub
......
......@@ -134,7 +134,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Private Const s_CHARPROP_LENGTH = &H180
' Maximum length of a token to scan
Friend Const MAXTOKENSIZE = 42
Friend Const MAX_CACHED_TOKENSIZE = 42
Shared Sub New()
Debug.Assert(s_charProperties.Length = s_CHARPROP_LENGTH)
......@@ -183,7 +183,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Dim index = _lineBufferOffset And s_PAGE_MASK
Dim qtStart = index
Dim limit = index + Math.Min(MAXTOKENSIZE, _bufferLen - offset)
Dim limit = index + Math.Min(MAX_CACHED_TOKENSIZE, _bufferLen - offset)
limit = Math.Min(limit, pageArr.Length)
Dim hashCode As Integer = Hash.FnvOffsetBias
......
......@@ -89,6 +89,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Me._trailingTrivia = DirectCast(reader.ReadValue(), GreenNode)
End Sub
Private ReadOnly Property IObjectWritable_ShouldReuseInSerialization As Boolean Implements IObjectWritable.ShouldReuseInSerialization
Get
Return ShouldCacheTriviaInfo(_leadingTrivia, _trailingTrivia)
End Get
End Property
Public Sub WriteTo(writer As ObjectWriter) Implements IObjectWritable.WriteTo
writer.WriteValue(_leadingTrivia)
writer.WriteValue(_trailingTrivia)
......@@ -190,6 +196,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
End If
End Sub
Friend Overrides ReadOnly Property ShouldReuseInSerialization As Boolean
Get
Return MyBase.ShouldReuseInSerialization AndAlso
Me.FullWidth < Scanner.MAX_CACHED_TOKENSIZE
End Get
End Property
Friend Overrides Sub WriteTo(writer As ObjectWriter)
MyBase.WriteTo(writer)
writer.WriteString(Me._text)
......
......@@ -49,6 +49,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
ObjectBinder.RegisterTypeReader(GetType(SyntaxTrivia), Function(r) New SyntaxTrivia(r))
End Sub
Friend Overrides ReadOnly Property ShouldReuseInSerialization As Boolean
Get
Select Case Me.Kind
Case SyntaxKind.WhitespaceTrivia,
SyntaxKind.EndOfLineTrivia,
SyntaxKind.LineContinuationTrivia,
SyntaxKind.DocumentationCommentExteriorTrivia,
SyntaxKind.ColonTrivia
Return True
Case Else
Return False
End Select
End Get
End Property
Friend Overrides Sub WriteTo(writer As ObjectWriter)
MyBase.WriteTo(writer)
writer.WriteString(Me._text)
......
......@@ -113,6 +113,8 @@ internal partial class SymbolTreeInfo : IObjectWritable
return result;
}
bool IObjectWritable.ShouldReuseInSerialization => true;
public void WriteTo(ObjectWriter writer)
{
writer.WriteString(SerializationFormat);
......
......@@ -143,6 +143,8 @@ private void WriteFormatAndChecksum(ObjectWriter writer, string formatVersion)
return false;
}
bool IObjectWritable.ShouldReuseInSerialization => true;
public void WriteTo(ObjectWriter writer)
{
_literalInfo.WriteTo(writer);
......
......@@ -10,6 +10,8 @@ internal partial class BloomFilter : IObjectWritable
{
private const string SerializationFormat = "2";
bool IObjectWritable.ShouldReuseInSerialization => true;
public void WriteTo(ObjectWriter writer)
{
writer.WriteString(SerializationFormat);
......
......@@ -15,6 +15,7 @@ internal class SpellChecker : IObjectWritable, IChecksummedObject
private const string SerializationFormat = "3";
public Checksum Checksum { get; }
private readonly BKTree _bkTree;
public SpellChecker(Checksum checksum, BKTree bKTree)
......@@ -42,6 +43,8 @@ public IList<string> FindSimilarWords(string value, bool substringsAreSimilar)
return array;
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
writer.WriteString(SerializationFormat);
......
......@@ -88,6 +88,8 @@ public override unsafe string ToString()
return !(left == right);
}
bool IObjectWritable.ShouldReuseInSerialization => true;
public void WriteTo(ObjectWriter writer)
=> _checkSum.WriteTo(writer);
......
......@@ -98,6 +98,8 @@ public override int GetHashCode()
return !(left == right);
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
ProjectId.WriteTo(writer);
......
......@@ -204,6 +204,8 @@ internal class DocumentAttributes : IChecksummedObject, IObjectWritable
return new DocumentAttributes(newId, newName, newFolders, newSourceCodeKind, newFilePath, newIsGenerated);
}
bool IObjectWritable.ShouldReuseInSerialization => true;
public void WriteTo(ObjectWriter writer)
{
Id.WriteTo(writer);
......
......@@ -84,6 +84,8 @@ public override int GetHashCode()
return this.Id.GetHashCode();
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
writer.WriteGuid(Id);
......
......@@ -486,6 +486,8 @@ internal class ProjectAttributes : IChecksummedObject, IObjectWritable
newHasAllInformation);
}
bool IObjectWritable.ShouldReuseInSerialization => true;
public void WriteTo(ObjectWriter writer)
{
Id.WriteTo(writer);
......
......@@ -81,6 +81,8 @@ public override int GetHashCode()
return this.Id.GetHashCode();
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
writer.WriteGuid(Id);
......
......@@ -112,6 +112,8 @@ public SolutionAttributes(SolutionId id, VersionStamp version, string filePath)
FilePath = filePath;
}
bool IObjectWritable.ShouldReuseInSerialization => true;
public void WriteTo(ObjectWriter writer)
{
Id.WriteTo(writer);
......
......@@ -193,6 +193,8 @@ internal static bool CanReusePersistedVersion(VersionStamp baseVersion, VersionS
return baseVersion._utcLastModified == persistedVersion._utcLastModified;
}
bool IObjectWritable.ShouldReuseInSerialization => true;
void IObjectWritable.WriteTo(ObjectWriter writer)
{
WriteTo(writer);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册