Skip to content
This repository was archived by the owner on Nov 2, 2018. It is now read-only.

Commit 10f7b69

Browse files
committed
PR comments
1 parent 8bc9d9d commit 10f7b69

10 files changed

+80
-68
lines changed

korebuild-lock.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version:2.1.0-preview2-15739
2-
commithash:d8c238a4ac822c643d707d9cf44d2dbc93c59a68
1+
version:2.1.0-preview2-15728
2+
commithash:393377068ddcf51dfee0536536d455f57a828b06

src/DI/ServiceLookup/ILEmit/ILEmitCallSiteAnalysisResult.cs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
55
{
6-
internal struct ILEmitCallSiteAnalysisResult
6+
internal readonly struct ILEmitCallSiteAnalysisResult
77
{
88
public ILEmitCallSiteAnalysisResult(int size) : this()
99
{
@@ -20,22 +20,13 @@ public ILEmitCallSiteAnalysisResult(int size, bool hasScope)
2020

2121
public bool HasScope;
2222

23-
public ILEmitCallSiteAnalysisResult Add(ILEmitCallSiteAnalysisResult other)
23+
public ILEmitCallSiteAnalysisResult Add(in ILEmitCallSiteAnalysisResult other)
2424
{
2525
return new ILEmitCallSiteAnalysisResult()
2626
{
2727
Size = Size + other.Size,
2828
HasScope = HasScope | other.HasScope
2929
};
3030
}
31-
32-
public ILEmitCallSiteAnalysisResult Add(byte size)
33-
{
34-
return new ILEmitCallSiteAnalysisResult()
35-
{
36-
Size = Size + size,
37-
HasScope = HasScope
38-
};
39-
}
4031
}
4132
}

src/DI/ServiceLookup/ILEmit/ILEmitCallSiteAnalyzer.cs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,28 @@
33

44
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
55
{
6+
// This class walkes the service scope tree and tries to calculate approximate
7+
// code size to avoid array resizings during IL generation
8+
// It also detects if lock is required to scoped services resolution
69
internal sealed class ILEmitCallSiteAnalyzer : CallSiteVisitor<object, ILEmitCallSiteAnalysisResult>
710
{
11+
private const int ConstructorILSize = 6;
12+
13+
private const int ScopedILSize = 64;
14+
15+
private const int ConstantILSize = 4;
16+
17+
private const int ServiceProviderSize = 1;
18+
19+
private const int FactoryILSize = 16;
20+
821
internal static ILEmitCallSiteAnalyzer Instance { get; } = new ILEmitCallSiteAnalyzer();
922

1023
protected override ILEmitCallSiteAnalysisResult VisitTransient(TransientCallSite transientCallSite, object argument) => VisitCallSite(transientCallSite.ServiceCallSite, argument);
1124

1225
protected override ILEmitCallSiteAnalysisResult VisitConstructor(ConstructorCallSite constructorCallSite, object argument)
1326
{
14-
var result = new ILEmitCallSiteAnalysisResult(6);
27+
var result = new ILEmitCallSiteAnalysisResult(ConstructorILSize);
1528
foreach (var callSite in constructorCallSite.ParameterCallSites)
1629
{
1730
result = result.Add(VisitCallSite(callSite, argument));
@@ -21,27 +34,30 @@ protected override ILEmitCallSiteAnalysisResult VisitConstructor(ConstructorCall
2134

2235
protected override ILEmitCallSiteAnalysisResult VisitSingleton(SingletonCallSite singletonCallSite, object argument) => VisitCallSite(singletonCallSite.ServiceCallSite, argument);
2336

24-
protected override ILEmitCallSiteAnalysisResult VisitScoped(ScopedCallSite scopedCallSite, object argument) => new ILEmitCallSiteAnalysisResult(64, true).Add(VisitCallSite(scopedCallSite.ServiceCallSite, argument));
37+
protected override ILEmitCallSiteAnalysisResult VisitScoped(ScopedCallSite scopedCallSite, object argument)
38+
{
39+
return new ILEmitCallSiteAnalysisResult(ScopedILSize, hasScope: true).Add(VisitCallSite(scopedCallSite.ServiceCallSite, argument));
40+
}
2541

26-
protected override ILEmitCallSiteAnalysisResult VisitConstant(ConstantCallSite constantCallSite, object argument) => new ILEmitCallSiteAnalysisResult(4);
42+
protected override ILEmitCallSiteAnalysisResult VisitConstant(ConstantCallSite constantCallSite, object argument) => new ILEmitCallSiteAnalysisResult(ConstantILSize);
2743

28-
protected override ILEmitCallSiteAnalysisResult VisitCreateInstance(CreateInstanceCallSite createInstanceCallSite, object argument) => new ILEmitCallSiteAnalysisResult(4);
44+
protected override ILEmitCallSiteAnalysisResult VisitCreateInstance(CreateInstanceCallSite createInstanceCallSite, object argument) => new ILEmitCallSiteAnalysisResult(ConstructorILSize);
2945

30-
protected override ILEmitCallSiteAnalysisResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, object argument) => new ILEmitCallSiteAnalysisResult(1);
46+
protected override ILEmitCallSiteAnalysisResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, object argument) => new ILEmitCallSiteAnalysisResult(ServiceProviderSize);
3147

32-
protected override ILEmitCallSiteAnalysisResult VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, object argument) => new ILEmitCallSiteAnalysisResult(6);
48+
protected override ILEmitCallSiteAnalysisResult VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, object argument) => new ILEmitCallSiteAnalysisResult(ConstantILSize);
3349

3450
protected override ILEmitCallSiteAnalysisResult VisitIEnumerable(IEnumerableCallSite enumerableCallSite, object argument)
3551
{
36-
var result = new ILEmitCallSiteAnalysisResult(6);
52+
var result = new ILEmitCallSiteAnalysisResult(ConstructorILSize);
3753
foreach (var callSite in enumerableCallSite.ServiceCallSites)
3854
{
3955
result = result.Add(VisitCallSite(callSite, argument));
4056
}
4157
return result;
4258
}
4359

44-
protected override ILEmitCallSiteAnalysisResult VisitFactory(FactoryCallSite factoryCallSite, object argument) => new ILEmitCallSiteAnalysisResult(16);
60+
protected override ILEmitCallSiteAnalysisResult VisitFactory(FactoryCallSite factoryCallSite, object argument) => new ILEmitCallSiteAnalysisResult(FactoryILSize);
4561

4662
public ILEmitCallSiteAnalysisResult CollectGenerationInfo(IServiceCallSite callSite) => VisitCallSite(callSite, null);
4763
}

src/DI/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ protected override Expression VisitSingleton(SingletonCallSite singletonCallSite
9494
return null;
9595
}
9696

97+
// this.RuntimeResolver.Resolve(singletonCallSite)
98+
9799
argument.Generator.Emit(OpCodes.Ldarg_0);
98100
argument.Generator.Emit(OpCodes.Ldfld, RuntimeResolverField);
99101

@@ -108,6 +110,18 @@ protected override Expression VisitSingleton(SingletonCallSite singletonCallSite
108110

109111
protected override Expression VisitScoped(ScopedCallSite scopedCallSite, ILEmitResolverBuilderContext argument)
110112
{
113+
114+
// var cacheKey = scopedCallSite.CacheKey;
115+
// if (ProviderScope.ResolvedServices.TryGetValue(cacheKey, out value)
116+
// {
117+
// [return] value
118+
// }
119+
// else
120+
// {
121+
// value = [createvalue];
122+
// ProviderScope.ResolvedServices.Add(cacheKey, value);
123+
// }
124+
111125
var resultLocal = argument.Generator.DeclareLocal(scopedCallSite.ServiceType);
112126
var cacheKeyLocal = argument.Generator.DeclareLocal(typeof(object));
113127
var endLabel = argument.Generator.DefineLabel();
@@ -119,7 +133,7 @@ protected override Expression VisitScoped(ScopedCallSite scopedCallSite, ILEmitR
119133
// Duplicate cache key
120134
argument.Generator.Emit(OpCodes.Dup);
121135
// and store to local
122-
StLoc(argument.Generator, cacheKeyLocal.LocalIndex);
136+
Stloc(argument.Generator, cacheKeyLocal.LocalIndex);
123137

124138
// Load address of local
125139
argument.Generator.Emit(OpCodes.Ldloca, resultLocal.LocalIndex);
@@ -143,15 +157,15 @@ protected override Expression VisitScoped(ScopedCallSite scopedCallSite, ILEmitR
143157

144158
argument.Generator.Emit(OpCodes.Ldloc_0);
145159
// Load cache key
146-
LdLoc(argument.Generator, cacheKeyLocal.LocalIndex);
160+
Ldloc(argument.Generator, cacheKeyLocal.LocalIndex);
147161
// Load value
148-
LdLoc(argument.Generator, resultLocal.LocalIndex);
162+
Ldloc(argument.Generator, resultLocal.LocalIndex);
149163

150164
argument.Generator.Emit(OpCodes.Callvirt, ExpressionResolverBuilder.AddMethodInfo);
151165

152166
// Load result and return it
153167
argument.Generator.MarkLabel(endLabel);
154-
LdLoc(argument.Generator, resultLocal.LocalIndex);
168+
Ldloc(argument.Generator, resultLocal.LocalIndex);
155169

156170
return null;
157171
}
@@ -164,46 +178,51 @@ protected override Expression VisitConstant(ConstantCallSite constantCallSite, I
164178

165179
protected override Expression VisitCreateInstance(CreateInstanceCallSite createInstanceCallSite, ILEmitResolverBuilderContext argument)
166180
{
181+
// new Type
167182
argument.Generator.Emit(OpCodes.Newobj, createInstanceCallSite.ImplementationType.GetConstructor(Type.EmptyTypes));
168183
return null;
169184
}
170185

171186
protected override Expression VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, ILEmitResolverBuilderContext argument)
172187
{
173-
// provider
188+
// [return] ProviderScope
174189
argument.Generator.Emit(OpCodes.Ldarg_1);
175190
return null;
176191
}
177192

178193
protected override Expression VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, ILEmitResolverBuilderContext argument)
179194
{
180-
// this
195+
// this.ScopeFactory
181196
argument.Generator.Emit(OpCodes.Ldarg_0);
182-
// .ScopeFactory
183197
argument.Generator.Emit(OpCodes.Ldfld, typeof(ILEmitResolverBuilderRuntimeContext).GetField(nameof(ILEmitResolverBuilderRuntimeContext.ScopeFactory)));
184198
return null;
185199
}
186200

187201
protected override Expression VisitIEnumerable(IEnumerableCallSite enumerableCallSite, ILEmitResolverBuilderContext argument)
188202
{
203+
189204
if (enumerableCallSite.ServiceCallSites.Length == 0)
190205
{
191206
argument.Generator.Emit(OpCodes.Call, ExpressionResolverBuilder.ArrayEmptyMethodInfo.MakeGenericMethod(enumerableCallSite.ItemType));
192207
}
193208
else
194209
{
195-
// push length
210+
211+
// var array = new ItemType[];
212+
// array[0] = [Create argument0];
213+
// array[1] = [Create argument1];
214+
// ...
196215
argument.Generator.Emit(OpCodes.Ldc_I4, enumerableCallSite.ServiceCallSites.Length);
197-
// new ItemType[length]
198216
argument.Generator.Emit(OpCodes.Newarr, enumerableCallSite.ItemType);
199217
for (int i = 0; i < enumerableCallSite.ServiceCallSites.Length; i++)
200218
{
201-
// array
219+
// duplicate array
202220
argument.Generator.Emit(OpCodes.Dup);
203221
// push index
204222
argument.Generator.Emit(OpCodes.Ldc_I4, i);
205223
// create parameter
206224
VisitCallSite(enumerableCallSite.ServiceCallSites[i], argument);
225+
// store
207226
argument.Generator.Emit(OpCodes.Stelem, enumerableCallSite.ItemType);
208227
}
209228
}
@@ -218,19 +237,14 @@ protected override Expression VisitFactory(FactoryCallSite factoryCallSite, ILEm
218237
argument.Factories = new List<Func<IServiceProvider, object>>();
219238
}
220239

221-
// this
240+
// this.Factories[i](ProviderScope)
222241
argument.Generator.Emit(OpCodes.Ldarg_0);
223-
// .Factories
224242
argument.Generator.Emit(OpCodes.Ldfld, FactoriesField);
225243

226-
// i
227244
argument.Generator.Emit(OpCodes.Ldc_I4, argument.Factories.Count);
228-
// [ ]
229245
argument.Generator.Emit(OpCodes.Ldelem, typeof(Func<IServiceProvider, object>));
230246

231-
// provider
232247
argument.Generator.Emit(OpCodes.Ldarg_1);
233-
// ( )
234248
argument.Generator.Emit(OpCodes.Call, ExpressionResolverBuilder.InvokeFactoryMethodInfo);
235249

236250
argument.Factories.Add(factoryCallSite.Factory);
@@ -244,7 +258,8 @@ private void AddConstant(ILEmitResolverBuilderContext argument, object value)
244258
{
245259
argument.Constants = new List<object>();
246260
}
247-
261+
262+
// this.Constants[i]
248263
argument.Generator.Emit(OpCodes.Ldarg_0);
249264
argument.Generator.Emit(OpCodes.Ldfld, ConstantsField);
250265

@@ -256,10 +271,17 @@ private void AddConstant(ILEmitResolverBuilderContext argument, object value)
256271

257272
private Func<ServiceProviderEngineScope, object> BuildType(IServiceCallSite callSite)
258273
{
259-
var dynamicMethod = new DynamicMethod("ResolveService", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(object), new [] {typeof(ILEmitResolverBuilderRuntimeContext), typeof(ServiceProviderEngineScope) }, GetType(), true);
274+
// We need to skit visibility checks because services/constructors might be private
275+
var dynamicMethod = new DynamicMethod("ResolveService",
276+
attributes: MethodAttributes.Public | MethodAttributes.Static,
277+
callingConvention: CallingConventions.Standard,
278+
returnType: typeof(object),
279+
parameterTypes: new [] {typeof(ILEmitResolverBuilderRuntimeContext), typeof(ServiceProviderEngineScope) },
280+
owner: GetType(),
281+
skipVisibility: true);
260282

261283
var info = ILEmitCallSiteAnalyzer.Instance.CollectGenerationInfo(callSite);
262-
var context2 = GenerateMethodBody(callSite, dynamicMethod.GetILGenerator(info.Size), info);
284+
var runtimeContext = GenerateMethodBody(callSite, dynamicMethod.GetILGenerator(info.Size), info);
263285

264286
#if SAVE_ASSEMBLY
265287
var assemblyName = "Test" + DateTime.Now.Ticks;
@@ -278,7 +300,7 @@ private Func<ServiceProviderEngineScope, object> BuildType(IServiceCallSite call
278300
assembly.Save(assemblyName+".dll");
279301
#endif
280302

281-
return (Func<ServiceProviderEngineScope, object>)dynamicMethod.CreateDelegate(typeof(Func<ServiceProviderEngineScope, object>), context2);
303+
return (Func<ServiceProviderEngineScope, object>)dynamicMethod.CreateDelegate(typeof(Func<ServiceProviderEngineScope, object>), runtimeContext);
282304
}
283305

284306
private ILEmitResolverBuilderRuntimeContext GenerateMethodBody(IServiceCallSite callSite, ILGenerator generator, ILEmitCallSiteAnalysisResult info)
@@ -320,7 +342,7 @@ private ILEmitResolverBuilderRuntimeContext GenerateMethodBody(IServiceCallSite
320342
{
321343
var resultLocal = context.Generator.DeclareLocal(typeof(object));
322344

323-
StLoc(context.Generator, resultLocal.LocalIndex);
345+
Stloc(context.Generator, resultLocal.LocalIndex);
324346
context.Generator.BeginFinallyBlock();
325347

326348
var postExitLabel = context.Generator.DefineLabel();
@@ -335,7 +357,7 @@ private ILEmitResolverBuilderRuntimeContext GenerateMethodBody(IServiceCallSite
335357

336358
context.Generator.EndExceptionBlock();
337359

338-
LdLoc(context.Generator, resultLocal.LocalIndex);
360+
Ldloc(context.Generator, resultLocal.LocalIndex);
339361
}
340362

341363
context.Generator.Emit(OpCodes.Ret);
@@ -359,7 +381,7 @@ private bool TryResolveSingletonValue(SingletonCallSite singletonCallSite, out o
359381

360382
private static bool BeginCaptureDisposable(Type implType, ILEmitResolverBuilderContext argument)
361383
{
362-
var shouldCapture = !(implType != null && !typeof(IDisposable).GetTypeInfo().IsAssignableFrom(implType.GetTypeInfo()));
384+
var shouldCapture = implType == null || typeof(IDisposable).GetTypeInfo().IsAssignableFrom(implType.GetTypeInfo());
363385

364386
if (shouldCapture)
365387
{
@@ -369,12 +391,13 @@ private static bool BeginCaptureDisposable(Type implType, ILEmitResolverBuilderC
369391

370392
return shouldCapture;
371393
}
394+
372395
private static void EndCaptureDisposable(ILEmitResolverBuilderContext argument)
373396
{
374397
argument.Generator.Emit(OpCodes.Callvirt, ExpressionResolverBuilder.CaptureDisposableMethodInfo);
375398
}
376399

377-
private void LdLoc(ILGenerator generator, int index)
400+
private void Ldloc(ILGenerator generator, int index)
378401
{
379402
switch (index)
380403
{
@@ -397,7 +420,7 @@ private void LdLoc(ILGenerator generator, int index)
397420
generator.Emit(OpCodes.Ldloc, index);
398421
}
399422

400-
private void StLoc(ILGenerator generator, int index)
423+
private void Stloc(ILGenerator generator, int index)
401424
{
402425
switch (index)
403426
{

src/DI/ServiceLookup/IServiceCallSite.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,5 @@ internal interface IServiceCallSite
1313
Type ServiceType { get; }
1414
Type ImplementationType { get; }
1515
CallSiteKind Kind { get; }
16-
1716
}
1817
}

src/DI/ServiceLookup/ReferenceEqualsEqualityComparer.cs

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

src/DI/ServiceLookup/ServiceProviderEngine.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptor
2424
CallSiteFactory = new CallSiteFactory(serviceDescriptors);
2525
CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
2626
CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());
27-
28-
RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>(new ReferenceEqualsEqualityComparer<Type>());
27+
RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
2928
}
3029

3130
internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; }

src/DI/ServiceLookup/ServiceProviderEngineScope.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ internal class ServiceProviderEngineScope : IServiceScope, IServiceProvider
1818
public ServiceProviderEngineScope(ServiceProviderEngine engine)
1919
{
2020
Engine = engine;
21-
ResolvedServices = new Dictionary<object, object>();
2221
}
2322

24-
internal Dictionary<object, object> ResolvedServices { get; }
23+
internal Dictionary<object, object> ResolvedServices { get; } = new Dictionary<object, object>();
2524

2625
public ServiceProviderEngine Engine { get; }
2726

test/DI.Tests/ServiceProviderCompilationTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ private async Task CompilesInLimitedStackSpace(ServiceProviderMode mode, Type se
2828
var stackSize = 256 * 1024;
2929
var serviceCollection = new ServiceCollection();
3030
CompilationTestDataProvider.Register(serviceCollection);
31-
var serviceProvider = serviceCollection.BuildServiceProvider(new ServiceProviderOptions() { Mode = mode });
31+
var serviceProvider = serviceCollection.BuildServiceProvider(new ServiceProviderOptions { Mode = mode });
3232

3333
// Act + Assert
3434

test/DI.Tests/ServiceProviderILEmitContainerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Microsoft.Extensions.DependencyInjection.Tests
77
{
8-
public class ServiceProviderILEmitContainerTests: ServiceProviderContainerTests
8+
public class ServiceProviderILEmitContainerTests : ServiceProviderContainerTests
99
{
1010
protected override IServiceProvider CreateServiceProvider(IServiceCollection collection) =>
1111
collection.BuildServiceProvider(new ServiceProviderOptions() { Mode = ServiceProviderMode.ILEmit});

0 commit comments

Comments
 (0)