Skip to content

Commit 4aa0f6e

Browse files
authored
Merge pull request #56 from servicetitan/no-getgenericmethoddefinition-clalls
No GetGenericMethodDefinition method calls
2 parents f779b50 + 438200c commit 4aa0f6e

File tree

7 files changed

+161
-230
lines changed

7 files changed

+161
-230
lines changed

Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerCollection.cs

Lines changed: 0 additions & 53 deletions
This file was deleted.

Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerProvider.cs

Lines changed: 61 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,42 @@ namespace Xtensive.Orm.Linq.MemberCompilation
1717
{
1818
internal partial class MemberCompilerProvider<T> : LockableBase, IMemberCompilerProvider<T>
1919
{
20-
private MemberCompilerCollection compilers = new MemberCompilerCollection();
20+
private readonly struct CompilerKey : IEquatable<CompilerKey>
21+
{
22+
private readonly Module module;
23+
private readonly int metadataToken;
24+
25+
public bool Equals(CompilerKey other) => metadataToken == other.metadataToken
26+
&& (ReferenceEquals(module, other.module) || module == other.module);
27+
28+
public override bool Equals(object obj) => obj is CompilerKey other && Equals(other);
29+
30+
public override int GetHashCode()
31+
{
32+
unchecked {
33+
return module == null ? metadataToken : (module.GetHashCode() * 397) ^ metadataToken;
34+
}
35+
}
2136

22-
public Type ExpressionType { get { return typeof(T); } }
37+
public CompilerKey(MemberInfo memberInfo)
38+
{
39+
module = memberInfo.Module;
40+
metadataToken = memberInfo.MetadataToken;
41+
}
42+
}
43+
44+
private readonly Dictionary<CompilerKey, Delegate> compilers
45+
= new Dictionary<CompilerKey, Delegate>();
46+
47+
public Type ExpressionType => typeof(T);
2348

2449
public Delegate GetUntypedCompiler(MemberInfo target)
2550
{
26-
ArgumentValidator.EnsureArgumentNotNull(target, "target");
27-
28-
var actualTarget = GetCanonicalMember(target);
29-
if (actualTarget == null)
30-
return null;
31-
var registration = compilers.Get(actualTarget);
32-
if (registration == null)
33-
return null;
34-
return registration.CompilerInvoker;
51+
ArgumentValidator.EnsureArgumentNotNull(target, nameof(target));
52+
53+
return compilers.TryGetValue(GetCompilerKey(target), out var compiler)
54+
? compiler
55+
: null;
3556
}
3657

3758
public Func<T, T[], T> GetCompiler(MemberInfo target)
@@ -54,16 +75,11 @@ public void RegisterCompilers(Type compilerContainer, ConflictHandlingMethod con
5475
throw new InvalidOperationException(string.Format(
5576
Strings.ExTypeXShouldNotBeGeneric, compilerContainer.GetFullName(true)));
5677

57-
var compilersToRegister = new MemberCompilerCollection();
58-
5978
var compilerMethods = compilerContainer
6079
.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
6180
.Where(method => method.IsDefined(typeof (CompilerAttribute), false) && !method.IsGenericMethod);
6281

63-
foreach (var compiler in compilerMethods)
64-
compilersToRegister.Add(ProcessCompiler(compiler));
65-
66-
UpdateRegistry(compilersToRegister, conflictHandlingMethod);
82+
UpdateRegistry(compilerMethods.Select(ProcessCompiler), conflictHandlingMethod);
6783
}
6884

6985
public void RegisterCompilers(IEnumerable<KeyValuePair<MemberInfo, Func<MemberInfo, T, T[], T>>> compilerDefinitions)
@@ -76,71 +92,38 @@ public void RegisterCompilers(IEnumerable<KeyValuePair<MemberInfo, Func<MemberIn
7692
ArgumentValidator.EnsureArgumentNotNull(compilerDefinitions, "compilerDefinitions");
7793
this.EnsureNotLocked();
7894

79-
var newItems = new MemberCompilerCollection();
80-
foreach (var item in compilerDefinitions)
81-
newItems.Add(new MemberCompilerRegistration(GetCanonicalMember(item.Key), item.Value));
95+
var newItems = compilerDefinitions.Select(item => (item.Key, (Delegate) item.Value));
8296
UpdateRegistry(newItems, conflictHandlingMethod);
8397
}
8498

8599
#region Private methods
86100

87-
private void UpdateRegistry(MemberCompilerCollection newItems, ConflictHandlingMethod conflictHandlingMethod)
101+
private void UpdateRegistry(
102+
IEnumerable<(MemberInfo targetMember, Delegate compiler)> newRegistrations, ConflictHandlingMethod conflictHandlingMethod)
88103
{
89-
if (newItems.Count==0)
90-
return;
91-
switch (conflictHandlingMethod) {
92-
case ConflictHandlingMethod.KeepOld:
93-
newItems.MergeWith(compilers, false);
94-
compilers = newItems;
95-
break;
96-
case ConflictHandlingMethod.Overwrite:
97-
compilers.MergeWith(newItems, false);
98-
break;
99-
case ConflictHandlingMethod.ReportError:
100-
compilers.MergeWith(newItems, true);
101-
break;
104+
foreach (var (targetMember, compiler) in newRegistrations) {
105+
var key = GetCompilerKey(targetMember);
106+
if (conflictHandlingMethod != ConflictHandlingMethod.Overwrite && compilers.ContainsKey(key)) {
107+
if (conflictHandlingMethod == ConflictHandlingMethod.ReportError) {
108+
throw new InvalidOperationException(string.Format(
109+
Strings.ExCompilerForXIsAlreadyRegistered, targetMember.GetFullName(true)));
110+
}
111+
continue;
112+
}
113+
compilers[key] = compiler;
102114
}
103115
}
104116

105-
private static bool ParameterTypeMatches(Type inputParameterType, Type candidateParameterType)
106-
{
107-
return inputParameterType.IsGenericParameter
108-
? candidateParameterType==inputParameterType
109-
: (candidateParameterType.IsGenericParameter || inputParameterType==candidateParameterType);
110-
}
111-
112-
private static bool AllParameterTypesMatch(
113-
IEnumerable<Type> inputParameterTypes, IEnumerable<Type> candidateParameterTypes)
114-
{
115-
return inputParameterTypes
116-
.Zip(candidateParameterTypes)
117-
.All(pair => ParameterTypeMatches(pair.First, pair.Second));
118-
}
119-
120117
private static MethodBase GetCanonicalMethod(MethodBase inputMethod, MethodBase[] possibleCanonicalMethods)
121118
{
122-
var inputParameterTypes = inputMethod.GetParameterTypes();
123-
124-
var candidates = possibleCanonicalMethods
125-
.Where(candidate => candidate.Name==inputMethod.Name
126-
&& candidate.GetParameters().Length==inputParameterTypes.Length
127-
&& candidate.IsStatic==inputMethod.IsStatic)
128-
.ToArray();
129-
130-
if (candidates.Length==0)
131-
return null;
132-
if (candidates.Length==1)
133-
return candidates[0];
134-
135-
candidates = candidates
136-
.Where(candidate =>
137-
AllParameterTypesMatch(inputParameterTypes, candidate.GetParameterTypes()))
138-
.ToArray();
139-
140-
if (candidates.Length!=1)
141-
return null;
119+
foreach (var candidate in possibleCanonicalMethods) {
120+
if (inputMethod.MetadataToken == candidate.MetadataToken
121+
&& (ReferenceEquals(inputMethod.Module, candidate.Module) || inputMethod.Module == candidate.Module)) {
122+
return candidate;
123+
}
124+
}
142125

143-
return candidates[0];
126+
return null;
144127
}
145128

146129
private static Type[] ValidateCompilerParametersAndExtractTargetSignature(MethodInfo compiler, bool requireMemberInfo)
@@ -176,7 +159,7 @@ private static Type[] ValidateCompilerParametersAndExtractTargetSignature(Method
176159
return result;
177160
}
178161

179-
private static MemberCompilerRegistration ProcessCompiler(MethodInfo compiler)
162+
private static (MemberInfo targetMember, Delegate compilerInvoker) ProcessCompiler(MethodInfo compiler)
180163
{
181164
var attribute = compiler.GetAttribute<CompilerAttribute>(AttributeSearchOptions.InheritNone);
182165

@@ -271,7 +254,7 @@ private static MemberCompilerRegistration ProcessCompiler(MethodInfo compiler)
271254
compiler.GetFullName(true)));
272255

273256
var invoker = WrapInvoker(CreateInvoker(compiler, isStatic || isCtor, isGeneric));
274-
return new MemberCompilerRegistration(targetMember, invoker);
257+
return (targetMember, invoker);
275258
}
276259

277260
private static Func<MemberInfo, T, T[], T> WrapInvoker(Func<MemberInfo, T, T[], T> invoker)
@@ -318,21 +301,18 @@ private static void ValidateCompilerParameter(ParameterInfo parameter, Type requ
318301
compiler.GetFullName(true), parameter.Name, requiredType.GetFullName(true)));
319302
}
320303

321-
private static MemberInfo GetCanonicalMember(MemberInfo member)
304+
private static CompilerKey GetCompilerKey(MemberInfo member)
322305
{
323306
var canonicalMember = member;
324307
var sourceProperty = canonicalMember as PropertyInfo;
325308
if (sourceProperty!=null) {
326309
canonicalMember = sourceProperty.GetGetMethod();
327310
// GetGetMethod returns null in case of non public getter.
328-
if (canonicalMember==null)
329-
return null;
311+
if (canonicalMember==null) {
312+
return default;
313+
}
330314
}
331315

332-
var sourceMethod = canonicalMember as MethodInfo;
333-
if (sourceMethod!=null && sourceMethod.IsGenericMethod)
334-
canonicalMember = sourceMethod.GetGenericMethodDefinition();
335-
336316
var targetType = canonicalMember.ReflectedType;
337317
if (targetType.IsGenericType) {
338318
targetType = targetType.GetGenericTypeDefinition();
@@ -348,7 +328,7 @@ private static MemberInfo GetCanonicalMember(MemberInfo member)
348328
}
349329

350330
if (canonicalMember == null) {
351-
return null;
331+
return default;
352332
}
353333

354334
if (targetType.IsEnum) {
@@ -359,7 +339,7 @@ private static MemberInfo GetCanonicalMember(MemberInfo member)
359339
canonicalMember = GetCanonicalMethod((MethodInfo) canonicalMember, targetType.GetMethods());
360340
}
361341

362-
return canonicalMember;
342+
return new CompilerKey(canonicalMember);
363343
}
364344

365345
#endregion

Orm/Xtensive.Orm/Orm/Linq/MemberCompilation/MemberCompilerRegistration.cs

Lines changed: 0 additions & 27 deletions
This file was deleted.

Orm/Xtensive.Orm/Orm/Linq/Model/QueryParser.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,37 @@
77
using System;
88
using System.Linq.Expressions;
99
using Xtensive.Core;
10+
using Xtensive.Reflection;
1011

1112
namespace Xtensive.Orm.Linq.Model
1213
{
1314
internal static class QueryParser
1415
{
1516
public static GroupByQuery ParseGroupBy(MethodCallExpression mc)
1617
{
17-
var method = mc.Method.GetGenericMethodDefinition();
18+
var method = mc.Method;
1819

19-
if (method==QueryableMethodInfo.GroupBy)
20+
if (method.IsGenericMethodSpecificationOf(QueryableMethodInfo.GroupBy))
2021
return new GroupByQuery {
2122
Source = mc.Arguments[0],
2223
KeySelector = mc.Arguments[1].StripQuotes(),
2324
};
2425

25-
if (method==QueryableMethodInfo.GroupByWithElementSelector)
26+
if (method.IsGenericMethodSpecificationOf(QueryableMethodInfo.GroupByWithElementSelector))
2627
return new GroupByQuery {
2728
Source = mc.Arguments[0],
2829
KeySelector = mc.Arguments[1].StripQuotes(),
2930
ElementSelector = mc.Arguments[2].StripQuotes(),
3031
};
3132

32-
if (method==QueryableMethodInfo.GroupByWithResultSelector)
33+
if (method.IsGenericMethodSpecificationOf(QueryableMethodInfo.GroupByWithResultSelector))
3334
return new GroupByQuery {
3435
Source = mc.Arguments[0],
3536
KeySelector = mc.Arguments[1].StripQuotes(),
3637
ResultSelector = mc.Arguments[2].StripQuotes(),
3738
};
3839

39-
if (method==QueryableMethodInfo.GroupByWithElementAndResultSelectors)
40+
if (method.IsGenericMethodSpecificationOf(QueryableMethodInfo.GroupByWithElementAndResultSelectors))
4041
return new GroupByQuery {
4142
Source = mc.Arguments[0],
4243
KeySelector = mc.Arguments[1].StripQuotes(),

0 commit comments

Comments
 (0)