Exemplo n.º 1
0
        /// <summary>
        /// Emits the instructions that will instantiate the current implementation.
        /// </summary>
        /// <param name="dependency">The dependency that describes the service to be instantiated.</param>
        /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param>
        /// <param name="targetMethod">The target method.</param>
        public void Emit(IDependency dependency, IDictionary<IDependency, IImplementation> serviceMap, MethodDefinition targetMethod)
        {
            var declaringType = targetMethod.DeclaringType;
            var module = declaringType.Module;

            var microContainerType = module.ImportType<IMicroContainer>();

            var il = targetMethod.GetILGenerator();

            // if (this is IMicroContainer && this.NextContainer != null) {
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Isinst, microContainerType);

            var skipCreate = il.Create(OpCodes.Nop);
            il.Emit(OpCodes.Brfalse, skipCreate);

            EmitGetContainerInstance(module, microContainerType, il, skipCreate);

            var getInstance = module.ImportMethod<IMicroContainer>("GetInstance");
            var getTypeFromHandleMethod = typeof(System.Type).GetMethod("GetTypeFromHandle", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
            var getTypeFromHandle = module.Import(getTypeFromHandleMethod);

            // Push the service type onto the stack
            var serviceType = module.Import(_serviceType);
            il.Emit(OpCodes.Ldtoken, serviceType);
            il.Emit(OpCodes.Call, getTypeFromHandle);

            var loadString = string.IsNullOrEmpty(_serviceName)
                                 ? il.Create(OpCodes.Ldnull)
                                 : il.Create(OpCodes.Ldstr, _serviceName);

            il.Append(loadString);
            il.Emit(OpCodes.Callvirt, getInstance);

            var endLabel = il.Create(OpCodes.Nop);
            il.Emit(OpCodes.Br, endLabel);

            il.Append(skipCreate);

            var serviceNotFoundExceptionCtor = module.ImportConstructor<ServiceNotFoundException>(typeof(string),
                                                                                                  typeof(System.Type));
            var serviceName = dependency.ServiceName ?? string.Empty;
            il.Emit(OpCodes.Ldstr, serviceName);
            il.Emit(OpCodes.Ldtoken, serviceType);
            il.Emit(OpCodes.Call, getTypeFromHandle);

            il.Emit(OpCodes.Newobj, serviceNotFoundExceptionCtor);
            il.Emit(OpCodes.Throw);

            il.Append(endLabel);

            // }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Emits the instructions that will instantiate the current implementation.
        /// </summary>
        /// <param name="dependency">The dependency that describes the service to be instantiated.</param>
        /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param>
        /// <param name="targetMethod">The target method.</param>
        public void Emit(IDependency dependency, IDictionary<IDependency, IImplementation> serviceMap, MethodDefinition targetMethod)
        {
            var declaringType = targetMethod.DeclaringType;
            var module = declaringType.Module;

            var listType = typeof(List<>).MakeGenericType(_serviceType);
            var listCtor = module.ImportConstructor(listType, new Type[0]);

            var listVariable = targetMethod.AddLocal(listType);
            var IL = targetMethod.GetILGenerator();
            IL.Emit(OpCodes.Newobj, listCtor);
            IL.Emit(OpCodes.Stloc, listVariable);

            var targetDependencies = (from d in serviceMap.Keys
                                     where d.ServiceType == _serviceType
                                     select d).ToArray();

            var addItem = module.ImportMethod("Add", listType);

            var serviceType = module.Import(_serviceType);
            var currentService = targetMethod.AddLocal(_serviceType);
            foreach(var currentDependency in targetDependencies)
            {
                IL.Emit(OpCodes.Ldloc, listVariable);

                // Instantiate the current service type
                var implementation = new ContainerCall(currentDependency.ServiceType, currentDependency.ServiceName);
                implementation.Emit(currentDependency, serviceMap, targetMethod);

                IL.Emit(OpCodes.Isinst, serviceType);
                IL.Emit(OpCodes.Stloc, currentService);

                // Call IInitialize.Initialize(container) on the current service type
                _initializer.Initialize(IL, module, currentService);

                IL.Emit(OpCodes.Ldloc, currentService);
                IL.Emit(OpCodes.Callvirt, addItem);
            }

            var enumerableType = typeof(IEnumerable<>).MakeGenericType(_serviceType);
            var importedEnumerableType = module.Import(enumerableType);

            IL.Emit(OpCodes.Ldloc, listVariable);
            IL.Emit(OpCodes.Isinst, importedEnumerableType);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Emits the <see cref="IFactory{T}.Create"/> method call that will instantiate the current service instance.
        /// </summary>
        /// <param name="dependency">The dependency that describes the service to be instantiated.</param>
        /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param>
        /// <param name="targetMethod">The target method.</param>
        public void Emit(IDependency dependency, IDictionary<IDependency, IImplementation> serviceMap, MethodDefinition targetMethod)
        {
            var factoryType = typeof (IFactory<>).MakeGenericType(_serviceType);
            var getFactoryInstanceCall = new ContainerCall(factoryType, _serviceName);

            var factoryName = _serviceName;
            getFactoryInstanceCall.Emit(new Dependency(factoryType, factoryName), serviceMap, targetMethod);

            var declaringType = targetMethod.DeclaringType;
            var module = declaringType.Module;
            var factoryTypeReference = module.Import(factoryType);

            var createMethod = module.Import(factoryType.GetMethod("Create"));

            var IL = targetMethod.GetILGenerator();
            IL.Emit(OpCodes.Isinst, factoryTypeReference);
            IL.Emit(OpCodes.Callvirt, createMethod);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Emits a service as a singleton type.
        /// </summary>
        /// <param name="targetMethod">The <see cref="IMicroContainer.GetInstance"/> method implementation.</param>
        /// <param name="dependency">The dependency that will be instantiated by the container.</param>
        /// <param name="implementation">The implementation that will be used to instantiate the dependency.</param>
        /// <param name="serviceMap">The service map the contains the current application dependencies.</param>
        public void EmitService(MethodDefinition targetMethod, IDependency dependency, 
                                IImplementation implementation, IDictionary<IDependency, IImplementation> serviceMap)
        {
            MethodDefinition getInstanceMethod = null;

            var worker = targetMethod.GetILGenerator();

            // Emit only one singleton per dependency and call
            // the singleton GetInstance() method on every subsequent emit call
            if (_entries.ContainsKey(dependency))
            {
                getInstanceMethod = _entries[dependency];
                worker.Emit(OpCodes.Call, getInstanceMethod);
                return;
            }

            var declaringType = targetMethod.DeclaringType;
            var module = declaringType.Module;

            var serviceType = dependency.ServiceType;

            var typeName = serviceType.Name;
            var singletonName = string.Format("{0}ServiceSingleton-{1}", typeName, dependency.GetHashCode());
            const TypeAttributes typeAttributes = TypeAttributes.NotPublic | TypeAttributes.AutoClass | TypeAttributes.Sealed |
                                                  TypeAttributes.BeforeFieldInit;
            var objectType = module.Import(typeof(object));

            var singletonType = AddDefaultSingletonConstructor(module, singletonName, typeAttributes, objectType);

            var instanceField = new FieldDefinition("__instance", FieldAttributes.Assembly | FieldAttributes.InitOnly | FieldAttributes.Static, objectType);

            DefineNestedType(module, singletonType, instanceField, serviceMap, implementation, dependency,
                             targetMethod);

            getInstanceMethod = DefineGetInstance(singletonType, worker, instanceField);

            worker.Emit(OpCodes.Call, getInstanceMethod);

            var serviceTypeRef = module.Import(serviceType);
            worker.Emit(OpCodes.Unbox_Any, serviceTypeRef);

            // Cache the singleton method
            _entries[dependency] = getInstanceMethod;
        }
Exemplo n.º 5
0
 /// <summary>
 /// Emits the instructions that will instantiate the current implementation.
 /// </summary>
 /// <param name="dependency">The dependency that describes the service to be instantiated.</param>
 /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param>
 /// <param name="targetMethod">The target method.</param>
 public void Emit(IDependency dependency, IDictionary<IDependency, IImplementation> serviceMap, MethodDefinition targetMethod)
 {
     var IL = targetMethod.GetILGenerator();
     IL.Emit(OpCodes.Ldarg_0);
 }
Exemplo n.º 6
0
        /// <summary>
        /// Emits the IL to save information about
        /// the method currently being executed.
        /// </summary>
        /// <seealso cref="IInvocationInfo"/>
        /// <param name="targetMethod">The target method currently being executed.</param>
        /// <param name="interceptedMethod">The method that will be passed to the <paramref name="invocationInfo"/> as the currently executing method.</param>
        /// <param name="invocationInfo">The local variable that will store the resulting <see cref="IInvocationInfo"/> instance.</param>
        public void Emit(MethodDefinition targetMethod, MethodReference interceptedMethod, VariableDefinition invocationInfo)
        {
            var module = targetMethod.DeclaringType.Module;
            var currentMethod = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(MethodBase));
            var parameterTypes = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(Type[]));
            var arguments = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(object[]));
            var typeArguments = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(Type[]));
            var systemType = module.ImportType(typeof(Type));

            var IL = targetMethod.GetILGenerator();
            #region Initialize the InvocationInfo constructor arguments

            // Type[] typeArguments = new Type[genericTypeCount];
            var genericParameterCount = targetMethod.GenericParameters.Count;
            IL.Emit(OpCodes.Ldc_I4, genericParameterCount);
            IL.Emit(OpCodes.Newarr, systemType);
            IL.Emit(OpCodes.Stloc, typeArguments);

            // object[] arguments = new object[argumentCount];
            IL.PushArguments(targetMethod, module, arguments);

            // object target = this;
            if (targetMethod.HasThis)
                IL.Emit(OpCodes.Ldarg_0);
            else
                IL.Emit(OpCodes.Ldnull);

            IL.PushMethod(interceptedMethod, module);

            IL.Emit(OpCodes.Stloc, currentMethod);

            // MethodBase targetMethod = currentMethod as MethodBase;
            IL.Emit(OpCodes.Ldloc, currentMethod);

            // Push the generic type arguments onto the stack
            if (genericParameterCount > 0)
                IL.PushGenericArguments(targetMethod, module, typeArguments);

            // Make sure that the generic methodinfo is instantiated with the
            // proper type arguments
            if (targetMethod.GenericParameters.Count > 0)
            {
                var methodInfoType = module.Import(typeof(MethodInfo));
                IL.Emit(OpCodes.Isinst, methodInfoType);

                var getIsGenericMethodDef = module.ImportMethod<MethodInfo>("get_IsGenericMethodDefinition");
                IL.Emit(OpCodes.Dup);
                IL.Emit(OpCodes.Callvirt, getIsGenericMethodDef);

                // Determine if the current method is a generic method
                // definition
                var skipMakeGenericMethod = IL.Create(OpCodes.Nop);
                IL.Emit(OpCodes.Brfalse, skipMakeGenericMethod);

                // Instantiate the specific generic method instance
                var makeGenericMethod = module.ImportMethod<MethodInfo>("MakeGenericMethod", typeof(Type[]));
                IL.Emit(OpCodes.Ldloc, typeArguments);
                IL.Emit(OpCodes.Callvirt, makeGenericMethod);
                IL.Append(skipMakeGenericMethod);
            }

            if (_pushStackTrace)
                IL.PushStackTrace(module);
            else
                IL.Emit(OpCodes.Ldnull);

            // Save the parameter types
            IL.Emit(OpCodes.Ldc_I4, targetMethod.Parameters.Count);
            IL.Emit(OpCodes.Newarr, systemType);
            IL.Emit(OpCodes.Stloc, parameterTypes);

            IL.SaveParameterTypes(targetMethod, module, parameterTypes);
            IL.Emit(OpCodes.Ldloc, parameterTypes);

            // Push the type arguments back onto the stack
            IL.Emit(OpCodes.Ldloc, typeArguments);

            // Save the return type
            var getTypeFromHandle = module.Import(_getTypeFromHandle);

            var returnType = targetMethod.ReturnType.ReturnType;
            IL.Emit(OpCodes.Ldtoken, returnType);
            IL.Emit(OpCodes.Call, getTypeFromHandle);

            // Push the arguments back onto the stack
            IL.Emit(OpCodes.Ldloc, arguments);
            #endregion

            // InvocationInfo info = new InvocationInfo(...);
            var infoConstructor = module.Import(_invocationInfoConstructor);
            IL.Emit(OpCodes.Newobj, infoConstructor);
            IL.Emit(OpCodes.Stloc, invocationInfo);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Creates a property setter method implementation with the
        /// <paramref name="propertyType"/> as the setter parameter.
        /// </summary>
        /// <param name="propertyType">Represents the <see cref="TypeReference">parameter type</see> for the setter method.</param>
        /// <param name="attributes">The method attributes associated with the setter method.</param>
        /// <param name="backingField">The field that will store the instance for the setter method.</param>
        /// <param name="setterName">The method name of the setter method.</param>
        /// <param name="voidType">The <see cref="TypeReference"/> that represents <see cref="Void"/>.</param>
        /// <returns>A <see cref="MethodDefinition"/> that represents the setter method itself.</returns>
        private static MethodDefinition AddPropertySetter(TypeReference propertyType, MethodAttributes attributes, FieldReference backingField, string setterName, TypeReference voidType)
        {
            var setter = new MethodDefinition(setterName, attributes, voidType)
                             {
                                 IsPublic = true,
                                 ImplAttributes = (MethodImplAttributes.Managed | MethodImplAttributes.IL)
                             };

            setter.Parameters.Add(new ParameterDefinition(propertyType));

            var IL = setter.GetILGenerator();
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Stfld, backingField);
            IL.Emit(OpCodes.Ret);

            return setter;
        }
Exemplo n.º 8
0
        /// <summary>
        /// Creates a property getter method implementation with the
        /// <paramref name="propertyType"/> as the return type.
        /// </summary>
        /// <param name="propertyType">Represents the <see cref="TypeReference">return type</see> for the getter method.</param>
        /// <param name="getterName">The getter method name.</param>
        /// <param name="attributes">The method attributes associated with the getter method.</param>
        /// <param name="backingField">The field that will store the instance that the getter method will retrieve.</param>
        /// <returns>A <see cref="MethodDefinition"/> representing the getter method itself.</returns>
        private static MethodDefinition AddPropertyGetter(TypeReference propertyType,
            string getterName, MethodAttributes attributes, FieldReference backingField)
        {
            var getter = new MethodDefinition(getterName, attributes, propertyType)
                             {
                                 IsPublic = true,
                                 ImplAttributes = (MethodImplAttributes.Managed | MethodImplAttributes.IL)
                             };

            var IL = getter.GetILGenerator();
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Ldfld, backingField);
            IL.Emit(OpCodes.Ret);

            return getter;
        }
        /// <summary>
        /// Saves the current <see cref="IExceptionHandlerInfo"/> instance.
        /// </summary>
        /// <param name="targetMethod">The target method.</param>
        /// <param name="emitter">The <see cref="IEmitInvocationInfo"/> instance that will emit the current method context.</param>
        private void SaveExceptionInfo(MethodDefinition targetMethod, IEmitInvocationInfo emitter)
        {
            var IL = targetMethod.GetILGenerator();
            var module = IL.GetModule();

            emitter.Emit(targetMethod, targetMethod, _invocationInfo);
            IL.Emit(OpCodes.Ldloc, _exception);
            IL.Emit(OpCodes.Ldloc, _invocationInfo);

            var exceptionInfoConstructor = module.ImportConstructor<ExceptionHandlerInfo>(
                typeof (Exception),
                typeof (IInvocationInfo));
            IL.Emit(OpCodes.Newobj, exceptionInfoConstructor);
            IL.Emit(OpCodes.Stloc, _exceptionInfo);

            var returnType = targetMethod.ReturnType.ReturnType;
            if (returnType == _voidType || _returnValue == null)
                return;

            // exceptionInfo.ReturnValue = returnValue;
            var setReturnValue = module.ImportMethod<IExceptionHandlerInfo>("set_ReturnValue");
            IL.Emit(OpCodes.Ldloc, _exceptionInfo);
            IL.Emit(OpCodes.Ldloc, _returnValue);
            IL.Emit(OpCodes.Callvirt, setReturnValue);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Generates a method body for the <paramref name="targetMethod"/>.
        /// </summary>
        /// <param name="originalMethod">The method currently being intercepted.</param>
        /// <param name="targetMethod">The target method that will contain the new method body.</param>
        public void Emit(MethodInfo originalMethod, MethodDefinition targetMethod)
        {
            var invocationInfo = targetMethod.AddLocal<IInvocationInfo>();
            invocationInfo.Name = "___invocationInfo___";

            // Emit the code to generate the IInvocationInfo instance
            // and save it into the invocationInfo local variable
            if (InvocationInfoEmitter != null)
                InvocationInfoEmitter.Emit(originalMethod, targetMethod, invocationInfo);

            var declaringType = targetMethod.DeclaringType;
            var module = declaringType.Module;
            var proxyType = module.ImportType<IProxy>();
            var getInterceptorMethod = module.ImportMethod("get_Interceptor", typeof (IProxy));
            var interceptor = targetMethod.AddLocal<IInterceptor>();
            var arguments = targetMethod.AddLocal<object[]>();

            // if (!(this is IProxy))
            var IL = targetMethod.GetILGenerator();
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Isinst, proxyType);

            var noImplementationFound = IL.Create(OpCodes.Nop);
            IL.Emit(OpCodes.Brfalse, noImplementationFound);

            var endLabel = IL.Create(OpCodes.Nop);
            EmitGetInterceptorInstruction(IL, proxyType, getInterceptorMethod);
            IL.Emit(OpCodes.Stloc, interceptor);

            //If (interceptor == null)
            //    throw a not implemented exception here
            IL.Emit(OpCodes.Ldloc, interceptor);
            IL.Emit(OpCodes.Brfalse, noImplementationFound);

            // var returnValue = interceptor.Intercept(info);
            var voidType = module.ImportType(typeof (void));
            var interceptMethod = module.ImportMethod<IInterceptor>("Intercept", typeof (IInvocationInfo));
            IL.Emit(OpCodes.Ldloc, interceptor);
            IL.Emit(OpCodes.Ldloc, invocationInfo);
            IL.Emit(OpCodes.Callvirt, interceptMethod);

            // Save the ref arguments
            var parameters = from ParameterDefinition param in targetMethod.Parameters
                select param;

            // Determine the return type
            var returnType = targetMethod.ReturnType != null
                ? targetMethod.ReturnType.ReturnType
                : voidType;

            IL.PackageReturnValue(module, returnType);

            SaveRefArguments(IL, parameters, invocationInfo, arguments);
            IL.Emit(OpCodes.Br, endLabel);

            // This code at this point will execute if no implementation
            // is found
            IL.Append(noImplementationFound);

            ImplementNotFound(IL);

            IL.Append(endLabel);
            IL.Emit(OpCodes.Ret);
        }
Exemplo n.º 11
0
        /// <summary>
        /// Defines the instructions that will instantiate the singleton instance itself.
        /// </summary>
        /// <param name="dependency">The dependency that will be instantiated by the singleton.</param>
        /// <param name="implementation">The implementation that will instantiate the dependency.</param>
        /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param>
        /// <param name="instanceField">The field that will hold the singleton instance.</param>
        /// <param name="cctor">The static constructor itself.</param>
        /// <param name="module">The target module.</param>
        /// <param name="targetMethod">The target method that will instantiate the service instance.</param>
        protected virtual void EmitSingletonInstantiation(IDependency dependency, 
            IImplementation implementation, 
            IDictionary<IDependency, IImplementation> serviceMap, 
            FieldDefinition instanceField, 
            MethodDefinition cctor, 
            ModuleDefinition module,
            MethodDefinition targetMethod)
        {
            var worker = cctor.GetILGenerator();
            implementation.Emit(dependency, serviceMap, cctor);

            worker.Emit(OpCodes.Stsfld, instanceField);
            worker.Emit(OpCodes.Ret);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Emits the instructions that will instantiate the current implementation.
        /// </summary>
        /// <param name="dependency">The dependency that describes the service to be instantiated.</param>
        /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param>
        /// <param name="targetMethod">The target method.</param>
        public void Emit(IDependency dependency, IDictionary<IDependency, IImplementation> serviceMap, MethodDefinition targetMethod)
        {
            _emitter.EmitService(targetMethod, dependency, _implementation, serviceMap);

            var il = targetMethod.GetILGenerator();

            var module = targetMethod.Module;
            var serviceType = module.Import(dependency.ServiceType);
            if (serviceType.IsValueType)
                return;

            il.Emit(OpCodes.Castclass, serviceType);
        }