Пример #1
0
        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
            });
        }
Пример #2
0
        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
            });
        }