Skip to content

Implement optimizations for constructing collections from collection literals #68785

@cston

Description

@cston

Implement various optimizations for constructing collections from collection literals, including:

  • Use inline array for the collection builder method ReadOnlySpan<T> argument when the span cannot escape. #69227

  • Use inline arrays for collection expressions with span target types #69412

  • Use existing optimization for ReadOnlySpan<T> to blit data into the assembly section when values are constants of primitive type. #69412

  • Emit [] as Array.Empty<T>() when the target type is IEnumerable<T> or T[]. #69355

  • Emit [] as default(Span<T>) when the target type is Span<T>. #70260

  • Avoid intermediate List<T> if all spread elements are countable and collection satisfies certain heuristics. #69875

  • Use EnsureCapacity(int) for collection initializer types with no spreads; potentially also when length is known and collection satisfies certain heuristics.

  • Use CollectionsMarshal.SetCount<T>(List<T>, int) and CollectionsMarshal.AsSpan<T>(List<T>) to create a List<T> when length is known and collection satisfies certain heuristics; fallback to List<T>..ctor(int capacity) if CollectionsMarshal is not available. #70197

  • Use ImmutableCollectionsMarshal.AsImmutableArray<T>(T[]) to create an ImmutableArray<T>. #70222

  • Use .ctor(int capacity) for some BCL types when EnsureCapacity(int) is not available, or not available downlevel.

  • Emit Enumerable.TryGetNonEnumeratedCount() and avoid intermediate List<T> at runtime. Poor codegen for collection expression spread (IEnumerable<T> -> ImmutableArray<T>) #71296

  • Use List<T>.AddRange(IEnumerable<T>) when adding a spread to a List<T> if the spread implements ICollection<T>, or if the spread implements IEnumerable<T> and does not have a struct enumerator; use CollectionExtensions.AddRange<T>(List<T>, ReadOnlySpan<T>) if the spread is a span; otherwise use foreach and List<T>.Add(T).

  • Use CollectionsMarshal.AsSpan<T>(List<T>) to create a ReadOnlySpan<T> from the temporary List<T> when creating a [CollectionBuilder] collection from a collection literal of unknown length.

  • emit foreach (var x in y ?? []) as a lifted null check that executes nothing if 'y' is null.

  • When producing an IEnumerable<T> use the same codegen pattern that yield does. Specifically, where the instance created is both an IEnumerable<T> and its own IEnumerator<T> for the very first iteration of the enumerable on the same thread. This avoids an extra allocation for hte common case of producing an IEnumerable<T> just to have it be immediately iterated.

  • Avoid heap allocation for spread in [.. x ? [y] : []]. (moved to #69277)

  • Avoid heap allocation for collection in foreach (bool x in [true, false]). (moved to #69277)

Relates to test plan #66418

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions