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

Make generic composition information more efficient #85623

Merged
merged 3 commits into from
May 2, 2023

Conversation

MichalStrehovsky
Copy link
Member

@MichalStrehovsky MichalStrehovsky commented May 2, 2023

Before this PR, we tracked information about generic composition of a MethodTable this way:

  • Each generic instance MethodTable had a pointer to the generic definition MethodTable.
  • Each generic instance MethodTable had a pointer to its generic composition: a variable sized data structure that had a small header (number of elements, a flag whether it's variant), followed by pointers to MethodTables of components, optionally followed by variance information for each argument.

This works, but it's not particularly efficient, especially in light of some facts that didn't exist at the time this scheme was introduced.

In particular:

  • The number of generic parameters can be obtained from the generic definition, no need to duplicate it into instances.
  • The variance information can be obtained from the generic definition, no need to duplicate it into instances.
  • It makes no sense to indirect to a single-element list - the list can be bypassed if arity is 1.

This PR addresses all of the above.

Saves about 0.5% in size for BasicMinimalApi, improves startup (the composition no longer needs to be dehydrated because it's relative pointers now), and improves working set (the composition stuff accounted for 100 kB of private dehydrated working set in BasicMinimalApi).

Cc @dotnet/ilc-contrib

Remove parameter count and flag. This is available in the generic definition MethodTable.
Use `MethodTableList` instead of `EETypeRef`. This allows emitting the list as relative pointers.
@ghost
Copy link

ghost commented May 2, 2023

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Before this PR, we tracked information about generic composition of a MethodTable this way:

  • Each generic instance MethodTable had a pointer to the generic definition MethodTable.
  • Each generic instance MethodTable had a pointer to its generic composition: a variable sized data structure that had a small header (number of elements, a flag whether it's variant), followed by pointers to MethodTables of components, optionally followed by variance information for each argument.

This works, but it's not particularly efficient, especially in light of some facts that didn't exist at the time this scheme was introduced.

In particular:

  • The number of generic parameters can be obtained from the generic definition, no need to duplicate it into instances.
  • The variance information can be obtained from the generic definition, no need to duplicate it into instances.
  • It makes no sense to indirect to a single-element list - the list can be bypassed if arity is 1.

This PR addresses all of the above.

Saves about 0.5% in size for BasicMinimalApi, improves startup (the composition no longer needs to be dehydrated because it's relative pointers now), and improves working set (the composition stuff accounted for 100 kB of private dehydrated working set in BasicMinimalApi).

Author: MichalStrehovsky
Assignees: -
Labels:

area-NativeAOT-coreclr

Milestone: -

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@agocke
Copy link
Member

agocke commented May 2, 2023

Very nice. Out of curiosity -- do we need type parameters often for instantiated types? My uninformed guess would be that we would need type arguments much more often.

@jkotas
Copy link
Member

jkotas commented May 2, 2023

The code does not use these type parameters. If the shared generic code needs these type parameters, they will get duplicated in the generic dictionary where they are fast to access.

These type parameters are only used for reflection and complex casts. Complex casts are behind a cache and so computing the answer of the complex cast is not perf critical.

@ghost ghost locked as resolved and limited conversation to collaborators Jun 1, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants