Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ private static ExtendedType FromMember(MemberInfo member)
};
}

public static ExtendedMethodInfo FromMethod(MethodInfo method, TypeCache cache)
public static ExtendedMethodInfo FromMethod(
MethodInfo method,
ParameterInfo[] parameters,
TypeCache cache)
{
var helper = new NullableHelper(method.DeclaringType!);
var context = helper.GetContext(method);
Expand All @@ -40,8 +43,8 @@ public static ExtendedMethodInfo FromMethod(MethodInfo method, TypeCache cache)
method,
cache));

var parameters = method.GetParameters();
var parameterTypes = ImmutableDictionary.CreateBuilder<ParameterInfo, IExtendedType>();
var parameterTypes = ImmutableDictionary.CreateBuilder<ParameterInfo, IExtendedType>(
ParameterInfoComparer.Instance);

foreach (var parameter in parameters)
{
Expand Down
8 changes: 6 additions & 2 deletions src/HotChocolate/Core/src/Types/Internal/ExtendedType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,16 @@ internal static ExtendedType FromMember(MemberInfo member, TypeCache cache)
return Members.FromMember(member, cache);
}

internal static ExtendedMethodInfo FromMethod(MethodInfo method, TypeCache cache)
internal static ExtendedMethodInfo FromMethod(
MethodInfo method,
ParameterInfo[] parameters,
TypeCache cache)
{
ArgumentNullException.ThrowIfNull(method);
ArgumentNullException.ThrowIfNull(parameters);
ArgumentNullException.ThrowIfNull(cache);

return Members.FromMethod(method, cache);
return Members.FromMethod(method, parameters, cache);
}

/// <summary>
Expand Down
29 changes: 29 additions & 0 deletions src/HotChocolate/Core/src/Types/Internal/ParameterInfoComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Reflection;

namespace HotChocolate.Internal;

internal sealed class ParameterInfoComparer : IEqualityComparer<ParameterInfo>
{
public bool Equals(ParameterInfo? x, ParameterInfo? y)
{
if (ReferenceEquals(x, y))
{
return true;
}

if (x is null || y is null)
{
return false;
}

return x.MetadataToken == y.MetadataToken
&& x.Member.Module.MetadataToken == y.Member.Module.MetadataToken;
}

public int GetHashCode(ParameterInfo obj)
{
return HashCode.Combine(obj.MetadataToken, obj.Member.Module.MetadataToken);
}

public static readonly ParameterInfoComparer Instance = new();
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ internal sealed class DefaultResolverCompiler : IResolverCompiler
private static readonly MethodInfo s_resolver =
typeof(IResolverContext).GetMethod(nameof(IResolverContext.Resolver))!;

private readonly ITypeInspector _typeInspector;
private readonly Dictionary<ParameterInfo, IParameterExpressionBuilder> _cache = [];
private readonly List<IParameterExpressionBuilder> _parameterExpressionBuilders;
private readonly List<IParameterExpressionBuilder> _defaultParameterExpressionBuilders;
Expand All @@ -40,9 +41,12 @@ internal sealed class DefaultResolverCompiler : IResolverCompiler
new Dictionary<ParameterInfo, string>();

public DefaultResolverCompiler(
ITypeInspector typeInspector,
IServiceProvider schemaServiceProvider,
IEnumerable<IParameterExpressionBuilder>? customParameterExpressionBuilders)
{
_typeInspector = typeInspector;

var appServiceProvider = schemaServiceProvider.GetService<IRootServiceProviderAccessor>()?.ServiceProvider;
var serviceInspector = appServiceProvider?.GetService<IServiceProviderIsService>();

Expand Down Expand Up @@ -251,9 +255,10 @@ public SubscribeResolverDelegate CompileSubscribe(
{
if (method.IsStatic)
{
var parameters = _typeInspector.GetParameters(method);
var parameterExpr = CreateParameters(
s_context,
method.GetParameters(),
parameters,
argumentNames,
parameterExpressionBuilders);
Expression subscribeResolver = Call(method, parameterExpr);
Expand All @@ -262,7 +267,7 @@ public SubscribeResolverDelegate CompileSubscribe(
}
else
{
var parameters = method.GetParameters();
var parameters = _typeInspector.GetParameters(method);
var owner = CreateResolverOwner(s_context, sourceType, resolverType);
var parameterExpr = CreateParameters(
s_context,
Expand Down Expand Up @@ -326,12 +331,13 @@ private FieldResolverDelegate CompileStaticResolver(
IReadOnlyDictionary<ParameterInfo, string> argumentNames,
IReadOnlyList<IParameterExpressionBuilder> fieldParameterExpressionBuilders)
{
var parameters = CreateParameters(
var parameters = _typeInspector.GetParameters(method);
var parameterExpr = CreateParameters(
s_context,
method.GetParameters(),
parameters,
argumentNames,
fieldParameterExpressionBuilders);
Expression resolver = Call(method, parameters);
Expression resolver = Call(method, parameterExpr);
resolver = EnsureResolveResult(resolver, method.ReturnType);
return Lambda<FieldResolverDelegate>(resolver, s_context).Compile();
}
Expand All @@ -353,7 +359,7 @@ private FieldResolverDelegate CreateResolver(

if (member is MethodInfo method)
{
var parameters = method.GetParameters();
var parameters = _typeInspector.GetParameters(method);
var owner = CreateResolverOwner(s_context, source, resolverType);
var parameterExpr = CreateParameters(
s_context,
Expand Down Expand Up @@ -391,7 +397,7 @@ private FieldResolverDelegate CreateResolver(

if (member is MethodInfo method)
{
var parameters = method.GetParameters();
var parameters = _typeInspector.GetParameters(method);

if (IsPureResolver(method, parameters, fieldParameterExpressionBuilders))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected override void OnConfigure(
if (MessageType is null)
{
var messageParameter =
method.GetParameters()
context.TypeInspector.GetParameters(method)
.FirstOrDefault(t => t.IsDefined(typeof(EventMessageAttribute)));

if (messageParameter is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ public class DefaultTypeInspector(bool ignoreRequiredAttribute = false) : Conven
private const string EqualsMethodName = "Equals";
private const string CloneMethodName = "<Clone>$";

#if NET9_0_OR_GREATER
private readonly Lock _parametersLock = new();
#else
private readonly object _parametersLock = new();
#endif
private readonly TypeCache _typeCache = new();
private readonly ConcurrentDictionary<MethodInfo, ExtendedMethodInfo> _methods = [];
private readonly ConcurrentDictionary<(Type, bool, bool), MemberInfo[]> _memberCache = new();
private readonly ConcurrentDictionary<(Type, bool, bool), MemberInfo[]> _membersCache = new();
private readonly ConcurrentDictionary<MethodInfo, ParameterInfo[]> _parametersCache = new();

/// <summary>
/// Infer type to be non-null if <see cref="RequiredAttribute"/> is found.
Expand All @@ -47,7 +53,7 @@ public ReadOnlySpan<MemberInfo> GetMembers(

var cacheKey = (type, includeIgnored, includeStatic);

if (_memberCache.TryGetValue(cacheKey, out var cached))
if (_membersCache.TryGetValue(cacheKey, out var cached))
{
return cached;
}
Expand All @@ -71,12 +77,35 @@ public ReadOnlySpan<MemberInfo> GetMembers(
var selectedMembers = new MemberInfo[next];
span.CopyTo(selectedMembers);
span.Clear();
_memberCache.TryAdd(cacheKey, selectedMembers);
_membersCache.TryAdd(cacheKey, selectedMembers);

ArrayPool<MemberInfo>.Shared.Return(temp);
return selectedMembers;
}

/// <inheritdoc />
public ParameterInfo[] GetParameters(MethodInfo method)
{
// ReSharper disable once InconsistentlySynchronizedField
if (_parametersCache.TryGetValue(method, out var parameters))
{
return parameters;
}

lock (_parametersLock)
{
if (_parametersCache.TryGetValue(method, out parameters))
{
return parameters;
}

parameters = method.GetParameters();
_parametersCache.TryAdd(method, parameters);

return parameters;
}
}

/// <inheritdoc />
public virtual bool IsMemberIgnored(MemberInfo member)
{
Expand Down Expand Up @@ -164,7 +193,11 @@ private IExtendedType GetArgumentTypeInternal(ParameterInfo parameter)

var info = _methods.GetOrAdd(
method,
static (m, c) => ExtendedType.FromMethod(m, c), _typeCache);
static (methodInfo, typeInspector) =>
{
var parameters = typeInspector.GetParameters(methodInfo);
return ExtendedType.FromMethod(methodInfo, parameters, typeInspector._typeCache);
}, this);

return info.ParameterTypes[parameter];
}
Expand Down Expand Up @@ -667,7 +700,8 @@ private bool CanBeHandled(
if (member is MethodInfo { IsGenericMethodDefinition: false } method
&& CanHandleReturnType(member, method.ReturnType, allowObjectType))
{
foreach (var parameter in method.GetParameters())
var parameters = GetParameters(method);
foreach (var parameter in parameters)
{
if (!CanHandleParameter(parameter, allowObjectType))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ public sealed partial class DescriptorContext : IDescriptorContext
private readonly Func<IReadOnlySchemaOptions> _options;
private FeatureReference<TypeSystemFeature> _typeSystemFeature = FeatureReference<TypeSystemFeature>.Default;
private TypeDiscoveryHandler[]? _typeDiscoveryHandlers;
private INamingConventions? _naming;
private ITypeInspector? _inspector;

private DescriptorContext(
Func<IReadOnlySchemaOptions> options,
Expand All @@ -42,13 +40,16 @@ private DescriptorContext(
_serviceHelper = new ServiceHelper(Services);
Features = features;
TypeInterceptor = typeInterceptor;
ResolverCompiler = new DefaultResolverCompiler(
schemaServices,
_serviceHelper.GetParameterExpressionBuilders());

TypeConverter = _serviceHelper.GetTypeConverter();
InputFormatter = _serviceHelper.GetInputFormatter(TypeConverter);
InputParser = _serviceHelper.GetInputParser(TypeConverter);

TypeInspector = this.GetConventionOrDefault<ITypeInspector>(new DefaultTypeInspector());
ResolverCompiler = new DefaultResolverCompiler(
TypeInspector,
schemaServices,
_serviceHelper.GetParameterExpressionBuilders());
}

internal SchemaBuilder.LazySchema Schema { get; }
Expand All @@ -60,11 +61,12 @@ private DescriptorContext(
public IReadOnlySchemaOptions Options => _options();

/// <inheritdoc />
[field: AllowNull, MaybeNull]
public INamingConventions Naming
{
get
{
_naming ??= GetConventionOrDefault<INamingConventions>(() => Options.UseXmlDocumentation
field ??= GetConventionOrDefault<INamingConventions>(() => Options.UseXmlDocumentation
? new DefaultNamingConventions(
new XmlDocumentationProvider(
new XmlDocumentationFileResolver(
Expand All @@ -73,21 +75,12 @@ public INamingConventions Naming
: new DefaultNamingConventions(
new NoopDocumentationProvider()));

return _naming;
return field;
}
}

/// <inheritdoc />
public ITypeInspector TypeInspector
{
get
{
_inspector ??= this.GetConventionOrDefault<ITypeInspector>(
new DefaultTypeInspector());

return _inspector;
}
}
public ITypeInspector TypeInspector { get; }

/// <inheritdoc />
public TypeInterceptor TypeInterceptor { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ ReadOnlySpan<MemberInfo> GetMembers(
bool includeStatic = false,
bool allowObject = false);

/// <summary>
/// Gets the parameters of <paramref name="method"/> in a thread-safe manner.
/// </summary>
/// <param name="method">
/// The method to get the parameters from.
/// </param>
/// <returns>
/// The parameters of the <paramref name="method"/>.
/// </returns>
ParameterInfo[] GetParameters(MethodInfo method);

/// <summary>
/// Defines if a member shall be ignored. This method interprets ignore attributes.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected internal InterfaceFieldDescriptor(

if (member is MethodInfo m)
{
_parameterInfos = m.GetParameters();
_parameterInfos = context.TypeInspector.GetParameters(m);
Parameters = _parameterInfos.ToDictionary(t => t.Name!, StringComparer.Ordinal);
}
}
Expand Down Expand Up @@ -241,7 +241,7 @@ private IInterfaceFieldDescriptor ResolveWithInternal(

if (propertyOrMethod is MethodInfo m)
{
_parameterInfos = m.GetParameters();
_parameterInfos = Context.TypeInspector.GetParameters(m);
Parameters = _parameterInfos.ToDictionary(t => t.Name!, StringComparer.Ordinal);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ protected ObjectFieldDescriptor(

if (member is MethodInfo m)
{
_parameterInfos = m.GetParameters();
_parameterInfos = context.TypeInspector.GetParameters(m);
Parameters = _parameterInfos.ToDictionary(t => t.Name!, StringComparer.Ordinal);
Configuration.ResultType = m.ReturnType;
}
Expand Down Expand Up @@ -172,7 +172,7 @@ private void CompleteArguments(ObjectFieldConfiguration definition)

if (subscribeMember is MethodInfo subscribeMethod)
{
var subscribeParameters = subscribeMethod.GetParameters();
var subscribeParameters = Context.TypeInspector.GetParameters(subscribeMethod);
var parameterLength = _parameterInfos.Length + subscribeParameters.Length;
var parameters = new ParameterInfo[parameterLength];

Expand Down Expand Up @@ -397,7 +397,7 @@ private IObjectFieldDescriptor ResolveWithInternal(

if (propertyOrMethod is MethodInfo m)
{
_parameterInfos = m.GetParameters();
_parameterInfos = Context.TypeInspector.GetParameters(m);
Parameters = _parameterInfos.ToDictionary(t => t.Name!, StringComparer.Ordinal);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,8 @@ private void TryBindArgumentRuntimeType(
{
if (member is MethodInfo method)
{
foreach (var parameter in _resolverCompiler.GetArgumentParameters(method.GetParameters()))
var parameters = _context.TypeInspector.GetParameters(method);
foreach (var parameter in _resolverCompiler.GetArgumentParameters(parameters))
{
_parameters[parameter.Name!] = parameter;
}
Expand Down
Loading
Loading