Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove indirection in DependencyInjection #52140

Merged
merged 8 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from 5 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 @@ -67,15 +67,6 @@ public void ServiceRealizationFailed(string? exceptionMessage)
WriteEvent(6, exceptionMessage);
}

[NonEvent]
public void ScopeDisposed(ServiceProviderEngine engine, ScopeState state)
{
if (IsEnabled(EventLevel.Verbose, EventKeywords.All))
{
ScopeDisposed(engine.GetHashCode(), state.ResolvedServicesCount, state.DisposableServicesCount);
}
}

[NonEvent]
public void ServiceResolved(Type serviceType)
{
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,7 @@ public static ServiceProvider BuildServiceProvider(this IServiceCollection servi
throw new ArgumentNullException(nameof(options));
}

IServiceProviderEngine engine;

#if !NETSTANDARD2_1
engine = new DynamicServiceProviderEngine(services);
#else
if (RuntimeFeature.IsDynamicCodeCompiled)
{
engine = new DynamicServiceProviderEngine(services);
}
else
{
// Don't try to compile Expressions/IL if they are going to get interpreted
engine = new RuntimeServiceProviderEngine(services);
}
#endif

return new ServiceProvider(services, engine, options);
return new ServiceProvider(services, options);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>
{
public static CallSiteRuntimeResolver Instance { get; } = new();

private CallSiteRuntimeResolver()
{
}

public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
return VisitCallSite(callSite, new RuntimeResolverContext
Expand Down Expand Up @@ -66,7 +72,7 @@ protected override object VisitRootCache(ServiceCallSite callSite, RuntimeResolv
}

var lockType = RuntimeResolverLock.Root;
ServiceProviderEngineScope serviceProviderEngine = context.Scope.Engine.Root;
ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;

lock (callSite)
{
Expand All @@ -91,7 +97,7 @@ protected override object VisitScopeCache(ServiceCallSite callSite, RuntimeResol
{
// Check if we are in the situation where scoped service was promoted to singleton
// and we need to lock the root
return context.Scope == context.Scope.Engine.Root ?
return context.Scope == context.Scope.RootProvider.Root ?
VisitRootCache(callSite, context) :
VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);
}
Expand Down Expand Up @@ -149,7 +155,7 @@ protected override object VisitServiceProvider(ServiceProviderCallSite servicePr

protected override object VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, RuntimeResolverContext context)
{
return context.Scope.Engine;
return serviceScopeFactoryCallSite.Value;
}

protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
Expand All @@ -14,21 +13,11 @@ internal abstract class CompiledServiceProviderEngine : ServiceProviderEngine
public ExpressionResolverBuilder ResolverBuilder { get; }
#endif

public CompiledServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors)
: base(serviceDescriptors)
public CompiledServiceProviderEngine(ServiceProvider provider)
{
#if IL_EMIT
ResolverBuilder = new ILEmitResolverBuilder(RuntimeResolver, this, Root);
#else
ResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
#endif
ResolverBuilder = new(provider);
}

protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
Func<ServiceProviderEngineScope, object> realizedService = ResolverBuilder.Build(callSite);
RealizedServices[callSite.ServiceType] = realizedService;
return realizedService;
}
public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite) => ResolverBuilder.Build(callSite);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,27 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Threading;

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal sealed class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
public DynamicServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors)
: base(serviceDescriptors)
private readonly ServiceProvider _serviceProvider;

public DynamicServiceProviderEngine(ServiceProvider serviceProvider): base(serviceProvider)
{
_serviceProvider = serviceProvider;
}

protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
int callCount = 0;
return scope =>
{
// Resolve the result before we increment the call count, this ensures that singletons
// won't cause any side effects during the compilation of the resolve function.
var result = RuntimeResolver.Resolve(callSite, scope);
var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);

if (Interlocked.Increment(ref callCount) == 2)
{
Expand All @@ -31,7 +32,7 @@ protected override Func<ServiceProviderEngineScope, object> RealizeService(Servi
{
try
{
base.RealizeService(callSite);
_serviceProvider.ReplaceServiceAccessor(callSite, base.RealizeService(callSite));
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,39 +44,21 @@ internal sealed class ExpressionResolverBuilder : CallSiteVisitor<object, Expres
Expression.Call(ScopeParameter, CaptureDisposableMethodInfo, CaptureDisposableParameter),
CaptureDisposableParameter);

private readonly CallSiteRuntimeResolver _runtimeResolver;

private readonly IServiceScopeFactory _serviceScopeFactory;

private readonly ServiceProviderEngineScope _rootScope;

private readonly ConcurrentDictionary<ServiceCacheKey, Func<ServiceProviderEngineScope, object>> _scopeResolverCache;

private readonly Func<ServiceCacheKey, ServiceCallSite, Func<ServiceProviderEngineScope, object>> _buildTypeDelegate;

public ExpressionResolverBuilder(CallSiteRuntimeResolver runtimeResolver, IServiceScopeFactory serviceScopeFactory, ServiceProviderEngineScope rootScope)
public ExpressionResolverBuilder(ServiceProvider serviceProvider)
{
if (runtimeResolver == null)
{
throw new ArgumentNullException(nameof(runtimeResolver));
}

_rootScope = serviceProvider.Root;
_scopeResolverCache = new ConcurrentDictionary<ServiceCacheKey, Func<ServiceProviderEngineScope, object>>();
_runtimeResolver = runtimeResolver;
_serviceScopeFactory = serviceScopeFactory;
_rootScope = rootScope;
_buildTypeDelegate = (key, cs) => BuildNoCache(cs);
}

public Func<ServiceProviderEngineScope, object> Build(ServiceCallSite callSite)
{
// Optimize singleton case
if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
davidfowl marked this conversation as resolved.
Show resolved Hide resolved
{
object value = _runtimeResolver.Resolve(callSite, _rootScope);
return scope => value;
}

// Only scope methods are cached
if (callSite.Cache.Location == CallSiteResultCacheLocation.Scope)
{
Expand Down Expand Up @@ -117,7 +99,7 @@ private Expression<Func<ServiceProviderEngineScope, object>> BuildExpression(Ser

protected override Expression VisitRootCache(ServiceCallSite singletonCallSite, object context)
{
return Expression.Constant(_runtimeResolver.Resolve(singletonCallSite, _rootScope));
return Expression.Constant(CallSiteRuntimeResolver.Instance.Resolve(singletonCallSite, _rootScope));
}

protected override Expression VisitConstant(ConstantCallSite constantCallSite, object context)
Expand All @@ -132,7 +114,7 @@ protected override Expression VisitServiceProvider(ServiceProviderCallSite servi

protected override Expression VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, object context)
{
return Expression.Constant(_serviceScopeFactory);
return Expression.Constant(serviceScopeFactoryCallSite.Value);
}

protected override Expression VisitFactory(FactoryCallSite factoryCallSite, object context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal sealed class ExpressionsServiceProviderEngine : ServiceProviderEngine
{
private readonly ExpressionResolverBuilder _expressionResolverBuilder;
public ExpressionsServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors) : base(serviceDescriptors)

public ExpressionsServiceProviderEngine(ServiceProvider serviceProvider)
{
_expressionResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
_expressionResolverBuilder = new ExpressionResolverBuilder(serviceProvider);
}

protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
Func<ServiceProviderEngineScope, object> realizedService = _expressionResolverBuilder.Build(callSite);
RealizedServices[callSite.ServiceType] = realizedService;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These calls were redundant.

return realizedService;
return _expressionResolverBuilder.Build(callSite);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ internal sealed class ILEmitResolverBuilder : CallSiteVisitor<ILEmitResolverBuil

private sealed class ILEmitResolverBuilderRuntimeContext
{
public IServiceScopeFactory ScopeFactory;
public object[] Constants;
public Func<IServiceProvider, object>[] Factories;
}
Expand All @@ -38,39 +37,21 @@ private struct GeneratedMethod
public DynamicMethod DynamicMethod;
}

private readonly CallSiteRuntimeResolver _runtimeResolver;

private readonly IServiceScopeFactory _serviceScopeFactory;

private readonly ServiceProviderEngineScope _rootScope;

private readonly ConcurrentDictionary<ServiceCacheKey, GeneratedMethod> _scopeResolverCache;

private readonly Func<ServiceCacheKey, ServiceCallSite, GeneratedMethod> _buildTypeDelegate;

public ILEmitResolverBuilder(CallSiteRuntimeResolver runtimeResolver, IServiceScopeFactory serviceScopeFactory, ServiceProviderEngineScope rootScope) :
base()
public ILEmitResolverBuilder(ServiceProvider serviceProvider)
{
if (runtimeResolver == null)
{
throw new ArgumentNullException(nameof(runtimeResolver));
}
_runtimeResolver = runtimeResolver;
_serviceScopeFactory = serviceScopeFactory;
_rootScope = rootScope;
_rootScope = serviceProvider.Root;
_scopeResolverCache = new ConcurrentDictionary<ServiceCacheKey, GeneratedMethod>();
_buildTypeDelegate = (key, cs) => BuildTypeNoCache(cs);
}

public Func<ServiceProviderEngineScope, object> Build(ServiceCallSite callSite)
{
// Optimize singleton case
if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
{
object value = _runtimeResolver.Resolve(callSite, _rootScope);
return scope => value;
}

maryamariyan marked this conversation as resolved.
Show resolved Hide resolved
return BuildType(callSite).Lambda;
}

Expand Down Expand Up @@ -164,7 +145,7 @@ protected override object VisitConstructor(ConstructorCallSite constructorCallSi

protected override object VisitRootCache(ServiceCallSite callSite, ILEmitResolverBuilderContext argument)
{
AddConstant(argument, _runtimeResolver.Resolve(callSite, _rootScope));
AddConstant(argument, CallSiteRuntimeResolver.Instance.Resolve(callSite, _rootScope));
return null;
}

Expand Down Expand Up @@ -203,9 +184,7 @@ protected override object VisitServiceProvider(ServiceProviderCallSite servicePr

protected override object VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, ILEmitResolverBuilderContext argument)
{
// this.ScopeFactory
argument.Generator.Emit(OpCodes.Ldarg_0);
argument.Generator.Emit(OpCodes.Ldfld, typeof(ILEmitResolverBuilderRuntimeContext).GetField(nameof(ILEmitResolverBuilderRuntimeContext.ScopeFactory)));
AddConstant(argument, serviceScopeFactoryCallSite.Value);
return null;
}

Expand Down Expand Up @@ -424,8 +403,7 @@ private ILEmitResolverBuilderRuntimeContext GenerateMethodBody(ServiceCallSite c
return new ILEmitResolverBuilderRuntimeContext
{
Constants = context.Constants?.ToArray(),
Factories = context.Factories?.ToArray(),
ScopeFactory = _serviceScopeFactory
Factories = context.Factories?.ToArray()
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal sealed class ILEmitServiceProviderEngine : ServiceProviderEngine
{
private readonly ILEmitResolverBuilder _expressionResolverBuilder;
public ILEmitServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors) : base(serviceDescriptors)
public ILEmitServiceProviderEngine(ServiceProvider serviceProvider)
{
_expressionResolverBuilder = new ILEmitResolverBuilder(RuntimeResolver, this, Root);
_expressionResolverBuilder = new ILEmitResolverBuilder(serviceProvider);
}

protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
Func<ServiceProviderEngineScope, object> realizedService = _expressionResolverBuilder.Build(callSite);
RealizedServices[callSite.ServiceType] = realizedService;
return realizedService;
return _expressionResolverBuilder.Build(callSite);
}
}
}

This file was deleted.

Loading