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); }
public InstructionBlockChainCreator( MethodDefinition method, ModuleDefinition moduleDefinition) { _method = method; _moduleDefinition = moduleDefinition; _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); } }
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); }
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++; }
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++; }