Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit fc7cd1b

Browse files
gfoidlstephentoub
authored andcommitted
Queue<T> optimization of (Try)Dequeue (#26087)
* Queue RCE With value types the effect is not so big, because there is still one (manual) check for bounds. For reference types one bounds-check can be saved, so there is a win. In MoveNext the conditional is with if, so the JIT can produce better code. * MoveNext uses temp-Variable for register access instead of memory access * Addressed PR feedback * #26087 (review) * #26087 (review)
1 parent 7320c34 commit fc7cd1b

File tree

1 file changed

+19
-8
lines changed
  • src/System.Collections/src/System/Collections/Generic

1 file changed

+19
-8
lines changed

src/System.Collections/src/System/Collections/Generic/Queue.cs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -234,15 +234,18 @@ IEnumerator IEnumerable.GetEnumerator()
234234
// InvalidOperationException.
235235
public T Dequeue()
236236
{
237+
int head = _head;
238+
T[] array = _array;
239+
237240
if (_size == 0)
238241
{
239242
ThrowForEmptyQueue();
240243
}
241244

242-
T removed = _array[_head];
245+
T removed = array[head];
243246
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
244247
{
245-
_array[_head] = default(T);
248+
array[head] = default;
246249
}
247250
MoveNext(ref _head);
248251
_size--;
@@ -252,16 +255,19 @@ public T Dequeue()
252255

253256
public bool TryDequeue(out T result)
254257
{
258+
int head = _head;
259+
T[] array = _array;
260+
255261
if (_size == 0)
256262
{
257-
result = default(T);
263+
result = default;
258264
return false;
259265
}
260266

261-
result = _array[_head];
267+
result = array[head];
262268
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
263269
{
264-
_array[_head] = default(T);
270+
array[head] = default;
265271
}
266272
MoveNext(ref _head);
267273
_size--;
@@ -367,10 +373,15 @@ private void SetCapacity(int capacity)
367373
// Increments the index wrapping it if necessary.
368374
private void MoveNext(ref int index)
369375
{
370-
// It is tempting to use the remainder operator here but it is actually much slower
371-
// than a simple comparison and a rarely taken branch.
376+
// It is tempting to use the remainder operator here but it is actually much slower
377+
// than a simple comparison and a rarely taken branch.
378+
// JIT produces better code than with ternary operator ?:
372379
int tmp = index + 1;
373-
index = (tmp == _array.Length) ? 0 : tmp;
380+
if (tmp == _array.Length)
381+
{
382+
tmp = 0;
383+
}
384+
index = tmp;
374385
}
375386

376387
private void ThrowForEmptyQueue()

0 commit comments

Comments
 (0)