Ejemplo n.º 1
0
        private static void AddPropertyInitializeInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var declaringType         = member.Property.OriginType;
            var syncRoot              = new __ISyncRoot();
            var legalInitInterceptors = member.InterceptorInfos.Where(x => x.InterfaceInitializer != null).ToArray();
            var relevantCtors         = member.Property.IsStatic ? new Method[] { declaringType.StaticConstructor } : declaringType.GetRelevantConstructors().Where(x => x.Name != ".cctor");

            foreach (var ctor in relevantCtors)
            {
                ctor.NewCode()
                .Context(x =>
                {
                    for (int i = 0; i < legalInitInterceptors.Length; i++)
                    {
                        var item  = legalInitInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];

                        x.Assign(field).NewObj(item.Attribute);
                        if (item.HasSyncRootInterface)
                        {
                            x.Load(field).As(__ISyncRoot.Type.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }

                        ImplementAssignMethodAttribute(builder, legalInitInterceptors[i].AssignMethodAttributeInfos, field, item.Attribute.Attribute.Type, x);
                    }

                    x.Assign(propertyField)
                    .NewObj(propertyInterceptionInfo.Ctor,
                            member.Property.Getter,
                            member.Property.Setter,
                            member.Property.Name,
                            member.Property.ReturnType,
                            Crumb.This,
                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                            propertySetter == null ? null : x.NewCode().NewObj(actionObjectCtor, propertySetter));

                    for (int i = 0; i < legalInitInterceptors.Length; i++)
                    {
                        var item  = legalInitInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(item.InterfaceInitializer.ToBuilderType)
                        .Call(item.InterfaceInitializer.OnInitialize, propertyField, member.Property.BackingField);
                    }
                })
                .Insert(InsertionPosition.Beginning);
            }
        }
        private void InterceptConstructors(Builder builder, IEnumerable <BuilderType> attributes)
        {
            if (!attributes.Any())
            {
                return;
            }

            using (new StopwatchLog(this, "constructor"))
            {
                var iConstructorInterceptor = new __IConstructorInterceptor();
                var syncRoot  = new __ISyncRoot();
                var exception = new __Exception();

                var constructors = builder
                                   .FindMethodsByAttributes(attributes)
                                   .Where(x => !x.Method.OriginType.IsInterface)
                                   .GroupBy(x => new MethodKey(x.Method, null))
                                   .Select(x => new MethodBuilderInfo <MethodBuilderInfoItem <__IConstructorInterceptor> >(x.Key, x.Select(y => new MethodBuilderInfoItem <__IConstructorInterceptor>(y, iConstructorInterceptor))))
                                   .ToArray();

                foreach (var constructor in constructors)
                {
                    this.Log($"Implementing constructors in method {constructor.Key.Method}");

                    if (constructor.Item == null || constructor.Item.Length == 0)
                    {
                        continue;
                    }

                    var targetedConstrutor = constructor.Key.Method;

                    if (constructor.RequiresSyncRootField)
                    {
                        this.Log(LogTypes.Warning, targetedConstrutor, $"An interceptor applied to the constructor has implemented ISyncRoot. This is not supported. The interceptor may not work correctly.");
                    }

                    Crumb parametersArray = null;
                    var   localVariables  = new LocalVariable[constructor.Item.Length];
                    var   interceptorInit = new Action <ICode, bool>((contextCoder, isBeforeInit) =>
                    {
                        parametersArray = contextCoder.GetParametersArray();

                        for (int i = 0; i < constructor.Item.Length; i++)
                        {
                            var item          = constructor.Item[i];
                            localVariables[i] = contextCoder.CreateVariable(item.Attribute.Attribute.Type);

                            contextCoder.Assign(localVariables[i]).NewObj(item.Attribute);

                            ImplementAssignMethodAttribute(builder, item.AssignMethodAttributeInfos, localVariables[i], contextCoder, isBeforeInit);

                            contextCoder.Load(localVariables[i]).As(item.Interface.ToBuilderType)
                            .Call(item.Interface.OnBeforeInitialization, targetedConstrutor.OriginType, targetedConstrutor, parametersArray);

                            item.Attribute.Remove();
                        }
                    });

                    if (targetedConstrutor.IsCtor)
                    {
                        targetedConstrutor.NewCode()
                        .Context(x => interceptorInit(x, true))
                        .Insert(InsertionPosition.CtorBeforeInit);
                    }

                    targetedConstrutor.NewCode()
                    .Context(x =>
                    {
                        if (targetedConstrutor.IsCCtor)
                        {
                            interceptorInit(x, false);
                        }
                    })
                    .Try(x =>
                    {
                        for (int i = 0; i < constructor.Item.Length; i++)
                        {
                            var item = constructor.Item[i];
                            x.Load(localVariables[i]).As(item.Interface.ToBuilderType)
                            .Call(item.Interface.OnEnter, targetedConstrutor.OriginType, Crumb.This, targetedConstrutor, parametersArray);
                        }

                        x.OriginalBody();
                    })
                    .Catch(exception.ToBuilderType, x =>
                    {
                        if (constructor.Key.AsyncMethod == null)
                        {
                            for (int i = 0; i < constructor.Item.Length; i++)
                            {
                                x.Load(localVariables[i]).As(constructor.Item[i].Interface.ToBuilderType).Call(constructor.Item[i].Interface.OnException, x.Exception);
                            }
                        }

                        x.Rethrow();
                    })
                    .Finally(x =>
                    {
                        for (int i = 0; i < constructor.Item.Length; i++)
                        {
                            x.Load(localVariables[i]).As(constructor.Item[i].Interface.ToBuilderType).Call(constructor.Item[i].Interface.OnExit);
                        }
                    })
                    .EndTry()
                    .Return()
                    .Replace();
                }
            }
        }
        private static void AddPropertySetterInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var syncRoot = new __ISyncRoot(builder);
            var legalSetterInterceptors = member.InterceptorInfos.Where(x => x.InterfaceSetter != null).ToArray();

            member.Property.Setter
            .NewCode()
            .Context(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).IsNull().Then(y =>
                    {
                        y.Assign(field).NewObj(item.Attribute);

                        if (item.HasSyncRootInterface)
                        {
                            y.Load(field).As(syncRoot.Type.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }
                    });
                    item.Attribute.Remove();
                }

                x.Load(propertyField).IsNull().Then(y =>
                                                    y.Assign(propertyField)
                                                    .NewObj(propertyInterceptionInfo.Ctor,
                                                            member.Property.Getter,
                                                            member.Property.Setter,
                                                            member.Property.Name,
                                                            member.Property.ReturnType,
                                                            y.This,
                                                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                                                            y.NewCode().NewObj(actionObjectCtor, propertySetter)));
            })
            .Try(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(item.InterfaceSetter.OnSet, propertyField, member.Property.BackingField, member.Property.Setter.NewCode().GetParameter(0));

                    x.IsFalse().Then(y => y.Assign(member.Property.BackingField).Set(member.Property.Setter.NewCode().GetParameter(0)));
                }
            })
            .Catch(typeof(Exception), x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(legalSetterInterceptors[i].InterfaceSetter.OnException, x.Exception);
                }

                x.Rethrow();
            })
            .Finally(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(legalSetterInterceptors[i].InterfaceSetter.OnExit);
                }
            })
            .EndTry()
            .Return()
            .Replace();
        }
        private void InterceptMethods(Builder builder, IEnumerable <BuilderType> attributes)
        {
            if (!attributes.Any())
            {
                return;
            }

            var stopwatch = Stopwatch.StartNew();

            var iMethodInterceptor            = new __IMethodInterceptor(builder);
            var asyncTaskMethodBuilder        = new __AsyncTaskMethodBuilder(builder);
            var asyncTaskMethodBuilderGeneric = new __AsyncTaskMethodBuilder_1(builder);
            var syncRoot  = new __ISyncRoot(builder);
            var task      = new __Task(builder);
            var exception = new __Exception(builder);

            var methods = builder
                          .FindMethodsByAttributes(attributes)
                          .GroupBy(x => new MethodKey(x.Method, x.AsyncMethod))
                          .Select(x => new MethodBuilderInfo(x.Key, x.Select(y => new MethodBuilderInfoItem(y, iMethodInterceptor))))
                          .ToArray();

            foreach (var method in methods)
            {
                this.LogInfo($"Implementing interceptors in method {method.Key.Method}");

                var targetedMethod   = method.Key.AsyncMethod == null ? method.Key.Method : method.Key.AsyncMethod;
                var attributedMethod = method.Key.Method;

                method.AddThisReferenceToAsyncMethod();

                var typeInstance     = method.GetAsyncMethodTypeInstace();
                var interceptorField = new Field[method.Item.Length];

                if (method.RequiresSyncRootField)
                {
                    foreach (var ctors in targetedMethod.DeclaringType.GetRelevantConstructors())
                    {
                        ctors.NewCode().Assign(method.SyncRoot).NewObj(builder.GetType(typeof(object)).Import().ParameterlessContructor).Insert(InsertionPosition.Beginning);
                    }
                }

                targetedMethod
                .NewCode()
                .Context(x =>
                {
                    for (int i = 0; i < method.Item.Length; i++)
                    {
                        var item            = method.Item[i];
                        var name            = $"<{targetedMethod.Name}>_attrib{i}_{item.Attribute.Identification}";
                        interceptorField[i] = targetedMethod.DeclaringType.CreateField(targetedMethod.Modifiers.GetPrivate(), item.Interface.Type, name);

                        x.Load(interceptorField[i]).IsNull().Then(y =>
                        {
                            y.Assign(interceptorField[i]).NewObj(item.Attribute);
                            if (item.HasSyncRootInterface)
                            {
                                y.Load(interceptorField[i]).As(syncRoot.Type).Call(syncRoot.SyncRoot, method.SyncRoot);
                            }
                        });
                        item.Attribute.Remove();
                    }
                })
                .Try(x =>
                {
                    for (int i = 0; i < method.Item.Length; i++)
                    {
                        var item = method.Item[i];
                        x.Load(interceptorField[i]).As(item.Interface.Type).Call(item.Interface.OnEnter, attributedMethod.DeclaringType, typeInstance, attributedMethod, x.GetParametersArray());
                    }

                    x.OriginalBody();

                    // Special case for async methods
                    if (method.Key.AsyncMethod != null && method.Key.Method.ReturnType.Fullname == task.Type.Fullname)     // Task return
                    {
                        var exceptionVar = x.CreateVariable(exception.Type);

                        x.Assign(exceptionVar).Set(
                            x.NewCode().Call(method.Key.AsyncMethod.DeclaringType.GetField("<>t__builder"), asyncTaskMethodBuilder.GetTask)
                            .Call(task.GetException));

                        x.Load(exceptionVar).IsNotNull().Then(y =>
                        {
                            for (int i = 0; i < method.Item.Length; i++)
                            {
                                y.Load(interceptorField[i]).Callvirt(method.Item[i].Interface.OnException, exceptionVar);
                            }
                        });
                    }
                    else if (method.Key.AsyncMethod != null)     // Task<> return
                    {
                        var exceptionVar = x.CreateVariable(exception.Type);
                        var taskArgument = method.Key.Method.ReturnType.GetGenericArgument(0);

                        x.Assign(exceptionVar).Set(
                            x.NewCode().Call(method.Key.AsyncMethod.DeclaringType.GetField("<>t__builder"), asyncTaskMethodBuilderGeneric.GetTask.MakeGeneric(taskArgument))
                            .Call(task.GetException));

                        x.Load(exceptionVar).IsNotNull().Then(y =>
                        {
                            for (int i = 0; i < method.Item.Length; i++)
                            {
                                y.Load(interceptorField[i]).Callvirt(method.Item[i].Interface.OnException, exceptionVar);
                            }
                        });
                    }
                })
                .Catch(exception.Type, x =>
                {
                    if (method.Key.AsyncMethod == null)
                    {
                        for (int i = 0; i < method.Item.Length; i++)
                        {
                            x.Load(interceptorField[i]).As(method.Item[i].Interface.Type).Call(method.Item[i].Interface.OnException, x.Exception);
                        }
                    }

                    x.Rethrow();
                })
                .Finally(x =>
                {
                    for (int i = 0; i < method.Item.Length; i++)
                    {
                        x.Load(interceptorField[i]).As(method.Item[i].Interface.Type).Call(method.Item[i].Interface.OnExit);
                    }
                })
                .EndTry()
                .Return()
                .Replace();
            }
            ;

            stopwatch.Stop();
            this.LogInfo($"Implementing method interceptors took {stopwatch.Elapsed.TotalMilliseconds}ms");
        }
        private static void AddPropertySetterInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var syncRoot = new __ISyncRoot();
            var legalSetterInterceptors = member.InterceptorInfos.Where(x => x.InterfaceSetter != null).ToArray();

            member.Property.Setter
            .NewCode()
            .Context(x =>
            {
                if (member.HasInitializer)
                {
                    return;
                }

                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).IsNull().Then(y =>
                    {
                        y.Assign(field).NewObj(item.Attribute);

                        if (item.HasSyncRootInterface)
                        {
                            y.Load(field).As(syncRoot.ToBuilderType.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }

                        ImplementAssignMethodAttribute(builder, legalSetterInterceptors[i].AssignMethodAttributeInfos, field, y, false);
                    });
                    item.Attribute.Remove();
                }

                x.Load(propertyField).IsNull().Then(y =>
                                                    y.Assign(propertyField)
                                                    .NewObj(propertyInterceptionInfo.Ctor,
                                                            member.Property.Getter,
                                                            member.Property.Setter,
                                                            member.Property.Name,
                                                            member.Property.ReturnType,
                                                            Crumb.This,
                                                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                                                            propertySetter == null ? null : y.NewCode().NewObj(actionObjectCtor, propertySetter)));
            })
            .Try(x =>
            {
                if (member.Property.BackingField == null)
                {
                    var oldvalue = member.Property.Getter == null ? null : x.CreateVariable(member.Property.ReturnType);

                    if (oldvalue != null)
                    {
                        var getter = member.Property.Getter.Copy();
                        x.Call(getter.IsStatic ? null : Crumb.This, getter).StoreLocal(oldvalue);
                    }

                    for (int i = 0; i < legalSetterInterceptors.Length; i++)
                    {
                        var item  = legalSetterInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(item.InterfaceSetter.OnSet, propertyField, oldvalue, Crumb.GetParameter(0));

                        x.IsFalse().Then(y => y.OriginalBodyNewMethod());
                    }
                }
                else
                {
                    for (int i = 0; i < legalSetterInterceptors.Length; i++)
                    {
                        var item  = legalSetterInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(item.InterfaceSetter.OnSet, propertyField, member.Property.BackingField, Crumb.GetParameter(0));

                        x.IsFalse().Then(y => y.OriginalBody());
                    }
                }
            })
            .Catch(typeof(Exception), x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(legalSetterInterceptors[i].InterfaceSetter.OnException, x.Exception);
                }

                x.Rethrow();
            })
            .Finally(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(legalSetterInterceptors[i].InterfaceSetter.OnExit);
                }
            })
            .EndTry()
            .Return()
            .Replace();
        }
        private void InterceptSimpleMethods(Builder builder, IEnumerable <BuilderType> attributes)
        {
            if (!attributes.Any())
            {
                return;
            }

            using (new StopwatchLog(this, "method simple"))
            {
                var asyncTaskMethodBuilder        = new __AsyncTaskMethodBuilder();
                var asyncTaskMethodBuilderGeneric = new __AsyncTaskMethodBuilder_1();
                var syncRoot  = new __ISyncRoot();
                var task      = new __Task();
                var exception = new __Exception();

                var methods = builder
                              .FindMethodsByAttributes(attributes)
                              .Where(x => !x.Method.IsPropertyGetterSetter)
                              .GroupBy(x => new MethodKey(x.Method, x.AsyncMethod))
                              .Select(x => new MethodBuilderInfo <MethodBuilderInfoItem <__ISimpleMethodInterceptor> >(x.Key, x.Select(y => new MethodBuilderInfoItem <__ISimpleMethodInterceptor>(y, __ISimpleMethodInterceptor.Instance))))
                              .OrderBy(x => x.Key.Method.DeclaringType.Fullname)
                              .ToArray();

                foreach (var method in methods)
                {
                    if (method.Item == null || method.Item.Length == 0)
                    {
                        continue;
                    }

                    this.Log($"Implementing method interceptors: {method.Key.Method.DeclaringType.Name.PadRight(40, ' ')} {method.Key.Method.Name}({string.Join(", ", method.Key.Method.Parameters.Select(x => x.Name))})");

                    var targetedMethod   = method.Key.AsyncMethod ?? method.Key.Method;
                    var attributedMethod = method.Key.Method;

                    var typeInstance     = method.Key.Method.AsyncMethodHelper.Instance;
                    var interceptorField = new Field[method.Item.Length];

                    if (method.RequiresSyncRootField)
                    {
                        if (method.SyncRoot.IsStatic)
                        {
                            targetedMethod.AsyncOriginType.CreateStaticConstructor().NewCode()
                            .Assign(method.SyncRoot).NewObj(builder.GetType(typeof(object)).Import().ParameterlessContructor)
                            .Insert(InsertionPosition.Beginning);
                        }
                        else
                        {
                            foreach (var ctors in targetedMethod.AsyncOriginType.GetRelevantConstructors().Where(x => x.Name == ".ctor"))
                            {
                                ctors.NewCode().Assign(method.SyncRoot).NewObj(builder.GetType(typeof(object)).Import().ParameterlessContructor).Insert(InsertionPosition.Beginning);
                            }
                        }
                    }

                    var coder = targetedMethod
                                .NewCode()
                                .Context(x =>
                    {
                        for (int i = 0; i < method.Item.Length; i++)
                        {
                            var item            = method.Item[i];
                            var name            = $"<{targetedMethod.Name}>_attrib{i}_{item.Attribute.Identification}";
                            interceptorField[i] = targetedMethod.AsyncOriginType.CreateField(targetedMethod.Modifiers.GetPrivate(), item.Interface.ToBuilderType, name);
                            interceptorField[i].CustomAttributes.AddNonSerializedAttribute();

                            x.Load(interceptorField[i]).IsNull().Then(y =>
                            {
                                y.Assign(interceptorField[i]).NewObj(item.Attribute);
                                if (item.HasSyncRootInterface)
                                {
                                    y.Load(interceptorField[i]).As(__ISyncRoot.Type).Call(syncRoot.SyncRoot, method.SyncRoot);
                                }

                                ImplementAssignMethodAttribute(builder, method.Item[i].AssignMethodAttributeInfos, interceptorField[i], item.Attribute.Attribute.Type, x);
                            });

                            x.Load(interceptorField[i]).Call(item.Interface.OnEnter, attributedMethod.OriginType, typeInstance, attributedMethod, x.GetParametersArray());

                            item.Attribute.Remove();
                        }
                    });

                    var position = coder.GetFirstOrDefaultPosition(x => x.OpCode == OpCodes.Stelem_Ref);

                    if (position == null)
                    {
                        coder.Insert(InsertionPosition.Beginning);
                    }
                    else
                    {
                        coder.Insert(InsertionAction.After, position);
                    }
                }
                ;
            }
        }