private GeneratedMethod BuildTypeNoCache(ServiceCallSite callSite) { // We need to skip visibility checks because services/constructors might be private var dynamicMethod = new DynamicMethod("ResolveService", attributes: MethodAttributes.Public | MethodAttributes.Static, callingConvention: CallingConventions.Standard, returnType: typeof(object), parameterTypes: new[] { typeof(ILEmitResolverBuilderRuntimeContext), typeof(ServiceProviderEngineScope) }, owner: GetType(), skipVisibility: true); ILEmitCallSiteAnalysisResult info = ILEmitCallSiteAnalyzer.Instance.CollectGenerationInfo(callSite); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(info.Size); ILEmitResolverBuilderRuntimeContext runtimeContext = GenerateMethodBody(callSite, ilGenerator); #if SAVE_ASSEMBLIES var assemblyName = "Test" + DateTime.Now.Ticks; var fileName = "Test" + DateTime.Now.Ticks; var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.RunAndSave); var module = assembly.DefineDynamicModule(assemblyName, assemblyName + ".dll"); var type = module.DefineType("Resolver"); var method = type.DefineMethod( "ResolveService", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(object), new[] { typeof(ILEmitResolverBuilderRuntimeContext), typeof(ServiceProviderEngineScope) }); GenerateMethodBody(callSite, method.GetILGenerator(), info); type.CreateTypeInfo(); assembly.Save(assemblyName + ".dll"); #endif DependencyInjectionEventSource.Log.DynamicMethodBuilt(callSite.ServiceType, ilGenerator.ILOffset); return(new GeneratedMethod() { Lambda = (Func <ServiceProviderEngineScope, object>)dynamicMethod.CreateDelegate(typeof(Func <ServiceProviderEngineScope, object>), runtimeContext), Context = runtimeContext, DynamicMethod = dynamicMethod }); }
private ILEmitResolverBuilderRuntimeContext GenerateMethodBody(IServiceCallSite callSite, ILGenerator generator, ILEmitCallSiteAnalysisResult info) { var context = new ILEmitResolverBuilderContext() { Generator = generator, Constants = null, Factories = null }; // try // { // Monitor.Enter(scope.ResolvedServices, out var lockTaken); // return [ create value ] // } // finally // { // if (lockTaken) Monitor.Exit(scope.ResolvedServices); // } var hasScopes = info.HasScope; if (hasScopes) { // Has to be first local defined var resolvedServicesLocal = context.Generator.DeclareLocal(typeof(IDictionary <object, object>)); Debug.Assert(resolvedServicesLocal.LocalIndex == 0); var lockTakenLocal = context.Generator.DeclareLocal(typeof(bool)); Debug.Assert(lockTakenLocal.LocalIndex == 1); context.Generator.BeginExceptionBlock(); // scope context.Generator.Emit(OpCodes.Ldarg_1); // .ResolvedServices context.Generator.Emit(OpCodes.Callvirt, ResolvedServicesGetter); context.Generator.Emit(OpCodes.Dup); // Store resolved services context.Generator.Emit(OpCodes.Stloc_0); context.Generator.Emit(OpCodes.Ldloca_S, 1); // Monitor.Enter context.Generator.Emit(OpCodes.Call, ExpressionResolverBuilder.MonitorEnterMethodInfo); } VisitCallSite(callSite, context); if (hasScopes) { var resultLocal = context.Generator.DeclareLocal(typeof(object)); Stloc(context.Generator, resultLocal.LocalIndex); context.Generator.BeginFinallyBlock(); var postExitLabel = context.Generator.DefineLabel(); context.Generator.Emit(OpCodes.Ldloc_1); context.Generator.Emit(OpCodes.Brfalse, postExitLabel); context.Generator.Emit(OpCodes.Ldloc, 0); // Monitor.Exit context.Generator.Emit(OpCodes.Call, ExpressionResolverBuilder.MonitorExitMethodInfo); context.Generator.MarkLabel(postExitLabel); context.Generator.EndExceptionBlock(); Ldloc(context.Generator, resultLocal.LocalIndex); } context.Generator.Emit(OpCodes.Ret); return(new ILEmitResolverBuilderRuntimeContext { Constants = context.Constants?.ToArray(), Factories = context.Factories?.ToArray(), Root = _rootScope, RuntimeResolver = _runtimeResolver, ScopeFactory = _serviceScopeFactory }); }