Improve ArrayList and NodeList#396
Conversation
src/Esprima/ArrayList.cs
Outdated
| if (value < (_items?.Length ?? 0)) | ||
| { | ||
| T[] array = new T[value]; | ||
| if (_count > 0) | ||
| { | ||
| Array.Copy(_items, 0, array, 0, _count); | ||
| } | ||
| _items = array; | ||
| } | ||
| else | ||
| { | ||
| _items = null; | ||
| ThrowArgumentOutOfRangeException(nameof(value), value, null); | ||
| } | ||
|
|
||
| EnsureCapacity(value); |
There was a problem hiding this comment.
I'd stick to the original logic here because the change leads to a bit confusing API. For example:
var al = new ArrayList<int>(initialCapacity: 4);
al.Capacity = 5;
var c = al.Capacity;
c is 8 instead of 5, which is kinda unexpected after explicitly setting Capacity to 5 in the previous line. At least, BCL types like List<T> don't have such behavior.
There was a problem hiding this comment.
Fair enough, I'll revert the capacity related changes.
There was a problem hiding this comment.
I had problems with the Capacity property only, EnsureCapacity seemed ok in other places. But I'm also ok with the original logic.
| } | ||
|
|
||
| [Benchmark] | ||
| public object For_DirectIndexing() |
There was a problem hiding this comment.
Damn, nice oversight on my part... This pretty much messed up the benchmark results.
Nice catch! 👍
Sounds like it's worth a try. Thanks to our source generation magic, probably it wouldn't be too tedious. So, I'm looking forward to the new benchmark results! ;) |
|
OK, I've reverted most of the PR and should now only contain the gist of indexing improvements. main vs this branch: Esprima.Benchmark.NodeListEnumerationBenchmark
|
* better indexer with less IL * encapsulate EnsureCapacity * remove TrimExcess
|
FWIW, I assume that spans' worse performance for smaller lists is caused by the initial cost of constructing a span. So, for read-only iteration |
adams85
left a comment
There was a problem hiding this comment.
Those indexer perf gains are serious. Kudos!
|
Thanks for helping out and getting this finalized! |
I was checking how much faster it is to use span instead of indexing (Jint uses indexing at the moment) and I though that it shouldn't have that much difference as it had so tweaked code a bit.
nameof(something)to causeldstring, more fine-grained ThrowHelper to the rescueEnsureCapacityas single method to resizeTrimExcessas I didn't see much point in it performance wiseResults
Modified benchmark (no boxing for result) was used against both
mainand this PR. The couple byte allocations in 0 size test case ForLoopBenchmark is quite curious, but didn't find out the reason. Now indexing is as fast as spans or even faster for small lists (0-1), spans start to shine when iterating more items.💡 We maybe should consider converting visitors to use foreach + span.
Esprima.Benchmark.AstTreeWalkBenchmark
Esprima.Benchmark.FileParsingBenchmark
Esprima.Benchmark.NodeListEnumerationBenchmark
Esprima.Benchmark.VisitorBenchmark