summaryrefslogtreecommitdiff
path: root/eng
diff options
context:
space:
mode:
authorNick Craver <nrcraver@gmail.com>2018-11-04 02:11:47 -0500
committerJan Kotas <jkotas@microsoft.com>2018-11-04 00:11:47 -0700
commit6d9fc60df3b721eab98ca08386a1f01358f93839 (patch)
tree5fd34a142d6daf5b736b61d35edc056bdd97418a /eng
parentf2d56a9b2b5737ab04d322f03404b9faef9e5293 (diff)
downloadcoreclr-6d9fc60df3b721eab98ca08386a1f01358f93839.tar.gz
coreclr-6d9fc60df3b721eab98ca08386a1f01358f93839.tar.bz2
coreclr-6d9fc60df3b721eab98ca08386a1f01358f93839.zip
Optimization: Reduce many array allocations in GetCustomAtttributes()'s inherited path (#20779)
* Optimization: avoid 2 array allocations in inherited attribute misses This is a follow-up to many allocations recognized in #20448. A lot of methods ultimately call through CustomAttributes.GetCustomAttributes(). In the inherited search path (default for most searches above), the inheritance path of a class is traversed, resulting in an array allocation per crawled type, a copy to the overall List<object> and then after that - in current code - an array allocation from that list and a typed array allocation it's copied to. However, in the common miss case as simple as: typeof(T).GetCustomAttributes(typeof(TAttr), true); ...and many other overloads, all the same path underneath... We can avoid the last 2 arrays in the miss case. We have the List<object> to go off of. If that's a zero-entry list, we can return an Array.Empty<TAttr>(). That's effectively what this change does. While converting the entire attribute pipeline to generics is problematic and has issue since some object[] return abstracts aren't sealed, we can at least somewhat trivially cache an array per attribute type (only one static, ultimately from Array.Empty<T> underneath) and return that for the miss case. There are far more wins to be had here, but they require more changes. * Move RuntimeType empty array cache generation to Attribute.CreateAttributeArrayHelper This exposes Attribute.CreateAttributeArrayHelper to internal and uses it directly on the RuntimeType caching for empty arrays. Though this allocated 1 additional array overall, it's simpler, faster to init, and still is an infinite win over the per-call allocations before this overall changesets. * CustomAttributes: remove needless array copy in the inherited hit case This removes a .ToArray() for the sake of Array.Copy() where a simple for loop suffices and removes the allocation. Reversing the "empty" result checks is also just a bit cleaner here. This also expands the same fix to the MemberInfo path. Note: should DRY these up too (longstanding issue) - but let's do that in a separate commit for clarity. * GetCusomAttributes: use ListBuilder<object> for inheritance crawls This exposes RuntimeType.ListBuilder<T> for internal usage and replaces the List<T> allocation in GetCustomAttributes() paths to reduce allocations and increase performance in the inherited crawl paths (which is the default for many optional-parameter methods in layers above). Note: there is a subtle behavior depending on previous-null (not possible with a struct now) in AttributeUsageCheck() that I believe still behaves correctly, but could use another set of eyes and a full test suite run to confirm. object[] attributes was removed there simply because it wasn't used before - only cleaning up. * Attribute caching: use Array.CreateInstance() directly on RuntimeType This also reverts the CreateAttributeArrayHelper => internal change, since it's no longer needed. * Ref passing for RuntimeType.ListBuilder<object> & CustomAttribute simplification This fixes the struct passing duplication and tweaks how we're creating arrays a bit, centralizing the zero-element checks to cover all cases as well as simplify the per-method code to rely on the fact this is happening underneath.
Diffstat (limited to 'eng')
0 files changed, 0 insertions, 0 deletions