Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Make Activator.CreateInstance<T> 50% faster #8000

Merged
merged 3 commits into from Feb 22, 2020

Conversation

MichalStrehovsky
Copy link
Member

Ratio
new 1.0
Activator.CreateInstance old 2.36
Activator.CreateInstance new 1.26

The existing implementation was a bit awkward because of how the intrinsic was implemented in .NET Native (the intrinsic in .NET Native did allocate+call default constructor - in CoreRT we have a separate intrinsic for "get default constructor").

.NET Native required an awkward dance around "uh-oh, this type doesn't have a default constructor, what should I call now". None of that is needed in CoreRT, but we had it there so that we don't diverge too much. It was 3x faster than CoreCLR anyway. We no longer have to worry about diverging and it seems like CoreCLR might be getting a perf boost here for .NET 5, so let's not stay behind.

In this commit:

  • Removing the s_createInstanceMissingDefaultConstructor flag - we can do this check quickly by comparing the retrieved default constructor with DefaultConstructorOf<ClassWithMissingConstructor>.
  • Removing upfront checks for arrays/strings/interfaces. We no longer have to worry about accidentally allocating them. We detect them as not having a default ctor.
  • For an additional perf boost, exposing AllocatorOf<T>. This is a new intrinsic that expands to the existing AllocatorOf dictionary entry that represents the optimized allocator method for T. This entry is normally only used in universal shared code, but it's valid to use it outside of that.
  • Extra compiler support for dictionary entries that are double indirections. AllocatorOf is doubly-indirect for USG reasons. We should probably keep that for universal shared code anyway.

There's still room left for improvement - RyuJIT currently doesn't have support for the RawCalli intrinsic and generates a normal calli for them. Normal calli needs to check for fat function pointers. These pointers are never fat pointers.

|                              | Ratio |
|------------------------------|------:|
| new                          |   1.0 |
| Activator.CreateInstance old |  2.36 |
| Activator.CreateInstance new |  1.26 |

The existing implementation was a bit awkward because of how the intrinsic was implemented in .NET Native (the intrinsic in .NET Native did allocate+call default constructor - in CoreRT we have a separate intrinsic for "get default constructor").

.NET Native required an awkward dance around "uh-oh, this type doesn't have a default constructor, what should I call now". None of that is needed in CoreRT, but we had it there so that we don't diverge too much. It was 3x faster than CoreCLR anyway. We no longer have to worry about diverging and it seems like CoreCLR might be getting a perf boost here for .NET 5, so let's not stay behind.

In this commit:
* Removing the `s_createInstanceMissingDefaultConstructor` flag - we can do this check quickly by comparing the retrieved default constructor with `DefaultConstructorOf<ClassWithMissingConstructor>`.
* Removing upfront checks for arrays/strings/interfaces. We no longer have to worry about accidentally allocating them. We detect them as not having a default ctor.
* For an additional perf boost, exposing `AllocatorOf<T>`. This is a new intrinsic that expands to the existing `AllocatorOf` dictionary entry that represents the optimized allocator method for T. This entry is normally only used in universal shared code, but it's valid to use it outside of that.
* Extra compiler support for dictionary entries that are double indirections. `AllocatorOf` is doubly-indirect for USG reasons. We should probably keep that for universal shared code anyway.

There's still room left for improvement - RyuJIT currently doesn't have support for the `RawCalli` intrinsic and generates a normal calli for them. Normal calli needs to check for fat function pointers. These pointers are never fat pointers.
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 :-)

@jkotas jkotas merged commit 9d81d82 into dotnet:master Feb 22, 2020
@MichalStrehovsky MichalStrehovsky deleted the fastActivator branch February 23, 2020 06:06
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants