Skip to content

Commit ccbcd4a

Browse files
authored
Merge pull request #359 from servicetitan/upstream/methodInvoker
Apply .NET8 `MethodInvoker`/`ConstructorInvoker` optimization
2 parents 435a27d + 32ca0bf commit ccbcd4a

File tree

6 files changed

+98
-18
lines changed

6 files changed

+98
-18
lines changed

Extensions/Xtensive.Orm.BulkOperations/Internals/Operation.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ protected void EnsureTransactionIsStarted()
6767

6868
public QueryTranslationResult GetRequest(IQueryable<T> query) => QueryBuilder.TranslateQuery(query);
6969

70-
public QueryTranslationResult GetRequest(Type type, IQueryable query)
71-
{
72-
var translateQueryMethod = WellKnownMembers.TranslateQueryMethod.CachedMakeGenericMethod(type);
73-
return (QueryTranslationResult) translateQueryMethod.Invoke(QueryBuilder, new object[] {query});
74-
}
70+
public QueryTranslationResult GetRequest(Type type, IQueryable query) =>
71+
#if NET8_0_OR_GREATER
72+
(QueryTranslationResult) WellKnownMembers.TranslateQueryMethod.CachedMakeGenericMethodInvoker(type).Invoke(QueryBuilder, query);
73+
#else
74+
(QueryTranslationResult) WellKnownMembers.TranslateQueryMethod.CachedMakeGenericMethod(type).Invoke(QueryBuilder, new object[] {query});
75+
#endif
7576

7677
public TypeInfo GetTypeInfo(Type entityType) =>
7778
Session.Domain.Model.Hierarchies.SelectMany(a => a.Types).Single(a => a.UnderlyingType == entityType);

Orm/Xtensive.Orm/IoC/ServiceContainer.cs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,35 @@ public class ServiceContainer : ServiceContainerBase
2929
{
3030
private static readonly Type iServiceContainerType = typeof(IServiceContainer);
3131

32+
#if NET8_0_OR_GREATER
33+
private static readonly Func<ServiceRegistration, Pair<ConstructorInvoker, ParameterInfo[]>> ConstructorFactory = serviceInfo => {
34+
#else
3235
private static readonly Func<ServiceRegistration, Pair<ConstructorInfo, ParameterInfo[]>> ConstructorFactory = serviceInfo => {
36+
#endif
3337
var mappedType = serviceInfo.MappedType;
3438
var ctor = (
3539
from c in mappedType.GetConstructors()
3640
where c.GetAttribute<ServiceConstructorAttribute>(AttributeSearchOptions.InheritNone) != null
3741
select c
3842
).SingleOrDefault() ?? mappedType.GetConstructor(Array.Empty<Type>());
3943
var @params = ctor?.GetParameters();
40-
return new Pair<ConstructorInfo, ParameterInfo[]>(ctor, @params);
44+
#if NET8_0_OR_GREATER
45+
return new(ctor is null ? null : ConstructorInvoker.Create(ctor), @params);
46+
#else
47+
return new(ctor, @params);
48+
#endif
4149
};
4250

4351
private readonly IReadOnlyDictionary<Key, List<ServiceRegistration>> types;
4452

4553
private readonly ConcurrentDictionary<ServiceRegistration, Lazy<object>> instances =
4654
new ConcurrentDictionary<ServiceRegistration, Lazy<object>>();
4755

48-
private readonly ConcurrentDictionary<ServiceRegistration, Pair<ConstructorInfo, ParameterInfo[]>> constructorCache =
49-
new ConcurrentDictionary<ServiceRegistration, Pair<ConstructorInfo, ParameterInfo[]>>();
56+
#if NET8_0_OR_GREATER
57+
private readonly ConcurrentDictionary<ServiceRegistration, Pair<ConstructorInvoker, ParameterInfo[]>> constructorCache = new();
58+
#else
59+
private readonly ConcurrentDictionary<ServiceRegistration, Pair<ConstructorInfo, ParameterInfo[]>> constructorCache = new();
60+
#endif
5061

5162
private readonly ConcurrentDictionary<(Type, int), bool> creating = new ConcurrentDictionary<(Type, int), bool>();
5263

@@ -85,17 +96,18 @@ protected virtual object CreateInstance(ServiceRegistration serviceInfo)
8596
return null;
8697
}
8798
var pInfos = cachedInfo.Second;
88-
if (pInfos.Length == 0) {
99+
var nArg = pInfos.Length;
100+
if (nArg == 0) {
89101
return Activator.CreateInstance(serviceInfo.MappedType);
90102
}
91103
var managedThreadId = Environment.CurrentManagedThreadId;
92104
var key = (serviceInfo.Type, managedThreadId);
93105
if (!creating.TryAdd(key, true)) {
94106
throw new ActivationException(Strings.ExRecursiveConstructorParameterDependencyIsDetected);
95107
}
96-
var args = new object[pInfos.Length];
108+
var args = new object[nArg];
97109
try {
98-
for (var i = 0; i < pInfos.Length; i++) {
110+
for (var i = 0; i < nArg; i++) {
99111
var type = pInfos[i].ParameterType;
100112
if (creating.ContainsKey((type, managedThreadId))) {
101113
throw new ActivationException(Strings.ExRecursiveConstructorParameterDependencyIsDetected);
@@ -106,10 +118,14 @@ protected virtual object CreateInstance(ServiceRegistration serviceInfo)
106118
finally {
107119
_ = creating.TryRemove(key, out _);
108120
}
121+
#if NET8_0_OR_GREATER
122+
return cInfo.Invoke(args.AsSpan());
123+
#else
109124
return cInfo.Invoke(args);
125+
#endif
110126
}
111127

112-
#endregion
128+
#endregion
113129

114130
#region Private \ internal methods
115131

@@ -194,17 +210,28 @@ public static IServiceContainer Create(Type containerType, object configuration,
194210
Type configurationType = configuration?.GetType(),
195211
parentType = parent?.GetType();
196212
return (IServiceContainer) (
213+
#if NET8_0_OR_GREATER
214+
FindConstructorInvoker(containerType, configurationType, parentType)?.Invoke(configuration, parent)
215+
?? FindConstructorInvoker(containerType, configurationType)?.Invoke(configuration)
216+
?? FindConstructorInvoker(containerType, parentType)?.Invoke(parent)
217+
#else
197218
FindConstructor(containerType, configurationType, parentType)?.Invoke(new[] { configuration, parent })
198219
?? FindConstructor(containerType, configurationType)?.Invoke(new[] { configuration })
199220
?? FindConstructor(containerType, parentType)?.Invoke(new[] { parent })
221+
#endif
200222
?? throw new ArgumentException(Strings.ExContainerTypeDoesNotProvideASuitableConstructor, "containerType")
201223
);
202224
}
203225

226+
#if NET8_0_OR_GREATER
227+
private static ConstructorInvoker FindConstructorInvoker(Type containerType, params Type[] argumentTypes) =>
228+
containerType.GetSingleConstructorInvokerOrDefault(argumentTypes);
229+
#else
204230
private static ConstructorInfo FindConstructor(Type containerType, params Type[] argumentTypes) =>
205231
containerType.GetSingleConstructorOrDefault(argumentTypes);
232+
#endif
206233

207-
#endregion
234+
#endregion
208235

209236
/// <summary>
210237
/// Creates <see cref="IServiceContainer"/> by default configuration.
@@ -324,4 +351,4 @@ public override void Dispose()
324351
}
325352
}
326353
}
327-
}
354+
}

Orm/Xtensive.Orm/Modelling/PropertyAccessor.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,11 @@ private void Initialize()
174174
dependencyRootType = pa.DependencyRootType;
175175
compareCaseInsensitive = tProperty == WellKnownTypes.String && pa.CaseInsensitiveComparison;
176176
}
177-
InnerInitializeMethodDefinition
178-
.CachedMakeGenericMethod(tType, tProperty)
179-
.Invoke(this, null);
177+
#if NET8_0_OR_GREATER
178+
InnerInitializeMethodDefinition.CachedMakeGenericMethodInvoker(tType, tProperty).Invoke(this);
179+
#else
180+
InnerInitializeMethodDefinition.CachedMakeGenericMethod(tType, tProperty).Invoke(this, null);
181+
#endif
180182
}
181183

182184
private void InnerInitialize<TType, TProperty>()

Orm/Xtensive.Orm/Orm/Linq/QueryProvider.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,21 @@ public IQueryable<TElement> CreateQuery<TElement>(Expression expression) =>
5353
object IQueryProvider.Execute(Expression expression)
5454
{
5555
var resultType = expression.Type;
56+
#if NET8_0_OR_GREATER
57+
var executeMethod = resultType.IsOfGenericInterface(WellKnownInterfaces.EnumerableOfT)
58+
? WellKnownMembers.QueryProvider.ExecuteSequence.CachedMakeGenericMethodInvoker(SequenceHelper.GetElementType(resultType))
59+
: WellKnownMembers.QueryProvider.ExecuteScalar.CachedMakeGenericMethodInvoker(resultType);
60+
try {
61+
return executeMethod.Invoke(this, expression);
62+
}
63+
#else
5664
var executeMethod = resultType.IsOfGenericInterface(WellKnownInterfaces.EnumerableOfT)
5765
? WellKnownMembers.QueryProvider.ExecuteSequence.CachedMakeGenericMethod(SequenceHelper.GetElementType(resultType))
5866
: WellKnownMembers.QueryProvider.ExecuteScalar.CachedMakeGenericMethod(resultType);
5967
try {
60-
return executeMethod.Invoke(this, new object[] {expression});
68+
return executeMethod.Invoke(this, new object[] { expression });
6169
}
70+
#endif
6271
catch (TargetInvocationException e) {
6372
if (e.InnerException != null) {
6473
ExceptionDispatchInfo.Throw(e.InnerException);

Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,11 @@ private static IReadOnlyCollection<IDbConnectionAccessor> CreateConnectionAccess
190190
throw new NotSupportedException(string.Format(Strings.ExConnectionAccessorXHasNoParameterlessConstructor, type));
191191
}
192192

193+
#if NET8_0_OR_GREATER
194+
var accessorFactory = (Func<IDbConnectionAccessor>) FactoryCreatorMethod.CachedMakeGenericMethodInvoker(type).Invoke(null);
195+
#else
193196
var accessorFactory = (Func<IDbConnectionAccessor>) FactoryCreatorMethod.CachedMakeGenericMethod(type).Invoke(null, null);
197+
#endif
194198
instances.Add(accessorFactory());
195199
factoriesLocal[type] = accessorFactory;
196200
}

Orm/Xtensive.Orm/Reflection/TypeHelper.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ public int GetHashCode((Type, Type[]) obj)
5353
private static readonly Type CompilerGeneratedAttributeType = typeof(CompilerGeneratedAttribute);
5454
private static readonly string TypeHelperNamespace = typeof(TypeHelper).Namespace;
5555

56+
#if NET8_0_OR_GREATER
57+
private static readonly ConcurrentDictionary<(Type, Type[]), ConstructorInvoker> ConstructorInvokerByTypes =
58+
#else
5659
private static readonly ConcurrentDictionary<(Type, Type[]), ConstructorInfo> ConstructorInfoByTypes =
60+
#endif
5761
new(new TypesEqualityComparer());
5862

5963
private static readonly ConcurrentDictionary<Type, Type[]> OrderedInterfaces = new();
@@ -68,6 +72,17 @@ public int GetHashCode((Type, Type[]) obj)
6872

6973
private static readonly ConcurrentDictionary<(MethodInfo, Type, Type), MethodInfo> GenericMethodInstances2 = new();
7074

75+
#if NET8_0_OR_GREATER
76+
private static readonly ConcurrentDictionary<(MethodInfo, Type), MethodInvoker> GenericMethodInvokers1 = new();
77+
private static readonly ConcurrentDictionary<(MethodInfo, Type, Type), MethodInvoker> GenericMethodInvokers2 = new();
78+
79+
private static readonly Func<(MethodInfo genericDefinition, Type typeArgument), MethodInvoker> GenericMethodInvokerFactory1 =
80+
key => MethodInvoker.Create(key.genericDefinition.MakeGenericMethod(key.typeArgument));
81+
82+
private static readonly Func<(MethodInfo genericDefinition, Type typeArgument1, Type typeArgument2), MethodInvoker> GenericMethodInvokerFactory2 =
83+
key => MethodInvoker.Create(key.genericDefinition.MakeGenericMethod(key.typeArgument1, key.typeArgument2));
84+
#endif
85+
7186
private static readonly ConcurrentDictionary<(Type, Type), Type> GenericTypeInstances1 = new();
7287

7388
private static readonly ConcurrentDictionary<(Type, Type, Type), Type> GenericTypeInstances2 = new();
@@ -644,9 +659,17 @@ public static object Activate(this Type type, Type[] genericArguments, params ob
644659
/// The <paramref name="type"/> has no constructors suitable for <paramref name="argumentTypes"/>
645660
/// -or- more than one such constructor.
646661
/// </exception>
662+
#if NET8_0_OR_GREATER
663+
public static ConstructorInvoker GetSingleConstructorInvoker(this Type type, Type[] argumentTypes) =>
664+
ConstructorInvokerByTypes.GetOrAdd((type, argumentTypes),
665+
static t => ConstructorExtractor(t) is ConstructorInfo ctor
666+
? ConstructorInvoker.Create(ctor)
667+
: throw new InvalidOperationException(Strings.ExGivenTypeHasNoOrMoreThanOneCtorWithGivenParameters));
668+
#else
647669
public static ConstructorInfo GetSingleConstructor(this Type type, Type[] argumentTypes) =>
648670
ConstructorInfoByTypes.GetOrAdd((type, argumentTypes), ConstructorExtractor)
649671
?? throw new InvalidOperationException(Strings.ExGivenTypeHasNoOrMoreThanOneCtorWithGivenParameters);
672+
#endif
650673

651674
/// <summary>
652675
/// Gets the public constructor of type <paramref name="type"/>
@@ -659,8 +682,14 @@ public static ConstructorInfo GetSingleConstructor(this Type type, Type[] argume
659682
/// otherwise, <see langword="null"/>.
660683
/// </returns>
661684
[CanBeNull]
685+
#if NET8_0_OR_GREATER
686+
public static ConstructorInvoker GetSingleConstructorInvokerOrDefault(this Type type, Type[] argumentTypes) =>
687+
ConstructorInvokerByTypes.GetOrAdd((type, argumentTypes),
688+
static t => ConstructorExtractor(t) is ConstructorInfo ctor ? ConstructorInvoker.Create(ctor) : null);
689+
#else
662690
public static ConstructorInfo GetSingleConstructorOrDefault(this Type type, Type[] argumentTypes) =>
663691
ConstructorInfoByTypes.GetOrAdd((type, argumentTypes), ConstructorExtractor);
692+
#endif
664693

665694
private static readonly Func<(Type, Type[]), ConstructorInfo> ConstructorExtractor = t => {
666695
(var type, var argumentTypes) = t;
@@ -920,6 +949,14 @@ public static MethodInfo CachedMakeGenericMethod(this MethodInfo genericDefiniti
920949
public static MethodInfo CachedMakeGenericMethod(this MethodInfo genericDefinition, Type typeArgument1, Type typeArgument2) =>
921950
GenericMethodInstances2.GetOrAdd((genericDefinition, typeArgument1, typeArgument2), GenericMethodFactory2);
922951

952+
#if NET8_0_OR_GREATER
953+
public static MethodInvoker CachedMakeGenericMethodInvoker(this MethodInfo genericDefinition, Type typeArgument) =>
954+
GenericMethodInvokers1.GetOrAdd((genericDefinition, typeArgument), GenericMethodInvokerFactory1);
955+
956+
public static MethodInvoker CachedMakeGenericMethodInvoker(this MethodInfo genericDefinition, Type typeArgument1, Type typeArgument2) =>
957+
GenericMethodInvokers2.GetOrAdd((genericDefinition, typeArgument1, typeArgument2), GenericMethodInvokerFactory2);
958+
#endif
959+
923960
public static Type CachedMakeGenericType(this Type genericDefinition, Type typeArgument) =>
924961
GenericTypeInstances1.GetOrAdd((genericDefinition, typeArgument), GenericTypeFactory1);
925962

0 commit comments

Comments
 (0)