Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swap backing for ParserStack from ArrayList to List<T>, improve performance #9969

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Change backing type for ParserStack as List<T>
  • Loading branch information
h3xds1nz committed Oct 15, 2024
commit c4750deeb064343420d2f099c273adc63ce23ca6
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ internal object ReadElement(Int64 startPosition,
CurrentContext.ObjectData = null;

#if DEBUG // ifdef's around Debug.Assert are necessary because stackDepth is only DEBUG defined
Debug.Assert( stackDepth == ReaderContextStack.Count );
Debug.Assert(stackDepth == ReaderContextStack.Count);
#endif

PopContext();
Expand Down Expand Up @@ -4081,12 +4081,12 @@ internal object FindResourceInParserStack(
// Check each one for the resource we are searching for until we reach a DependencyObject
// which is actually in the element tree. Stop at this one.

ParserStack contextStack = ReaderContextStack;
ParserStack<ReaderContextStackData> contextStack = ReaderContextStack;
BamlRecordReader reader = this;

while( contextStack != null )
while (contextStack != null)
{
for (int i = contextStack.Count-1; i >= 0; i--)
for (int i = contextStack.Count - 1; i >= 0; i--)
{
ReaderContextStackData stackData = (ReaderContextStackData) contextStack[i];
IDictionary dictionary = GetDictionaryFromContext(stackData, false /*toInsert*/);
Expand Down Expand Up @@ -4340,7 +4340,7 @@ internal void PushContext(
// Pos the reader context stack.
internal void PopContext()
{
ReaderContextStackData stackData = (ReaderContextStackData) ReaderContextStack.Pop();
ReaderContextStackData stackData = ReaderContextStack.Pop();

// If we're through with an Name scoping point, take it off the stack.
INameScope nameScope = NameScope.NameScopeFromObject(stackData.ObjectData);
Expand Down Expand Up @@ -5493,43 +5493,43 @@ internal XmlnsDictionary XmlnsDictionary

internal ReaderContextStackData CurrentContext
{
get { return (ReaderContextStackData) ReaderContextStack.CurrentContext; }
get { return ReaderContextStack.CurrentContext; }
}

internal ReaderContextStackData ParentContext
{
get { return (ReaderContextStackData) ReaderContextStack.ParentContext; }
get { return ReaderContextStack.ParentContext; }
}

internal object ParentObjectData
{
get
{
ReaderContextStackData contextData = ParentContext;
return contextData == null ? null : contextData.ObjectData;
return contextData?.ObjectData;
}
}

internal ReaderContextStackData GrandParentContext
{
get { return (ReaderContextStackData) ReaderContextStack.GrandParentContext; }
get { return ReaderContextStack.GrandParentContext; }
}

internal object GrandParentObjectData
{
get
{
ReaderContextStackData contextData = GrandParentContext;
return contextData == null ? null : contextData.ObjectData;
return contextData?.ObjectData;
}
}

internal ReaderContextStackData GreatGrandParentContext
{
get { return (ReaderContextStackData) ReaderContextStack.GreatGrandParentContext; }
get { return ReaderContextStack.GreatGrandParentContext; }
}

internal ParserStack ReaderContextStack
internal ParserStack<ReaderContextStackData> ReaderContextStack
{
get { return _contextStack; }
}
Expand Down Expand Up @@ -5575,7 +5575,7 @@ ReaderStream XamlReaderStream
}

// The stack of context information accumulated during reading.
internal ParserStack ContextStack
internal ParserStack<ReaderContextStackData> ContextStack
{
get { return _contextStack; }
set { _contextStack = value; }
Expand Down Expand Up @@ -5628,27 +5628,27 @@ internal BamlRecordReader PreviousBamlRecordReader
#region Data

// state vars
IComponentConnector _componentConnector;
object _rootElement;
bool _bamlAsForest;
bool _isRootAlreadyLoaded;
ArrayList _rootList;
ParserContext _parserContext; // XamlTypeMapper, namespace state, lang/space values
TypeConvertContext _typeConvertContext;
int _persistId;
ParserStack _contextStack = new ParserStack();
XamlParseMode _parseMode = XamlParseMode.Synchronous;
int _maxAsyncRecords;
IComponentConnector _componentConnector;
object _rootElement;
bool _bamlAsForest;
bool _isRootAlreadyLoaded;
ArrayList _rootList;
ParserContext _parserContext; // XamlTypeMapper, namespace state, lang/space values
TypeConvertContext _typeConvertContext;
int _persistId;
ParserStack<ReaderContextStackData> _contextStack = new();
XamlParseMode _parseMode = XamlParseMode.Synchronous;
int _maxAsyncRecords;
// end of state vars

Stream _bamlStream;
ReaderStream _xamlReaderStream;
BamlBinaryReader _binaryReader;
BamlRecordManager _bamlRecordManager;
BamlRecord _preParsedBamlRecordsStart = null;
BamlRecord _preParsedIndexRecord = null;
bool _endOfDocument = false;
bool _buildTopDown = true;
Stream _bamlStream;
ReaderStream _xamlReaderStream;
BamlBinaryReader _binaryReader;
BamlRecordManager _bamlRecordManager;
BamlRecord _preParsedBamlRecordsStart = null;
BamlRecord _preParsedIndexRecord = null;
bool _endOfDocument = false;
bool _buildTopDown = true;

// The outer BRR, when this one is nested.
BamlRecordReader _previousBamlRecordReader;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public BamlWriter(
_startDocumentWritten = false;
_depth = 0;
_closed = false;
_nodeTypeStack = new ParserStack();
_nodeTypeStack = new ParserStack<WriteStackNode>();
_assemblies = new Hashtable(7);
_extensionParser = new MarkupExtensionParser((IParserHelper)this, _parserContext);
_markupExtensionNodes = new ArrayList();
Expand Down Expand Up @@ -1282,23 +1282,23 @@ private void Push(BamlRecordType recordType, Type elementType)
// Pop an item off the node stack and return its type.
private BamlRecordType Pop()
{
WriteStackNode stackNode = _nodeTypeStack.Pop() as WriteStackNode;
WriteStackNode stackNode = _nodeTypeStack.Pop();
Debug.Assert(stackNode != null);
return stackNode.RecordType;
}

// Return the record type on the top of the stack
private BamlRecordType PeekRecordType()
{
WriteStackNode stackNode = _nodeTypeStack.Peek() as WriteStackNode;
WriteStackNode stackNode = _nodeTypeStack.Peek();
Debug.Assert(stackNode != null);
return stackNode.RecordType;
}

// Return the element type on the top of the stack
private Type PeekElementType()
{
WriteStackNode stackNode = _nodeTypeStack.Peek() as WriteStackNode;
WriteStackNode stackNode = _nodeTypeStack.Peek();
Debug.Assert(stackNode != null);
return stackNode.ElementType;
}
Expand All @@ -1309,16 +1309,10 @@ private void CheckEndAttributes()
{
if (_nodeTypeStack.Count > 0)
{
WriteStackNode parentNode = _nodeTypeStack.Peek() as WriteStackNode;
if (!parentNode.EndAttributesReached &&
parentNode.RecordType == BamlRecordType.ElementStart)
WriteStackNode parentNode = _nodeTypeStack.Peek();
if (!parentNode.EndAttributesReached && parentNode.RecordType == BamlRecordType.ElementStart)
{
XamlEndAttributesNode node = new XamlEndAttributesNode(
0,
0,
_depth,
false);
_bamlRecordWriter.WriteEndAttributes(node);
_bamlRecordWriter.WriteEndAttributes(new XamlEndAttributesNode(0, 0, _depth, false));
}
parentNode.EndAttributesReached = true;
}
Expand Down Expand Up @@ -1389,7 +1383,7 @@ public Type ElementType
// Stack of the type of nodes written to the baml stream. This is
// used for end-tag matching and basic structure checking. This
// contains WriteStackNode objects.
ParserStack _nodeTypeStack;
private readonly ParserStack<WriteStackNode> _nodeTypeStack;

// Cache of assemblies that are needed for type resolutions when
// doingIBamlSerialize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,7 @@
*
\***************************************************************************/

using System;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Globalization;
using MS.Utility;
using System.Collections.Specialized;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using MS.Internal;


#if !PBTCOMPILER

using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;

#endif

#if PBTCOMPILER
namespace MS.Internal.Markup
Expand All @@ -49,88 +24,71 @@ namespace System.Windows.Markup
/// Main goal is to track current/parent context with a minimum of overhead.
/// This class is internal so it can be shared with the BamlRecordReader
/// </summary>
internal class ParserStack : ArrayList
internal sealed class ParserStack<T> : List<T> where T : class
{
/// <summary>
/// Creates a default ParserStack
/// </summary>
internal ParserStack() : base()
{
}
internal ParserStack() : base() { }

/// <summary>
/// Creates a clone.
/// </summary>
private ParserStack(ICollection collection) : base(collection)
public void Push(T item)
{
Add(item);
}

#region StackOverrides

public void Push(object o)
public T Pop()
{
Add(o);
}

public object Pop()
{
object o = this[Count - 1];
T item = this[Count - 1];
RemoveAt(Count - 1);
return o;

return item;
}

#if !PBTCOMPILER
public object Peek()
public T Peek()
{
// Die if peeking on empty stack
return this[Count - 1];
}
#endif

public override object Clone()
public List<T> Clone()
{
return new ParserStack(this);
return new List<T>(this);
}

#endregion // StackOverrides

#region Properties

/// <summary>
/// Returns the Current Context on the stack
/// </summary>
internal object CurrentContext
internal T CurrentContext
{
get { return Count > 0 ? this[Count - 1] : null; }
get => Count > 0 ? this[Count - 1] : null;
}

/// <summary>
/// Returns the Parent of the Current Context
/// </summary>
internal object ParentContext
internal T ParentContext
{
get { return Count > 1 ? this[Count - 2] : null; }
get => Count > 1 ? this[Count - 2] : null;
}

/// <summary>
/// Returns the GrandParent of the Current Context
/// </summary>
internal object GrandParentContext
internal T GrandParentContext
{
get { return Count > 2 ? this[Count - 3] : null; }
get => Count > 2 ? this[Count - 3] : null;
}

#if !PBTCOMPILER
/// <summary>
/// Returns the GreatGrandParent of the Current Context
/// </summary>
internal object GreatGrandParentContext
internal T GreatGrandParentContext
{
get { return Count > 3 ? this[Count - 4] : null; }
get => Count > 3 ? this[Count - 4] : null;
}
#endif

#endregion // Properties

}
}
Loading