Esempio n. 1
0
        public InstructionBlock Load(bool forDereferencing, bool onlyValue)
        {
            var instructions = new List <Instruction>
            {
                _processor.Create(OpCodes.Ldloc, _arrayVariableDefinition),
                _processor.Create(OpCodes.Ldc_I4, _index),
                _processor.Create(OpCodes.Ldelem_Ref)
            };

            var arrayTypeReference = (ArrayType)_arrayVariableDefinition.VariableType;
            var castFromType       = arrayTypeReference.ElementType;

            var parameterType = _parameter.ParameterType;
            var castToType    = parameterType;

            if (parameterType.IsByReference) // support for ref-Arguments
            {
                castToType = ((ByReferenceType)castToType).ElementType;
            }

            var castOrUnbox = InstructionBlockCreator.CastValueCurrentlyOnStack(
                castFromType,
                castToType);

            instructions.AddRange(castOrUnbox);

            if (!onlyValue && parameterType.IsByReference) // support for ref-Arguments
            {
                var variable = _creator.CreateVariable(castToType).Variable;
                instructions.Add(_processor.Create(OpCodes.Stloc, variable));
                instructions.Add(_processor.Create(OpCodes.Ldloca, variable));
            }

            return(new InstructionBlock($"Load {_index}", instructions));
        }
        public InstructionBlockChainCreator(MethodDefinition method, TypeReference aspectTypeDefinition, ModuleDefinition moduleDefinition, int aspectCounter)
        {
            _method = method;
            _aspectTypeDefinition = aspectTypeDefinition;
            _moduleDefinition = moduleDefinition;
            _aspectCounter = aspectCounter;

            _referenceFinder = new ReferenceFinder(_moduleDefinition);
            _creator = new InstructionBlockCreator(_method, _referenceFinder);
        }
Esempio n. 3
0
        public InstructionBlockChainCreator(
            MethodDefinition method,
            ModuleDefinition moduleDefinition)
        {
            _method           = method;
            _moduleDefinition = moduleDefinition;

            _referenceFinder = new ReferenceFinder(_moduleDefinition);
            _creator         = new InstructionBlockCreator(_method, _referenceFinder);
        }
        public InstructionBlockChainCreator(MethodDefinition method, TypeReference aspectTypeDefinition, ModuleDefinition moduleDefinition, int aspectCounter)
        {
            _method = method;
            _aspectTypeDefinition = aspectTypeDefinition;
            _moduleDefinition     = moduleDefinition;
            _aspectCounter        = aspectCounter;

            _referenceFinder = new ReferenceFinder(_moduleDefinition);
            _creator         = new InstructionBlockCreator(_method, _referenceFinder);
        }
        public NamedInstructionBlockChain LoadAspectInstance(CustomAttribute aspect, TypeReference type)
        {
            var caching = aspect.AttributeType.Resolve().CustomAttributes.FirstOrDefault(a => a.AttributeType.FullName == typeof(AspectCachingAttribute).FullName);

            Caching cachingLevel = Caching.None;

            if (caching != null)
            {
                cachingLevel = (Caching)caching.ConstructorArguments.First().Value;
            }

            var aspectTypeReference = _moduleDefinition.ImportReference(_aspectTypeDefinition);
            var aspectVariable      = _creator.CreateVariable(aspectTypeReference);

            if (cachingLevel == Caching.StaticByMethod)
            {
                var typeDef = type.Resolve();
                int i;
                string nameFactory(int index) => $"<{_method.Name}>k_aspectField_{index}";
                bool isNameTaken(int index) => typeDef.Fields.FirstOrDefault(f => f.Name == nameFactory(index)) != null;

                for (i = 1; isNameTaken(i); ++i)
                {
                }

                var field      = new FieldDefinition(nameFactory(i), Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.Private, aspectTypeReference);
                var staticCtor = _creator.EnsureStaticConstructor(typeDef);
                var processor  = staticCtor.Body.GetILProcessor();
                var first      = staticCtor.Body.Instructions.First();

                var creator = new InstructionBlockCreator(staticCtor, _referenceFinder);
                var aspectStaticVariable = creator.CreateVariable(aspectTypeReference);
                var newObjectAspectBlock = creator.NewObject(aspectStaticVariable, aspectTypeReference, _moduleDefinition, aspect, _aspectCounter);
                foreach (var inst in newObjectAspectBlock.Instructions)
                {
                    processor.InsertBefore(first, inst);
                }
                processor.InsertBefore(first, processor.Create(OpCodes.Ldloc, aspectStaticVariable));
                processor.InsertBefore(first, processor.Create(OpCodes.Stsfld, field));
                var loadAspectFieldBlockChain = new NamedInstructionBlockChain(aspectVariable, aspectTypeReference);
                loadAspectFieldBlockChain.Add(new InstructionBlock("LoadAspectField: ",
                                                                   Instruction.Create(OpCodes.Ldsfld, field),
                                                                   Instruction.Create(OpCodes.Stloc, aspectVariable)));
                type.Resolve().Fields.Add(field);
                return(loadAspectFieldBlockChain);
            }
            else
            {
                var newObjectAspectBlock = _creator.NewObject(aspectVariable,
                                                              aspectTypeReference, _moduleDefinition, aspect, _aspectCounter);
                var newObjectAspectBlockChain = new NamedInstructionBlockChain(aspectVariable, aspectTypeReference);
                newObjectAspectBlockChain.Add(newObjectAspectBlock);
                return(newObjectAspectBlockChain);
            }
        }
Esempio n. 6
0
        public InstructionBlockChain ReadReturnValue(IPersistable executionArgs, IPersistable returnValue)
        {
            if (InstructionBlockCreator.IsVoid(_method.ReturnType))
            {
                return(new InstructionBlockChain());
            }

            var getReturnValue = _referenceFinder.GetMethodReference(executionArgs.PersistedType, md => md.Name == "get_ReturnValue");
            var readValueBlock = _creator.CallInstanceMethod(getReturnValue, executionArgs, returnValue);

            var readValueBlockChain = new InstructionBlockChain();

            readValueBlockChain.Add(readValueBlock);
            return(readValueBlockChain);
        }
Esempio n. 7
0
        public void Weave()
        {
            if (_aspects.Count == 0)
            {
                return;
            }

            Setup();

            var arguments = _creator.CreateMethodArgumentsArray();

            AddToSetup(arguments);

            WeaveMethodExecutionArgs(arguments);

            SetupAspects();

            var hasReturnValue = !InstructionBlockCreator.IsVoid(_method.ReturnType);
            var returnValue    = hasReturnValue
                    ? _creator.CreateVariable(_method.ReturnType)
                    : null;

            WeaveOnEntry(returnValue);

            HandleBody(arguments, returnValue?.Variable, out var instructionCallStart, out var instructionCallEnd);

            var instructionAfterCall = WeaveOnExit(hasReturnValue, returnValue);

            HandleReturnValue(hasReturnValue, returnValue);

            if (_aspects.Any(x => (x.AspectMethods & AspectMethods.OnException) != 0))
            {
                WeaveOnException(_aspects, instructionCallStart, instructionCallEnd, instructionAfterCall, returnValue);
            }

            Optimize();

            Finish();

            WeaveCounter++;
        }
Esempio n. 8
0
        public void Weave(
            ModuleDefinition module,
            MethodDefinition method,
            IEnumerable <AspectInfo> aspectInfos)
        {
            var usableAspects = aspectInfos
                                .Select(x => new
            {
                Aspect        = x,
                AspectMethods = GetUsedAspectMethods(x.AspectAttribute.AttributeType)
            })
                                .Where(x => x.AspectMethods != AspectMethods.None)
                                .ToList();

            if (usableAspects.Count == 0)
            {
                return;
            }

            var hasMultipleAspects = usableAspects.Count > 1;

            var clonedMethod = CloneMethod(method);

            method.DeclaringType.Methods.Add(clonedMethod);

            // redirect source call
            ClearMethod(method);

            var ilProcessor = method.Body.GetILProcessor();
            var creator     = new InstructionBlockChainCreator(method, module);
            var arguments   = creator.CreateMethodArgumentsArray();

            arguments.Append(ilProcessor);

            var executionArgs = creator.CreateMethodExecutionArgsInstance(
                arguments,
                usableAspects.First().Aspect.AspectAttribute.AttributeType);

            executionArgs.Append(ilProcessor);

            // create aspect instance
            var aspectInstances = new Dictionary <AspectInfo, NamedInstructionBlockChain>();
            var tagVariables    = new Dictionary <AspectInfo, VariableDefinition>();

            foreach (var aspect in usableAspects)
            {
                var instance = creator.CreateAspectInstance(aspect.Aspect.AspectAttribute);
                instance.Append(ilProcessor);

                if (hasMultipleAspects)
                {
                    var tagVariable = creator.CreateObjectVariable();
                    method.Body.Variables.Add(tagVariable.Variable);
                    tagVariables.Add(aspect.Aspect, tagVariable.Variable);
                }

                aspectInstances.Add(aspect.Aspect, instance);
            }

            //OnEntries
            foreach (var aspect in usableAspects.Where(x => x.AspectMethods.HasFlag(AspectMethods.OnEntry)))
            {
                var aspectInstance = aspectInstances[aspect.Aspect];
                var call           = creator.CallAspectOnEntry(aspectInstance, executionArgs);
                call.Append(ilProcessor);

                if (hasMultipleAspects)
                {
                    var tagVariable = tagVariables[aspect.Aspect];
                    var save        = creator.SaveMethodExecutionArgsTagToVariable(executionArgs, tagVariable);
                    save.Append(ilProcessor);
                }
            }

            // call original method
            VariableDefinition thisVariable = null;

            if (!method.IsStatic)
            {
                var thisVariableBlock = creator.CreateThisVariable(method.DeclaringType);
                thisVariableBlock.Append(ilProcessor);
                thisVariable = thisVariableBlock.Variable;
            }

            var hasReturnValue = !InstructionBlockCreator.IsVoid(method.ReturnType);
            var returnValue    = hasReturnValue
                ? creator.CreateVariable(method.ReturnType)
                : null;
            var callSourceMethod = creator.CallMethodWithLocalParameters(
                method,
                clonedMethod,
                thisVariable,
                returnValue?.Variable);

            callSourceMethod.Append(ilProcessor);
            var instructionCallStart = callSourceMethod.First;
            var instructionCallEnd   = callSourceMethod.Last;

            var onExitAspects = usableAspects
                                .Where(x => x.AspectMethods.HasFlag(AspectMethods.OnExit))
                                .Reverse()
                                .ToList();

            Instruction instructionAfterCall = null;

            if (hasReturnValue && onExitAspects.Any())
            {
                var loadReturnValue = creator.LoadValueOnStack(returnValue);

                var setMethodExecutionArgsReturnValue = creator.SetMethodExecutionArgsReturnValue(
                    executionArgs,
                    loadReturnValue);
                setMethodExecutionArgsReturnValue.Append(ilProcessor);

                instructionAfterCall = setMethodExecutionArgsReturnValue.First;
            }

            // OnExit
            foreach (var aspect in onExitAspects)
            {
                if (hasMultipleAspects)
                {
                    var tagVariable = tagVariables[aspect.Aspect];
                    var load        = creator.LoadMethodExecutionArgsTagFromVariable(executionArgs,
                                                                                     tagVariable);
                    load.Append(ilProcessor);
                }

                var aspectInstance = aspectInstances[aspect.Aspect];
                var call           = creator.CallAspectOnExit(aspectInstance, executionArgs);
                call.Append(ilProcessor);
            }

            // return
            if (hasReturnValue)
            {
                var load = creator.LoadValueOnStack(returnValue);
                load.Append(ilProcessor);
            }

            var returnCall = creator.CreateReturn();

            returnCall.Append(ilProcessor);

            // add exception handling
            var onExceptionAspects = usableAspects
                                     .Where(x => x.AspectMethods.HasFlag(AspectMethods.OnException))
                                     .Reverse()
                                     .ToList();

            if (onExceptionAspects.Any())
            {
                var realInstructionAfterCall = instructionAfterCall ?? instructionCallEnd.Next;
                var tryLeaveInstruction      = Instruction.Create(OpCodes.Leave, realInstructionAfterCall);
                ilProcessor.InsertAfter(instructionCallEnd, tryLeaveInstruction);

                var exception = creator.SaveThrownException();
                var exceptionHandlerCurrent = exception.InsertAfter(tryLeaveInstruction, ilProcessor);

                var pushException = creator.LoadValueOnStack(exception);
                exceptionHandlerCurrent = pushException.InsertAfter(exceptionHandlerCurrent, ilProcessor);

                var setExceptionFromStack =
                    creator.SetMethodExecutionArgsExceptionFromStack(executionArgs);
                exceptionHandlerCurrent = setExceptionFromStack.InsertAfter(exceptionHandlerCurrent, ilProcessor);

                foreach (var onExceptionAspect in onExceptionAspects)
                {
                    if (hasMultipleAspects)
                    {
                        var tagVariable = tagVariables[onExceptionAspect.Aspect];
                        var load        = creator.LoadMethodExecutionArgsTagFromVariable(executionArgs,
                                                                                         tagVariable);
                        exceptionHandlerCurrent = load.InsertAfter(exceptionHandlerCurrent, ilProcessor);
                    }

                    var aspectInstance        = aspectInstances[onExceptionAspect.Aspect];
                    var callAspectOnException =
                        creator.CallAspectOnException(aspectInstance, executionArgs);
                    callAspectOnException.InsertAfter(exceptionHandlerCurrent, ilProcessor);
                    exceptionHandlerCurrent = callAspectOnException.Last;
                }

                var pushException2 = creator.LoadValueOnStack(exception);
                exceptionHandlerCurrent = pushException2.InsertAfter(exceptionHandlerCurrent, ilProcessor);

                ////var catchLeaveInstruction = Instruction.Create(OpCodes.Leave, realInstructionAfterCall);
                var catchLastInstruction = Instruction.Create(OpCodes.Throw);
                ilProcessor.InsertAfter(exceptionHandlerCurrent, catchLastInstruction);

                method.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch)
                {
                    CatchType    = creator.GetExceptionTypeReference(),
                    TryStart     = instructionCallStart,
                    TryEnd       = tryLeaveInstruction.Next,
                    HandlerStart = tryLeaveInstruction.Next,
                    HandlerEnd   = catchLastInstruction.Next
                });
            }

            // add DebuggerStepThrough attribute to avoid compiler searching for
            // non existing soure code for weaved il code
            var attributeCtor = creator.GetDebuggerStepThroughAttributeCtorReference();

            method.CustomAttributes.Add(new CustomAttribute(attributeCtor));

            method.Body.InitLocals = true;
            method.Body.Optimize();
            Catel.Fody.CecilExtensions.UpdateDebugInfo(method);

            clonedMethod.Body.InitLocals = true;
            clonedMethod.Body.Optimize();
            Catel.Fody.CecilExtensions.UpdateDebugInfo(clonedMethod);

            WeaveCounter++;
        }